Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add core functionality to support other Module._resolveFilename hooks #1614

Merged
merged 1 commit into from
Jan 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions src/cjs-resolve-filename-hook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import type Module = require('module');
import type { Service } from '.';

/** @internal */
export type ModuleConstructorWithInternals = typeof Module & {
_resolveFilename(
request: string,
parent?: Module,
isMain?: boolean,
options?: ModuleResolveFilenameOptions,
...rest: any[]
): string;
_preloadModules(requests?: string[]): void;
};

interface ModuleResolveFilenameOptions {
paths?: Array<string>;
}

/**
* @internal
*/
export function installCommonjsResolveHookIfNecessary(tsNodeService: Service) {
const Module = require('module') as ModuleConstructorWithInternals;
const originalResolveFilename = Module._resolveFilename;
const shouldInstallHook = tsNodeService.options.experimentalResolverFeatures;
if (shouldInstallHook) {
Module._resolveFilename = _resolveFilename;
}
function _resolveFilename(
this: any,
request: string,
parent?: Module,
isMain?: boolean,
options?: ModuleResolveFilenameOptions,
...rest: any[]
): string {
if (!tsNodeService.enabled())
return originalResolveFilename.call(
this,
request,
parent,
isMain,
options,
...rest
);

// This is a stub to support other pull requests that will be merged in the near future
// Right now, it does nothing.
return originalResolveFilename.call(
this,
request,
parent,
isMain,
options,
...rest
);
}
}
2 changes: 2 additions & 0 deletions src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ function filterRecognizedTsConfigTsNodeOptions(jsonObject: any): {
moduleTypes,
experimentalReplAwait,
swc,
experimentalResolverFeatures,
...unrecognized
} = jsonObject as TsConfigOptions;
const filteredTsConfigOptions = {
Expand All @@ -300,6 +301,7 @@ function filterRecognizedTsConfigTsNodeOptions(jsonObject: any): {
scopeDir,
moduleTypes,
swc,
experimentalResolverFeatures,
};
// Use the typechecker to make sure this implementation has the correct set of properties
const catchExtraneousProps: keyof TsConfigOptions =
Expand Down
19 changes: 18 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ import {
} from './module-type-classifier';
import { createResolverFunctions } from './resolver-functions';
import type { createEsmHooks as createEsmHooksFn } from './esm';
import {
installCommonjsResolveHookIfNecessary,
ModuleConstructorWithInternals,
} from './cjs-resolve-filename-hook';

export { TSCommon };
export {
Expand Down Expand Up @@ -379,6 +383,15 @@ export interface RegisterOptions extends CreateOptions {
* @default false
*/
preferTsExts?: boolean;

/**
* Enable experimental features that re-map imports and require calls to support:
* `baseUrl`, `paths`, `rootDirs`, `.js` to `.ts` file extension mappings,
* `outDir` to `rootDir` mappings for composite projects and monorepos.
*
* For details, see https://github.com/TypeStrong/ts-node/issues/1514
*/
experimentalResolverFeatures?: boolean;
}

/**
Expand Down Expand Up @@ -546,8 +559,12 @@ export function register(
originalJsHandler
);

installCommonjsResolveHookIfNecessary(service);

// Require specified modules before start-up.
(Module as any)._preloadModules(service.options.require);
(Module as ModuleConstructorWithInternals)._preloadModules(
service.options.require
);

return service;
}
Expand Down
1 change: 1 addition & 0 deletions website/docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ _Environment variables, where available, are in `ALL_CAPS`_
- `moduleType` Override the module type of certain files, ignoring the `package.json` `"type"` field. See [Module type overrides](./module-type-overrides.md) for details.<br/>*Default:* obeys `package.json` `"type"` and `tsconfig.json` `"module"` <br/>*Can only be specified via `tsconfig.json` or API.*
- `TS_NODE_HISTORY` Path to history file for REPL <br/>*Default:* `~/.ts_node_repl_history`<br/>
- `--noExperimentalReplAwait` Disable top-level await in REPL. Equivalent to node's [`--no-experimental-repl-await`](https://nodejs.org/api/cli.html#cli_no_experimental_repl_await)<br/>*Default:* Enabled if TypeScript version is 3.8 or higher and target is ES2018 or higher.<br/>*Environment:* `TS_NODE_EXPERIMENTAL_REPL_AWAIT` set `false` to disable
- `experimentalResolverFeatures` Enable experimental features that re-map imports and require calls to support: `baseUrl`, `paths`, `rootDirs`, `.js` to `.ts` file extension mappings, `outDir` to `rootDir` mappings for composite projects and monorepos. For details, see [#1514](https://github.com/TypeStrong/ts-node/issues/1514)<br/>*Default:* `false`<br/>*Can only be specified via `tsconfig.json` or API.*

## API

Expand Down