Description
Search Terms
ERR_UNKNOWN_FILE_EXTENSION, entrypoint, runmain
Expected Behavior
Running ts-node-esm
for binaries with no extension work without error in node 18.6 and greater.
Actual Behavior
Executing ts-node-esm
for binaries without extension (sequelize, uuid, tserver) throws the following error:
CustomError: ERR_UNKNOWN_FILE_EXTENSION /Users/enriquearias/Workspace/swile/notifications-hub/node_modules/uuid/dist/bin/uuid
at defaultGetFormat (/Users/enriquearias/Workspace/swile/notifications-hub/node_modules/ts-node/dist-raw/node-internal-modules-esm-get_format.js:93:15)
at defer (/Users/enriquearias/Workspace/swile/notifications-hub/node_modules/ts-node/src/esm.ts:307:38)
at entrypointFallback (/Users/enriquearias/Workspace/swile/notifications-hub/node_modules/ts-node/src/esm.ts:314:14)
at getFormat (/Users/enriquearias/Workspace/swile/notifications-hub/node_modules/ts-node/src/esm.ts:352:17)
at /Users/enriquearias/Workspace/swile/notifications-hub/node_modules/ts-node/src/esm.ts:268:10
at addShortCircuitFlag (/Users/enriquearias/Workspace/swile/notifications-hub/node_modules/ts-node/dist/esm.js:233:23)
at load (/Users/enriquearias/Workspace/swile/notifications-hub/node_modules/ts-node/dist/esm.js:122:16)
at load (/Users/enriquearias/Workspace/swile/notifications-hub/node_modules/ts-node/src/child/child-loader.ts:18:36)
at nextLoad (node:internal/modules/esm/loader:163:28)
at ESMLoader.load (node:internal/modules/esm/loader:605:26)
This error happens only in node v18.6 and higher.
Minimal reproduction
Here's a minimal reproduction repository to test it.
Specifications
- ts-node version: 10.9.1
- node version: >= 18.6.0
- TypeScript version: 4.9.4
- Operating system and version: Mac OSX | Ubuntu
Debug
After debugging the source code, I've noticed that the last version (10.9.1) includes this patch which causes the issue here.
Concretely, the file runmain-hack.js is importing the entrypoint file (uuid in the example above) which adds itself as parentURL
in the current import context.
When the entrypointFallback
function is executed, it is asked if the current file (specifier) is an entrypoint by calling the function isProbablyEntrypoint
.
One of the conditions to be a entrypoint in isProbablyEntrypoint
is that there's no parent in the context. Because runmain-hack adds the parent in the context, the rememberIsProbablyEntrypoint
object won't be updated.
This is important for files without extension, because when the function getFormat
executes the defaultGetFormat
which throws an error because there's no matching format, the catch body checks if the file is an entrypoint. But, because the rememberIsProbablyEntrypoint
was not set, instead of returning the commonjs format, the error is re-thrown.