linguist icon indicating copy to clipboard operation
linguist copied to clipboard

Consider supporting .ts files with node shebang

Open marcustyphoon opened this issue 8 months ago • 9 comments

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?)

marcustyphoon avatar Apr 20 '25 22:04 marcustyphoon

(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.

lildude avatar Apr 21 '25 05:04 lildude

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?

marcustyphoon avatar Apr 21 '25 05:04 marcustyphoon

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.

lildude avatar Apr 21 '25 11:04 lildude

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)

marcustyphoon avatar Apr 21 '25 18:04 marcustyphoon

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.

lildude avatar Apr 22 '25 06:04 lildude

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.

spenserblack avatar Apr 23 '25 14:04 spenserblack

The quick workaround is to add this to your .gitattributes file:

*.ts linguist-language=TypeScript

mondeja avatar Sep 19 '25 07:09 mondeja

  • See #4558 #5249 #5251

Nixinova avatar Sep 20 '25 06:09 Nixinova

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.

marcustyphoon avatar Sep 20 '25 06:09 marcustyphoon