Repository: deno
Issue: Allow executing TS scripts when NPM package is internal & private, and are treated as "binaries" (with shebang, etc.)
Labels: suggestion

## Related issues
- https://github.com/denoland/deno/issues/16790
- https://github.com/denoland/deno/issues/24093

## Problem description

1. I'm working in a monorepo environment, with many JS/TS packages, many of them private, and not published to any registry.
2. Some of these non-published private packages are automation scripts.
3. To improve cross-platform compatibility, I want to avoid relying on Bash or POSIX shell scripts. I have other reasons as well, such as maintainability, type checking, static analysis, etc.
4. These packages DO NOT export TypeScript modules to be consumed by JS/TS code elsewhere.
5. But they do contain TypeScript files with a shebang to ensure that they will run under the Deno runtime, something like
   ```bash
   #!/usr/bin/env -S deno run --node-modules-dir --allow-env --allow-read --allow-sys --allow-run
   ```
6. I export the corresponding binary in the `package.json` file of said package:
   ```json
   {
	"name": "@kindspells/internal-tools",
	"private": true,
	"type": "module",
	"bin": { "biome-check-staged": "./src/biome-check-staged.ts" },
	"dependencies": { "zx": "^8.1.4" }
   }
   ```
7. I install this package as a **dev** dependency in other packages of this same monorepo, so I can use the automation scripts from there, without having to deal with relative paths and other nightmarish command line tricks.
8. When I run the exported binary with PNPM... Deno refuses to run and makes me feel sad:
   ```
   error: TypeScript files are not supported in npm packages: file:///Users/me/mycode/node_modules/@kindspells/internal-tools/src/biome-check-staged.ts
   ```
9. As a side note, it doesn't matter if I try to trick the system by calling a `.js` file that in turn calls the `.ts` file.

## Proposed solution

I am aware that there are other open issues that got closed because it is a very bad idea to allow people to pack TypeScript in NPM packages instead of distributing JS directly. I want to be clear that this is not what I'm asking for. I'll go into the details right now.

My first point would be to notice the fact that we are talking about a "binary", a script that it is intended to be executed "as is" (it even has its own shebang to tell the OS how to be executed). We are not talking about code distribution.

Now, my proposal is that, when **all** of the following conditions are met, Deno should allow the execution of TypeScript scripts even when they are exposed through NPM packages:
- The package is in the same monorepo, configured as a "workspace"
- The package is _private_ (`"private": true` in `package.json`)
- The TypeScript code is not exported as a module or anything like that, but as a binary with its own shebang.
  - Exported through `package.json`'s `"bin"` field.
  - The file is marked as executable
  - The file has its own shebang

We know that, if we decided to pack POSIX shell scripts in NPM packages, they would be executed without hesitation, even though they are not pure JavaScript. The same would happen if we decided to pack Python scripts. For consistency (and a better life for everyone) the same should apply to virtually any scripting language, **including TypeScript**.

I don't think that being in the same monorepo and being private are important requirements, but I introduced them here to minimise potential concerns, and because in any case... this is the most common use case.

## Alternative Solution

I've been checking the source code to see where this error is raised, and although I still didn't invest enought time, I can see how much of the information I mentioned in the previous proposal could not be available at the time of deciding whether to accept or not that script execution.

A simpler alternative could be to pass a specific flag to `deno run` (in the shebang) that disables the check raising the error... but adding an extra check that verifies that there is a shebang in the executed flag, and raise an error if it's not there.

This second check once we are at runtime would serve to ensure that people do not abuse the config flag for "normal code", and it is used only in "binaries".