Drop anything, and recognising it is not the same as reading it
"Choose your source type" is a question the app should be able to answer itself. So we stopped asking it. Drop whatever you have, in any mix, and SnoutData works out what each thing is, including when the answer is "this one has no records in it".
The extension is a hint, not the answer
File extensions lie constantly. A .txt that is really tab-separated, a .csv that somebody saved as JSON, a log file with no extension at all. So the extension is demoted to a tiebreak and the content decides: magic bytes first, then a byte-order mark, then is this even text, then what structure does it actually have.
The practical effect is that the mislabelled file, the one that used to make an importer fail with a parse error on line 1, just gets read correctly.
Recognising something and declining it is a real answer
This is the part we care most about getting right. Most binaries hold no records. A font, an executable, a compressed archive of things we cannot see into: there is no honest table in there, and a tool that pretends otherwise produces garbage rows that look like data.
So declining is a first-class outcome, not a failure. The file is named, the reason is given, and the rest of the flow carries on with the files that do have records. You end up knowing exactly what was and was not read, which is a much better position than a suspiciously round row count.
The source step is a bin
You are not adding one file. You are filling a bin: drop anything, any kind, any number, in as many goes as you like, remove things you changed your mind about. Nothing is read until you press the button.
And they do not have to match. A folder of CSVs and JSON files and a couple of PDFs can go into one flow and land in one destination, with the columns unioned across them and a _source on every record naming which input it came from. We originally required every file in a flow to be the same kind, and then reversed that, because "here is the folder" is what people actually have.
What we found when we looked
Worth admitting, since it is the kind of bug that survives a green test suite: when we sat down and actually dragged a file onto the window, the drop did not work at all. Electron 32 removed the File.path property that both of our drop handlers read, and the app-window drop was additionally filtering by an extension allow list, which is exactly the thing this feature exists to stop doing.
Both are fixed and both are now pinned by end-to-end tests that perform a real drop, because a stubbed file picker is not a drop and will happily pass forever while the actual feature is broken.