Consider supporting .ts files with node shebang
Describe the enhancement
As of node 23.6, node can run typescript files directly, without ts-node, tsx, etc. Thus, a .ts file with #!/usr/bin/env node can actually be run now, and it would make sense for linguist to detect this as a typescript file. #!/usr/bin/env node --experimental-transform-types works in node ≥22.6, in fact.
(I assume this would be as simple as adding node, and I guess nodejs, to the list of typescript interpreters in languages.yml? I'm not familiar enough with this repository to test that. Edit: Nope, seems like probably not?)
(I assume this would be as simple as adding node, and I guess nodejs, to the list of typescript interpreters in languages.yml?
Yup, however this is already the case for JavaScript so Linguist will need to fall back to other strategies to differentiate between JavaScript and TypeScript which it may struggle with if there isn't an extension given how similar the languages are.
Yeah, my hope was that there was a way to specify preferring file extension over shebang when shebang yields the same set of results. I can't imagine that there are going to be extensionless files that are actually typescript (node wouldn't process them as such) so I don't think we want file-content-based heuristics in this case at all. Looks like there's probably nowhere near that level of granularity though?
I can't imagine that there are going to be extensionless files that are actually typescript (node wouldn't process them as such)
🤔 If there are never going to be extensionless files, there shouldn't be any need to add these to the list of intepreters.
Two points:
a) What I mean is that—at least any time soon—there would be extensionless javascript files, but no extensionless typescript files! When I tried adding those interpreters and running bundle exec rake test, it looked like linguist might have started misclassifying some of the extensionless javascript samples as typescript, which would be bad (it wasn't clear to me how to figure out what tests were actually failing, so I could be wrong about this).
b) The bug I'm observing—I should have been clearer about this in the initial report, sorry—is that a .ts-extensioned file with a node shebang is detected as javascript; the shebang is overriding the extension and file contents!
(edit: link may no longer work, as I've since added a .gitattributes override)
What I mean is that—at least any time soon—there would be extensionless javascript files, but no extensionless typescript files! When I tried adding those interpreters and running bundle exec rake test, it looked like linguist might have started misclassifying some of the extensionless javascript samples as typescript, which would be bad (it wasn't clear to me how to figure out what tests were actually failing, so I could be wrong about this).
This is what I thought would happen, and as mentioned before it's going to be tough to prevent given how similar the two languages are.
The bug I'm observing—I should have been clearer about this in the initial report, sorry—is that a .ts-extensioned file with a node shebang is detected as javascript; the shebang is overriding the extension and file contents!
Now that makes more sense. Yes, the shebang takes priority as you have effectively explicitly told Linguist what language to use.
The only solution I can think of right now is to leave things as-is and users will need to use overrides when things aren't right.
Depending on your usage, another workaround is to just use a thin JS wrapper around your actual implementation, which is what I typically do.
// src/cli.ts
export function run(): void {
console.log("Hello, World!");
}
#!/usr/bin/env node
// bin.mjs
import { run } from "./dist/cli.js";
run();
Besides keeping language stats accurate, this also helps make your code a bit more testable. Change run() to take a value with a console-like type and now you can test your executable's behavior with a mock console.
The quick workaround is to add this to your .gitattributes file:
*.ts linguist-language=TypeScript
- See #4558 #5249 #5251
Yep, those are definitely duplicates of this issue—of course besides the fact that at the time node couldn't execute .ts files (valid reason to close!) but now it can.