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

fix: Add globalPreload to ts-node/esm for node 20 #2009

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
loader: Set default 'pretty' option properly
Set the default `options.pretty` value based on stderr rather than
stdout, as this is where errors are printed.

The loader thread does not get a process.stderr.isTTY set, because its
"stderr" is actually a pipe. If `options.pretty` is not set explicitly,
the GlobalPreload's `context.port` is used to send a message from the
main thread indicating the state of stderr.isTTY.

Adds `Service.setPrettyErrors` method to enable setting this value when
needed.
  • Loading branch information
isaacs committed Sep 7, 2023
commit 04d9419fedacd02f499f901ef3b1b32575776f33
24 changes: 22 additions & 2 deletions src/esm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { extname, resolve as pathResolve } from 'path';
import * as assert from 'assert';
import { normalizeSlashes, versionGteLt } from './util';
import { createRequire } from 'module';
import type { MessagePort } from 'worker_threads';

// Note: On Windows, URLs look like this: file:///D:/dev/@TypeStrong/ts-node-examples/foo.ts

Expand Down Expand Up @@ -75,7 +76,7 @@ export namespace NodeLoaderHooksAPI2 {
export interface NodeImportAssertions {
type?: 'json';
}
export type GlobalPreloadHook = () => string;
export type GlobalPreloadHook = (context?: { port: MessagePort }) => string;
}

export type NodeLoaderHooksFormat = 'builtin' | 'commonjs' | 'dynamic' | 'json' | 'module' | 'wasm';
Expand Down Expand Up @@ -123,10 +124,29 @@ export function createEsmHooks(tsNodeService: Service) {
globalPreload: useLoaderThread ? globalPreload : undefined,
});

function globalPreload() {
function globalPreload({ port }: { port?: MessagePort } = {}) {
// The loader thread doesn't get process.stderr.isTTY properly,
// so this signal lets us infer it based on the state of the main
// thread, but only relevant if options.pretty is unset.
let stderrTTYSignal: string;
if (tsNodeService.options.pretty === undefined) {
port?.on('message', (data) => {
if (data?.stderrIsTTY) {
tsNodeService.setPrettyErrors(true);
}
});
stderrTTYSignal = `
port.postMessage({
stderrIsTTY: !!process.stderr.isTTY
});
`;
} else {
stderrTTYSignal = '';
}
return `
const { createRequire } = getBuiltin('module');
const require = createRequire(${JSON.stringify(__filename)});
${stderrTTYSignal}
require('./index').register();
`;
}
Expand Down
15 changes: 11 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ export interface Service {
ignored(fileName: string): boolean;
compile(code: string, fileName: string, lineOffset?: number): string;
getTypeInfo(code: string, fileName: string, position: number): TypeInfo;
setPrettyErrors(pretty: boolean): void;
/** @internal */
configFilePath: string | undefined;
/** @internal */
Expand Down Expand Up @@ -719,11 +720,16 @@ export function createFromPreloadedConfig(foundConfigResult: ReturnType<typeof f
});
}

const shouldHavePrettyErrors = options.pretty === undefined ? process.stdout.isTTY : options.pretty;
let shouldHavePrettyErrors!: boolean;
let formatDiagnostics: (diagnostics: readonly _ts.Diagnostic[], host: _ts.FormatDiagnosticsHost) => string;

const formatDiagnostics = shouldHavePrettyErrors
? ts.formatDiagnosticsWithColorAndContext || ts.formatDiagnostics
: ts.formatDiagnostics;
function setPrettyErrors(pretty: boolean) {
shouldHavePrettyErrors = pretty;
formatDiagnostics = shouldHavePrettyErrors
? ts.formatDiagnosticsWithColorAndContext || ts.formatDiagnostics
: ts.formatDiagnostics;
}
setPrettyErrors(options.pretty !== undefined ? options.pretty : !!process.stderr.isTTY);

function createTSError(diagnostics: ReadonlyArray<_ts.Diagnostic>) {
const diagnosticText = formatDiagnostics(diagnostics, diagnosticHost);
Expand Down Expand Up @@ -1282,6 +1288,7 @@ export function createFromPreloadedConfig(foundConfigResult: ReturnType<typeof f
getNodeEsmGetFormat,
getNodeCjsLoader,
extensions,
setPrettyErrors,
};
}

Expand Down