UNPKG

46 kBJavaScriptView Raw
1"use strict";
2var _a, _b;
3Object.defineProperty(exports, "__esModule", { value: true });
4exports.createEsmHooks = exports.createFromPreloadedConfig = exports.create = exports.register = exports.TSError = exports.DEFAULTS = exports.VERSION = exports.debug = exports.INSPECT_CUSTOM = exports.env = exports.REGISTER_INSTANCE = exports.createRepl = void 0;
5const path_1 = require("path");
6const module_1 = require("module");
7const util = require("util");
8const url_1 = require("url");
9const make_error_1 = require("make-error");
10const util_1 = require("./util");
11const configuration_1 = require("./configuration");
12const module_type_classifier_1 = require("./module-type-classifier");
13const resolver_functions_1 = require("./resolver-functions");
14const cjs_resolve_hooks_1 = require("./cjs-resolve-hooks");
15const node_module_type_classifier_1 = require("./node-module-type-classifier");
16const file_extensions_1 = require("./file-extensions");
17const ts_transpile_module_1 = require("./ts-transpile-module");
18var repl_1 = require("./repl");
19Object.defineProperty(exports, "createRepl", { enumerable: true, get: function () { return repl_1.createRepl; } });
20/**
21 * Does this version of node obey the package.json "type" field
22 * and throw ERR_REQUIRE_ESM when attempting to require() an ESM modules.
23 */
24const engineSupportsPackageTypeField = parseInt(process.versions.node.split('.')[0], 10) >= 12;
25/**
26 * Assert that script can be loaded as CommonJS when we attempt to require it.
27 * If it should be loaded as ESM, throw ERR_REQUIRE_ESM like node does.
28 *
29 * Loaded conditionally so we don't need to support older node versions
30 */
31let assertScriptCanLoadAsCJS = engineSupportsPackageTypeField
32 ? require('../dist-raw/node-internal-modules-cjs-loader').assertScriptCanLoadAsCJSImpl
33 : () => {
34 /* noop */
35 };
36/**
37 * Registered `ts-node` instance information.
38 */
39exports.REGISTER_INSTANCE = Symbol.for('ts-node.register.instance');
40/** @internal */
41exports.env = process.env;
42/**
43 * @internal
44 */
45exports.INSPECT_CUSTOM = util.inspect.custom || 'inspect';
46/**
47 * Debugging `ts-node`.
48 */
49const shouldDebug = (0, util_1.yn)(exports.env.TS_NODE_DEBUG);
50/** @internal */
51exports.debug = shouldDebug
52 ? (...args) => console.log(`[ts-node ${new Date().toISOString()}]`, ...args)
53 : () => undefined;
54const debugFn = shouldDebug
55 ? (key, fn) => {
56 let i = 0;
57 return (x) => {
58 (0, exports.debug)(key, x, ++i);
59 return fn(x);
60 };
61 }
62 : (_, fn) => fn;
63/**
64 * Export the current version.
65 */
66exports.VERSION = require('../package.json').version;
67/**
68 * Default register options, including values specified via environment
69 * variables.
70 * @internal
71 */
72exports.DEFAULTS = {
73 cwd: (_a = exports.env.TS_NODE_CWD) !== null && _a !== void 0 ? _a : exports.env.TS_NODE_DIR,
74 emit: (0, util_1.yn)(exports.env.TS_NODE_EMIT),
75 scope: (0, util_1.yn)(exports.env.TS_NODE_SCOPE),
76 scopeDir: exports.env.TS_NODE_SCOPE_DIR,
77 files: (0, util_1.yn)(exports.env.TS_NODE_FILES),
78 pretty: (0, util_1.yn)(exports.env.TS_NODE_PRETTY),
79 compiler: exports.env.TS_NODE_COMPILER,
80 compilerOptions: (0, util_1.parse)(exports.env.TS_NODE_COMPILER_OPTIONS),
81 ignore: (0, util_1.split)(exports.env.TS_NODE_IGNORE),
82 project: exports.env.TS_NODE_PROJECT,
83 skipProject: (0, util_1.yn)(exports.env.TS_NODE_SKIP_PROJECT),
84 skipIgnore: (0, util_1.yn)(exports.env.TS_NODE_SKIP_IGNORE),
85 preferTsExts: (0, util_1.yn)(exports.env.TS_NODE_PREFER_TS_EXTS),
86 ignoreDiagnostics: (0, util_1.split)(exports.env.TS_NODE_IGNORE_DIAGNOSTICS),
87 transpileOnly: (0, util_1.yn)(exports.env.TS_NODE_TRANSPILE_ONLY),
88 typeCheck: (0, util_1.yn)(exports.env.TS_NODE_TYPE_CHECK),
89 compilerHost: (0, util_1.yn)(exports.env.TS_NODE_COMPILER_HOST),
90 logError: (0, util_1.yn)(exports.env.TS_NODE_LOG_ERROR),
91 experimentalReplAwait: (_b = (0, util_1.yn)(exports.env.TS_NODE_EXPERIMENTAL_REPL_AWAIT)) !== null && _b !== void 0 ? _b : undefined,
92 tsTrace: console.log.bind(console),
93};
94/**
95 * TypeScript diagnostics error.
96 */
97class TSError extends make_error_1.BaseError {
98 constructor(diagnosticText, diagnosticCodes, diagnostics = []) {
99 super(`⨯ Unable to compile TypeScript:\n${diagnosticText}`);
100 this.diagnosticCodes = diagnosticCodes;
101 this.name = 'TSError';
102 Object.defineProperty(this, 'diagnosticText', {
103 configurable: true,
104 writable: true,
105 value: diagnosticText,
106 });
107 Object.defineProperty(this, 'diagnostics', {
108 configurable: true,
109 writable: true,
110 value: diagnostics,
111 });
112 }
113 /**
114 * @internal
115 */
116 [exports.INSPECT_CUSTOM]() {
117 return this.diagnosticText;
118 }
119}
120exports.TSError = TSError;
121const TS_NODE_SERVICE_BRAND = Symbol('TS_NODE_SERVICE_BRAND');
122function register(serviceOrOpts) {
123 // Is this a Service or a RegisterOptions?
124 let service = serviceOrOpts;
125 if (!(serviceOrOpts === null || serviceOrOpts === void 0 ? void 0 : serviceOrOpts[TS_NODE_SERVICE_BRAND])) {
126 // Not a service; is options
127 service = create((serviceOrOpts !== null && serviceOrOpts !== void 0 ? serviceOrOpts : {}));
128 }
129 const originalJsHandler = require.extensions['.js'];
130 // Expose registered instance globally.
131 process[exports.REGISTER_INSTANCE] = service;
132 // Register the extensions.
133 registerExtensions(service.options.preferTsExts, service.extensions.compiled, service, originalJsHandler);
134 (0, cjs_resolve_hooks_1.installCommonjsResolveHooksIfNecessary)(service);
135 // Require specified modules before start-up.
136 module_1.Module._preloadModules(service.options.require);
137 return service;
138}
139exports.register = register;
140/**
141 * Create TypeScript compiler instance.
142 *
143 * @category Basic
144 */
145function create(rawOptions = {}) {
146 const foundConfigResult = (0, configuration_1.findAndReadConfig)(rawOptions);
147 return createFromPreloadedConfig(foundConfigResult);
148}
149exports.create = create;
150/** @internal */
151function createFromPreloadedConfig(foundConfigResult) {
152 var _a, _b, _c, _d;
153 const { configFilePath, cwd, options, config, compiler, projectLocalResolveDir, optionBasePaths, } = foundConfigResult;
154 const projectLocalResolveHelper = (0, util_1.createProjectLocalResolveHelper)(projectLocalResolveDir);
155 const ts = (0, configuration_1.loadCompiler)(compiler);
156 // Experimental REPL await is not compatible targets lower than ES2018
157 const targetSupportsTla = config.options.target >= ts.ScriptTarget.ES2018;
158 if (options.experimentalReplAwait === true && !targetSupportsTla) {
159 throw new Error('Experimental REPL await is not compatible with targets lower than ES2018');
160 }
161 // Top-level await was added in TS 3.8
162 const tsVersionSupportsTla = (0, util_1.versionGteLt)(ts.version, '3.8.0');
163 if (options.experimentalReplAwait === true && !tsVersionSupportsTla) {
164 throw new Error('Experimental REPL await is not compatible with TypeScript versions older than 3.8');
165 }
166 const shouldReplAwait = options.experimentalReplAwait !== false &&
167 tsVersionSupportsTla &&
168 targetSupportsTla;
169 // swc implies two other options
170 // typeCheck option was implemented specifically to allow overriding tsconfig transpileOnly from the command-line
171 // So we should allow using typeCheck to override swc
172 if (options.swc && !options.typeCheck) {
173 if (options.transpileOnly === false) {
174 throw new Error("Cannot enable 'swc' option with 'transpileOnly: false'. 'swc' implies 'transpileOnly'.");
175 }
176 if (options.transpiler) {
177 throw new Error("Cannot specify both 'swc' and 'transpiler' options. 'swc' uses the built-in swc transpiler.");
178 }
179 }
180 const readFile = options.readFile || ts.sys.readFile;
181 const fileExists = options.fileExists || ts.sys.fileExists;
182 // typeCheck can override transpileOnly, useful for CLI flag to override config file
183 const transpileOnly = (options.transpileOnly === true || options.swc === true) &&
184 options.typeCheck !== true;
185 let transpiler = undefined;
186 let transpilerBasePath = undefined;
187 if (options.transpiler) {
188 transpiler = options.transpiler;
189 transpilerBasePath = optionBasePaths.transpiler;
190 }
191 else if (options.swc) {
192 transpiler = require.resolve('./transpilers/swc.js');
193 transpilerBasePath = optionBasePaths.swc;
194 }
195 const transformers = options.transformers || undefined;
196 const diagnosticFilters = [
197 {
198 appliesToAllFiles: true,
199 filenamesAbsolute: [],
200 diagnosticsIgnored: [
201 6059,
202 18002,
203 18003,
204 ...(options.experimentalTsImportSpecifiers
205 ? [
206 2691, // "An import path cannot end with a '.ts' extension. Consider importing '<specifier without ext>' instead."
207 ]
208 : []),
209 ...(options.ignoreDiagnostics || []),
210 ].map(Number),
211 },
212 ];
213 const configDiagnosticList = filterDiagnostics(config.errors, diagnosticFilters);
214 const outputCache = new Map();
215 const configFileDirname = configFilePath ? (0, path_1.dirname)(configFilePath) : null;
216 const scopeDir = (_c = (_b = (_a = options.scopeDir) !== null && _a !== void 0 ? _a : config.options.rootDir) !== null && _b !== void 0 ? _b : configFileDirname) !== null && _c !== void 0 ? _c : cwd;
217 const ignoreBaseDir = configFileDirname !== null && configFileDirname !== void 0 ? configFileDirname : cwd;
218 const isScoped = options.scope
219 ? (fileName) => (0, path_1.relative)(scopeDir, fileName).charAt(0) !== '.'
220 : () => true;
221 const shouldIgnore = createIgnore(ignoreBaseDir, options.skipIgnore
222 ? []
223 : (options.ignore || ['(?:^|/)node_modules/']).map((str) => new RegExp(str)));
224 const diagnosticHost = {
225 getNewLine: () => ts.sys.newLine,
226 getCurrentDirectory: () => cwd,
227 // TODO switch to getCanonicalFileName we already create later in scope
228 getCanonicalFileName: ts.sys.useCaseSensitiveFileNames
229 ? (x) => x
230 : (x) => x.toLowerCase(),
231 };
232 if (options.transpileOnly && typeof transformers === 'function') {
233 throw new TypeError('Transformers function is unavailable in "--transpile-only"');
234 }
235 let createTranspiler = initializeTranspilerFactory();
236 function initializeTranspilerFactory() {
237 var _a;
238 if (transpiler) {
239 if (!transpileOnly)
240 throw new Error('Custom transpiler can only be used when transpileOnly is enabled.');
241 const transpilerName = typeof transpiler === 'string' ? transpiler : transpiler[0];
242 const transpilerOptions = typeof transpiler === 'string' ? {} : (_a = transpiler[1]) !== null && _a !== void 0 ? _a : {};
243 const transpilerConfigLocalResolveHelper = transpilerBasePath
244 ? (0, util_1.createProjectLocalResolveHelper)(transpilerBasePath)
245 : projectLocalResolveHelper;
246 const transpilerPath = transpilerConfigLocalResolveHelper(transpilerName, true);
247 const transpilerFactory = require(transpilerPath)
248 .create;
249 return createTranspiler;
250 function createTranspiler(compilerOptions, nodeModuleEmitKind) {
251 return transpilerFactory === null || transpilerFactory === void 0 ? void 0 : transpilerFactory({
252 service: {
253 options,
254 config: {
255 ...config,
256 options: compilerOptions,
257 },
258 projectLocalResolveHelper,
259 },
260 transpilerConfigLocalResolveHelper,
261 nodeModuleEmitKind,
262 ...transpilerOptions,
263 });
264 }
265 }
266 }
267 /**
268 * True if require() hooks should interop with experimental ESM loader.
269 * Enabled explicitly via a flag since it is a breaking change.
270 */
271 let experimentalEsmLoader = false;
272 function enableExperimentalEsmLoaderInterop() {
273 experimentalEsmLoader = true;
274 }
275 // Install source map support and read from memory cache.
276 installSourceMapSupport();
277 function installSourceMapSupport() {
278 const sourceMapSupport = require('@cspotcode/source-map-support');
279 sourceMapSupport.install({
280 environment: 'node',
281 retrieveFile(pathOrUrl) {
282 var _a;
283 let path = pathOrUrl;
284 // If it's a file URL, convert to local path
285 // Note: fileURLToPath does not exist on early node v10
286 // I could not find a way to handle non-URLs except to swallow an error
287 if (experimentalEsmLoader && path.startsWith('file://')) {
288 try {
289 path = (0, url_1.fileURLToPath)(path);
290 }
291 catch (e) {
292 /* swallow error */
293 }
294 }
295 path = (0, util_1.normalizeSlashes)(path);
296 return ((_a = outputCache.get(path)) === null || _a === void 0 ? void 0 : _a.content) || '';
297 },
298 redirectConflictingLibrary: true,
299 onConflictingLibraryRedirect(request, parent, isMain, options, redirectedRequest) {
300 (0, exports.debug)(`Redirected an attempt to require source-map-support to instead receive @cspotcode/source-map-support. "${parent.filename}" attempted to require or resolve "${request}" and was redirected to "${redirectedRequest}".`);
301 },
302 });
303 }
304 const shouldHavePrettyErrors = options.pretty === undefined ? process.stdout.isTTY : options.pretty;
305 const formatDiagnostics = shouldHavePrettyErrors
306 ? ts.formatDiagnosticsWithColorAndContext || ts.formatDiagnostics
307 : ts.formatDiagnostics;
308 function createTSError(diagnostics) {
309 const diagnosticText = formatDiagnostics(diagnostics, diagnosticHost);
310 const diagnosticCodes = diagnostics.map((x) => x.code);
311 return new TSError(diagnosticText, diagnosticCodes, diagnostics);
312 }
313 function reportTSError(configDiagnosticList) {
314 const error = createTSError(configDiagnosticList);
315 if (options.logError) {
316 // Print error in red color and continue execution.
317 console.error('\x1b[31m%s\x1b[0m', error);
318 }
319 else {
320 // Throw error and exit the script.
321 throw error;
322 }
323 }
324 // Render the configuration errors.
325 if (configDiagnosticList.length)
326 reportTSError(configDiagnosticList);
327 const jsxEmitPreserve = config.options.jsx === ts.JsxEmit.Preserve;
328 /**
329 * Get the extension for a transpiled file.
330 * [MUST_UPDATE_FOR_NEW_FILE_EXTENSIONS]
331 */
332 function getEmitExtension(path) {
333 const lastDotIndex = path.lastIndexOf('.');
334 if (lastDotIndex >= 0) {
335 const ext = path.slice(lastDotIndex);
336 switch (ext) {
337 case '.js':
338 case '.ts':
339 return '.js';
340 case '.jsx':
341 case '.tsx':
342 return jsxEmitPreserve ? '.jsx' : '.js';
343 case '.mjs':
344 case '.mts':
345 return '.mjs';
346 case '.cjs':
347 case '.cts':
348 return '.cjs';
349 }
350 }
351 return '.js';
352 }
353 /**
354 * Get output from TS compiler w/typechecking. `undefined` in `transpileOnly`
355 * mode.
356 */
357 let getOutput;
358 let getTypeInfo;
359 const getCanonicalFileName = ts.createGetCanonicalFileName(ts.sys.useCaseSensitiveFileNames);
360 const moduleTypeClassifier = (0, module_type_classifier_1.createModuleTypeClassifier)({
361 basePath: (_d = options.optionBasePaths) === null || _d === void 0 ? void 0 : _d.moduleTypes,
362 patterns: options.moduleTypes,
363 });
364 const extensions = (0, file_extensions_1.getExtensions)(config, options, ts.version);
365 // Use full language services when the fast option is disabled.
366 if (!transpileOnly) {
367 const fileContents = new Map();
368 const rootFileNames = new Set(config.fileNames);
369 const cachedReadFile = (0, util_1.cachedLookup)(debugFn('readFile', readFile));
370 // Use language services by default
371 if (!options.compilerHost) {
372 let projectVersion = 1;
373 const fileVersions = new Map(Array.from(rootFileNames).map((fileName) => [fileName, 0]));
374 const getCustomTransformers = () => {
375 if (typeof transformers === 'function') {
376 const program = service.getProgram();
377 return program ? transformers(program) : undefined;
378 }
379 return transformers;
380 };
381 // Create the compiler host for type checking.
382 const serviceHost = {
383 getProjectVersion: () => String(projectVersion),
384 getScriptFileNames: () => Array.from(rootFileNames),
385 getScriptVersion: (fileName) => {
386 const version = fileVersions.get(fileName);
387 return version ? version.toString() : '';
388 },
389 getScriptSnapshot(fileName) {
390 // TODO ordering of this with getScriptVersion? Should they sync up?
391 let contents = fileContents.get(fileName);
392 // Read contents into TypeScript memory cache.
393 if (contents === undefined) {
394 contents = cachedReadFile(fileName);
395 if (contents === undefined)
396 return;
397 fileVersions.set(fileName, 1);
398 fileContents.set(fileName, contents);
399 projectVersion++;
400 }
401 return ts.ScriptSnapshot.fromString(contents);
402 },
403 readFile: cachedReadFile,
404 readDirectory: ts.sys.readDirectory,
405 getDirectories: (0, util_1.cachedLookup)(debugFn('getDirectories', ts.sys.getDirectories)),
406 fileExists: (0, util_1.cachedLookup)(debugFn('fileExists', fileExists)),
407 directoryExists: (0, util_1.cachedLookup)(debugFn('directoryExists', ts.sys.directoryExists)),
408 realpath: ts.sys.realpath
409 ? (0, util_1.cachedLookup)(debugFn('realpath', ts.sys.realpath))
410 : undefined,
411 getNewLine: () => ts.sys.newLine,
412 useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames,
413 getCurrentDirectory: () => cwd,
414 getCompilationSettings: () => config.options,
415 getDefaultLibFileName: () => ts.getDefaultLibFilePath(config.options),
416 getCustomTransformers: getCustomTransformers,
417 trace: options.tsTrace,
418 };
419 const { resolveModuleNames, getResolvedModuleWithFailedLookupLocationsFromCache, resolveTypeReferenceDirectives, isFileKnownToBeInternal, markBucketOfFilenameInternal, } = (0, resolver_functions_1.createResolverFunctions)({
420 host: serviceHost,
421 getCanonicalFileName,
422 ts,
423 cwd,
424 config,
425 projectLocalResolveHelper,
426 options,
427 extensions,
428 });
429 serviceHost.resolveModuleNames = resolveModuleNames;
430 serviceHost.getResolvedModuleWithFailedLookupLocationsFromCache =
431 getResolvedModuleWithFailedLookupLocationsFromCache;
432 serviceHost.resolveTypeReferenceDirectives =
433 resolveTypeReferenceDirectives;
434 const registry = ts.createDocumentRegistry(ts.sys.useCaseSensitiveFileNames, cwd);
435 const service = ts.createLanguageService(serviceHost, registry);
436 const updateMemoryCache = (contents, fileName) => {
437 // Add to `rootFiles` as necessary, either to make TS include a file it has not seen,
438 // or to trigger a re-classification of files from external to internal.
439 if (!rootFileNames.has(fileName) &&
440 !isFileKnownToBeInternal(fileName)) {
441 markBucketOfFilenameInternal(fileName);
442 rootFileNames.add(fileName);
443 // Increment project version for every change to rootFileNames.
444 projectVersion++;
445 }
446 const previousVersion = fileVersions.get(fileName) || 0;
447 const previousContents = fileContents.get(fileName);
448 // Avoid incrementing cache when nothing has changed.
449 if (contents !== previousContents) {
450 fileVersions.set(fileName, previousVersion + 1);
451 fileContents.set(fileName, contents);
452 // Increment project version for every file change.
453 projectVersion++;
454 }
455 };
456 let previousProgram = undefined;
457 getOutput = (code, fileName) => {
458 updateMemoryCache(code, fileName);
459 const programBefore = service.getProgram();
460 if (programBefore !== previousProgram) {
461 (0, exports.debug)(`compiler rebuilt Program instance when getting output for ${fileName}`);
462 }
463 const output = service.getEmitOutput(fileName);
464 // Get the relevant diagnostics - this is 3x faster than `getPreEmitDiagnostics`.
465 const diagnostics = service
466 .getSemanticDiagnostics(fileName)
467 .concat(service.getSyntacticDiagnostics(fileName));
468 const programAfter = service.getProgram();
469 (0, exports.debug)('invariant: Is service.getProject() identical before and after getting emit output and diagnostics? (should always be true) ', programBefore === programAfter);
470 previousProgram = programAfter;
471 const diagnosticList = filterDiagnostics(diagnostics, diagnosticFilters);
472 if (diagnosticList.length)
473 reportTSError(diagnosticList);
474 if (output.emitSkipped) {
475 return [undefined, undefined, true];
476 }
477 // Throw an error when requiring `.d.ts` files.
478 if (output.outputFiles.length === 0) {
479 throw new TypeError(`Unable to require file: ${(0, path_1.relative)(cwd, fileName)}\n` +
480 'This is usually the result of a faulty configuration or import. ' +
481 'Make sure there is a `.js`, `.json` or other executable extension with ' +
482 'loader attached before `ts-node` available.');
483 }
484 return [output.outputFiles[1].text, output.outputFiles[0].text, false];
485 };
486 getTypeInfo = (code, fileName, position) => {
487 const normalizedFileName = (0, util_1.normalizeSlashes)(fileName);
488 updateMemoryCache(code, normalizedFileName);
489 const info = service.getQuickInfoAtPosition(normalizedFileName, position);
490 const name = ts.displayPartsToString(info ? info.displayParts : []);
491 const comment = ts.displayPartsToString(info ? info.documentation : []);
492 return { name, comment };
493 };
494 }
495 else {
496 const sys = {
497 ...ts.sys,
498 ...diagnosticHost,
499 readFile: (fileName) => {
500 const cacheContents = fileContents.get(fileName);
501 if (cacheContents !== undefined)
502 return cacheContents;
503 const contents = cachedReadFile(fileName);
504 if (contents)
505 fileContents.set(fileName, contents);
506 return contents;
507 },
508 readDirectory: ts.sys.readDirectory,
509 getDirectories: (0, util_1.cachedLookup)(debugFn('getDirectories', ts.sys.getDirectories)),
510 fileExists: (0, util_1.cachedLookup)(debugFn('fileExists', fileExists)),
511 directoryExists: (0, util_1.cachedLookup)(debugFn('directoryExists', ts.sys.directoryExists)),
512 resolvePath: (0, util_1.cachedLookup)(debugFn('resolvePath', ts.sys.resolvePath)),
513 realpath: ts.sys.realpath
514 ? (0, util_1.cachedLookup)(debugFn('realpath', ts.sys.realpath))
515 : undefined,
516 };
517 const host = ts.createIncrementalCompilerHost
518 ? ts.createIncrementalCompilerHost(config.options, sys)
519 : {
520 ...sys,
521 getSourceFile: (fileName, languageVersion) => {
522 const contents = sys.readFile(fileName);
523 if (contents === undefined)
524 return;
525 return ts.createSourceFile(fileName, contents, languageVersion);
526 },
527 getDefaultLibLocation: () => (0, util_1.normalizeSlashes)((0, path_1.dirname)(compiler)),
528 getDefaultLibFileName: () => (0, util_1.normalizeSlashes)((0, path_1.join)((0, path_1.dirname)(compiler), ts.getDefaultLibFileName(config.options))),
529 useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
530 };
531 host.trace = options.tsTrace;
532 const { resolveModuleNames, resolveTypeReferenceDirectives, isFileKnownToBeInternal, markBucketOfFilenameInternal, } = (0, resolver_functions_1.createResolverFunctions)({
533 host,
534 cwd,
535 config,
536 ts,
537 getCanonicalFileName,
538 projectLocalResolveHelper,
539 options,
540 extensions,
541 });
542 host.resolveModuleNames = resolveModuleNames;
543 host.resolveTypeReferenceDirectives = resolveTypeReferenceDirectives;
544 // Fallback for older TypeScript releases without incremental API.
545 let builderProgram = ts.createIncrementalProgram
546 ? ts.createIncrementalProgram({
547 rootNames: Array.from(rootFileNames),
548 options: config.options,
549 host,
550 configFileParsingDiagnostics: config.errors,
551 projectReferences: config.projectReferences,
552 })
553 : ts.createEmitAndSemanticDiagnosticsBuilderProgram(Array.from(rootFileNames), config.options, host, undefined, config.errors, config.projectReferences);
554 // Read and cache custom transformers.
555 const customTransformers = typeof transformers === 'function'
556 ? transformers(builderProgram.getProgram())
557 : transformers;
558 // Set the file contents into cache manually.
559 const updateMemoryCache = (contents, fileName) => {
560 const previousContents = fileContents.get(fileName);
561 const contentsChanged = previousContents !== contents;
562 if (contentsChanged) {
563 fileContents.set(fileName, contents);
564 }
565 // Add to `rootFiles` when discovered by compiler for the first time.
566 let addedToRootFileNames = false;
567 if (!rootFileNames.has(fileName) &&
568 !isFileKnownToBeInternal(fileName)) {
569 markBucketOfFilenameInternal(fileName);
570 rootFileNames.add(fileName);
571 addedToRootFileNames = true;
572 }
573 // Update program when file changes.
574 if (addedToRootFileNames || contentsChanged) {
575 builderProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram(Array.from(rootFileNames), config.options, host, builderProgram, config.errors, config.projectReferences);
576 }
577 };
578 getOutput = (code, fileName) => {
579 let outText = '';
580 let outMap = '';
581 updateMemoryCache(code, fileName);
582 const sourceFile = builderProgram.getSourceFile(fileName);
583 if (!sourceFile)
584 throw new TypeError(`Unable to read file: ${fileName}`);
585 const program = builderProgram.getProgram();
586 const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile);
587 const diagnosticList = filterDiagnostics(diagnostics, diagnosticFilters);
588 if (diagnosticList.length)
589 reportTSError(diagnosticList);
590 const result = builderProgram.emit(sourceFile, (path, file, writeByteOrderMark) => {
591 if (path.endsWith('.map')) {
592 outMap = file;
593 }
594 else {
595 outText = file;
596 }
597 if (options.emit)
598 sys.writeFile(path, file, writeByteOrderMark);
599 }, undefined, undefined, customTransformers);
600 if (result.emitSkipped) {
601 return [undefined, undefined, true];
602 }
603 // Throw an error when requiring files that cannot be compiled.
604 if (outText === '') {
605 if (program.isSourceFileFromExternalLibrary(sourceFile)) {
606 throw new TypeError(`Unable to compile file from external library: ${(0, path_1.relative)(cwd, fileName)}`);
607 }
608 throw new TypeError(`Unable to require file: ${(0, path_1.relative)(cwd, fileName)}\n` +
609 'This is usually the result of a faulty configuration or import. ' +
610 'Make sure there is a `.js`, `.json` or other executable extension with ' +
611 'loader attached before `ts-node` available.');
612 }
613 return [outText, outMap, false];
614 };
615 getTypeInfo = (code, fileName, position) => {
616 const normalizedFileName = (0, util_1.normalizeSlashes)(fileName);
617 updateMemoryCache(code, normalizedFileName);
618 const sourceFile = builderProgram.getSourceFile(normalizedFileName);
619 if (!sourceFile)
620 throw new TypeError(`Unable to read file: ${fileName}`);
621 const node = getTokenAtPosition(ts, sourceFile, position);
622 const checker = builderProgram.getProgram().getTypeChecker();
623 const symbol = checker.getSymbolAtLocation(node);
624 if (!symbol)
625 return { name: '', comment: '' };
626 const type = checker.getTypeOfSymbolAtLocation(symbol, node);
627 const signatures = [
628 ...type.getConstructSignatures(),
629 ...type.getCallSignatures(),
630 ];
631 return {
632 name: signatures.length
633 ? signatures.map((x) => checker.signatureToString(x)).join('\n')
634 : checker.typeToString(type),
635 comment: ts.displayPartsToString(symbol ? symbol.getDocumentationComment(checker) : []),
636 };
637 };
638 // Write `.tsbuildinfo` when `--build` is enabled.
639 if (options.emit && config.options.incremental) {
640 process.on('exit', () => {
641 // Emits `.tsbuildinfo` to filesystem.
642 builderProgram.getProgram().emitBuildInfo();
643 });
644 }
645 }
646 }
647 else {
648 getTypeInfo = () => {
649 throw new TypeError('Type information is unavailable in "--transpile-only"');
650 };
651 }
652 function createTranspileOnlyGetOutputFunction(overrideModuleType, nodeModuleEmitKind) {
653 const compilerOptions = { ...config.options };
654 if (overrideModuleType !== undefined)
655 compilerOptions.module = overrideModuleType;
656 let customTranspiler = createTranspiler === null || createTranspiler === void 0 ? void 0 : createTranspiler(compilerOptions, nodeModuleEmitKind);
657 let tsTranspileModule = (0, util_1.versionGteLt)(ts.version, '4.7.0')
658 ? (0, ts_transpile_module_1.createTsTranspileModule)(ts, {
659 compilerOptions,
660 reportDiagnostics: true,
661 transformers: transformers,
662 })
663 : undefined;
664 return (code, fileName) => {
665 let result;
666 if (customTranspiler) {
667 result = customTranspiler.transpile(code, {
668 fileName,
669 });
670 }
671 else if (tsTranspileModule) {
672 result = tsTranspileModule(code, {
673 fileName,
674 }, nodeModuleEmitKind === 'nodeesm' ? 'module' : 'commonjs');
675 }
676 else {
677 result = ts.transpileModule(code, {
678 fileName,
679 compilerOptions,
680 reportDiagnostics: true,
681 transformers: transformers,
682 });
683 }
684 const diagnosticList = filterDiagnostics(result.diagnostics || [], diagnosticFilters);
685 if (diagnosticList.length)
686 reportTSError(diagnosticList);
687 return [result.outputText, result.sourceMapText, false];
688 };
689 }
690 // When true, these mean that a `moduleType` override will cause a different emit
691 // than the TypeScript compiler, so we *must* overwrite the emit.
692 const shouldOverwriteEmitWhenForcingCommonJS = config.options.module !== ts.ModuleKind.CommonJS;
693 // [MUST_UPDATE_FOR_NEW_MODULEKIND]
694 const shouldOverwriteEmitWhenForcingEsm = !(config.options.module === ts.ModuleKind.ES2015 ||
695 (ts.ModuleKind.ES2020 && config.options.module === ts.ModuleKind.ES2020) ||
696 (ts.ModuleKind.ES2022 && config.options.module === ts.ModuleKind.ES2022) ||
697 config.options.module === ts.ModuleKind.ESNext);
698 /**
699 * node16 or nodenext
700 * [MUST_UPDATE_FOR_NEW_MODULEKIND]
701 */
702 const isNodeModuleType = (ts.ModuleKind.Node16 && config.options.module === ts.ModuleKind.Node16) ||
703 (ts.ModuleKind.NodeNext &&
704 config.options.module === ts.ModuleKind.NodeNext);
705 const getOutputForceCommonJS = createTranspileOnlyGetOutputFunction(ts.ModuleKind.CommonJS);
706 const getOutputForceNodeCommonJS = createTranspileOnlyGetOutputFunction(ts.ModuleKind.NodeNext, 'nodecjs');
707 const getOutputForceNodeESM = createTranspileOnlyGetOutputFunction(ts.ModuleKind.NodeNext, 'nodeesm');
708 // [MUST_UPDATE_FOR_NEW_MODULEKIND]
709 const getOutputForceESM = createTranspileOnlyGetOutputFunction(ts.ModuleKind.ES2022 || ts.ModuleKind.ES2020 || ts.ModuleKind.ES2015);
710 const getOutputTranspileOnly = createTranspileOnlyGetOutputFunction();
711 // Create a simple TypeScript compiler proxy.
712 function compile(code, fileName, lineOffset = 0) {
713 const normalizedFileName = (0, util_1.normalizeSlashes)(fileName);
714 const classification = moduleTypeClassifier.classifyModuleByModuleTypeOverrides(normalizedFileName);
715 let value = '';
716 let sourceMap = '';
717 let emitSkipped = true;
718 if (getOutput) {
719 // Must always call normal getOutput to throw typechecking errors
720 [value, sourceMap, emitSkipped] = getOutput(code, normalizedFileName);
721 }
722 // If module classification contradicts the above, call the relevant transpiler
723 if (classification.moduleType === 'cjs' &&
724 (shouldOverwriteEmitWhenForcingCommonJS || emitSkipped)) {
725 [value, sourceMap] = getOutputForceCommonJS(code, normalizedFileName);
726 }
727 else if (classification.moduleType === 'esm' &&
728 (shouldOverwriteEmitWhenForcingEsm || emitSkipped)) {
729 [value, sourceMap] = getOutputForceESM(code, normalizedFileName);
730 }
731 else if (emitSkipped) {
732 // Happens when ts compiler skips emit or in transpileOnly mode
733 const classification = (0, node_module_type_classifier_1.classifyModule)(fileName, isNodeModuleType);
734 [value, sourceMap] =
735 classification === 'nodecjs'
736 ? getOutputForceNodeCommonJS(code, normalizedFileName)
737 : classification === 'nodeesm'
738 ? getOutputForceNodeESM(code, normalizedFileName)
739 : classification === 'cjs'
740 ? getOutputForceCommonJS(code, normalizedFileName)
741 : classification === 'esm'
742 ? getOutputForceESM(code, normalizedFileName)
743 : getOutputTranspileOnly(code, normalizedFileName);
744 }
745 const output = updateOutput(value, normalizedFileName, sourceMap, getEmitExtension);
746 outputCache.set(normalizedFileName, { content: output });
747 return output;
748 }
749 let active = true;
750 const enabled = (enabled) => enabled === undefined ? active : (active = !!enabled);
751 const ignored = (fileName) => {
752 if (!active)
753 return true;
754 const ext = (0, path_1.extname)(fileName);
755 if (extensions.compiled.includes(ext)) {
756 return !isScoped(fileName) || shouldIgnore(fileName);
757 }
758 return true;
759 };
760 function addDiagnosticFilter(filter) {
761 diagnosticFilters.push({
762 ...filter,
763 filenamesAbsolute: filter.filenamesAbsolute.map((f) => (0, util_1.normalizeSlashes)(f)),
764 });
765 }
766 const getNodeEsmResolver = (0, util_1.once)(() => require('../dist-raw/node-internal-modules-esm-resolve').createResolve({
767 extensions,
768 preferTsExts: options.preferTsExts,
769 tsNodeExperimentalSpecifierResolution: options.experimentalSpecifierResolution,
770 }));
771 const getNodeEsmGetFormat = (0, util_1.once)(() => require('../dist-raw/node-internal-modules-esm-get_format').createGetFormat(options.experimentalSpecifierResolution, getNodeEsmResolver()));
772 const getNodeCjsLoader = (0, util_1.once)(() => require('../dist-raw/node-internal-modules-cjs-loader').createCjsLoader({
773 extensions,
774 preferTsExts: options.preferTsExts,
775 nodeEsmResolver: getNodeEsmResolver(),
776 }));
777 return {
778 [TS_NODE_SERVICE_BRAND]: true,
779 ts,
780 compilerPath: compiler,
781 config,
782 compile,
783 getTypeInfo,
784 ignored,
785 enabled,
786 options,
787 configFilePath,
788 moduleTypeClassifier,
789 shouldReplAwait,
790 addDiagnosticFilter,
791 installSourceMapSupport,
792 enableExperimentalEsmLoaderInterop,
793 transpileOnly,
794 projectLocalResolveHelper,
795 getNodeEsmResolver,
796 getNodeEsmGetFormat,
797 getNodeCjsLoader,
798 extensions,
799 };
800}
801exports.createFromPreloadedConfig = createFromPreloadedConfig;
802/**
803 * Check if the filename should be ignored.
804 */
805function createIgnore(ignoreBaseDir, ignore) {
806 return (fileName) => {
807 const relname = (0, path_1.relative)(ignoreBaseDir, fileName);
808 const path = (0, util_1.normalizeSlashes)(relname);
809 return ignore.some((x) => x.test(path));
810 };
811}
812/**
813 * Register the extensions to support when importing files.
814 */
815function registerExtensions(preferTsExts, extensions, service, originalJsHandler) {
816 const exts = new Set(extensions);
817 // Can't add these extensions cuz would allow omitting file extension; node requires ext for .cjs and .mjs
818 // Unless they're already registered by something else (nyc does this):
819 // then we *must* hook them or else our transformer will not be called.
820 for (const cannotAdd of ['.mts', '.cts', '.mjs', '.cjs']) {
821 if (exts.has(cannotAdd) && !(0, util_1.hasOwnProperty)(require.extensions, cannotAdd)) {
822 // Unrecognized file exts can be transformed via the `.js` handler.
823 exts.add('.js');
824 exts.delete(cannotAdd);
825 }
826 }
827 // Register new extensions.
828 for (const ext of exts) {
829 registerExtension(ext, service, originalJsHandler);
830 }
831 if (preferTsExts) {
832 const preferredExtensions = new Set([
833 ...exts,
834 ...Object.keys(require.extensions),
835 ]);
836 // Re-sort iteration order of Object.keys()
837 for (const ext of preferredExtensions) {
838 const old = Object.getOwnPropertyDescriptor(require.extensions, ext);
839 delete require.extensions[ext];
840 Object.defineProperty(require.extensions, ext, old);
841 }
842 }
843}
844/**
845 * Register the extension for node.
846 */
847function registerExtension(ext, service, originalHandler) {
848 const old = require.extensions[ext] || originalHandler;
849 require.extensions[ext] = function (m, filename) {
850 if (service.ignored(filename))
851 return old(m, filename);
852 assertScriptCanLoadAsCJS(service, m, filename);
853 const _compile = m._compile;
854 m._compile = function (code, fileName) {
855 (0, exports.debug)('module._compile', fileName);
856 const result = service.compile(code, fileName);
857 return _compile.call(this, result, fileName);
858 };
859 return old(m, filename);
860 };
861}
862/**
863 * Update the output remapping the source map.
864 */
865function updateOutput(outputText, fileName, sourceMap, getEmitExtension) {
866 const base64Map = Buffer.from(updateSourceMap(sourceMap, fileName), 'utf8').toString('base64');
867 const sourceMapContent = `//# sourceMappingURL=data:application/json;charset=utf-8;base64,${base64Map}`;
868 // Expected form: `//# sourceMappingURL=foo bar.js.map` or `//# sourceMappingURL=foo%20bar.js.map` for input file "foo bar.tsx"
869 // Percent-encoding behavior added in TS 4.1.1: https://github.com/microsoft/TypeScript/issues/40951
870 const prefix = '//# sourceMappingURL=';
871 const prefixLength = prefix.length;
872 const baseName = /*foo.tsx*/ (0, path_1.basename)(fileName);
873 const extName = /*.tsx*/ (0, path_1.extname)(fileName);
874 const extension = /*.js*/ getEmitExtension(fileName);
875 const sourcemapFilename = baseName.slice(0, -extName.length) + extension + '.map';
876 const sourceMapLengthWithoutPercentEncoding = prefixLength + sourcemapFilename.length;
877 /*
878 * Only rewrite if existing directive exists at the location we expect, to support:
879 * a) compilers that do not append a sourcemap directive
880 * b) situations where we did the math wrong
881 * Not ideal, but appending our sourcemap *after* a pre-existing sourcemap still overrides, so the end-user is happy.
882 */
883 if (outputText.substr(-sourceMapLengthWithoutPercentEncoding, prefixLength) ===
884 prefix) {
885 return (outputText.slice(0, -sourceMapLengthWithoutPercentEncoding) +
886 sourceMapContent);
887 }
888 // If anyone asks why we're not using URL, the URL equivalent is: `u = new URL('http://d'); u.pathname = "/" + sourcemapFilename; return u.pathname.slice(1);
889 const sourceMapLengthWithPercentEncoding = prefixLength + encodeURI(sourcemapFilename).length;
890 if (outputText.substr(-sourceMapLengthWithPercentEncoding, prefixLength) ===
891 prefix) {
892 return (outputText.slice(0, -sourceMapLengthWithPercentEncoding) +
893 sourceMapContent);
894 }
895 return `${outputText}\n${sourceMapContent}`;
896}
897/**
898 * Update the source map contents for improved output.
899 */
900function updateSourceMap(sourceMapText, fileName) {
901 const sourceMap = JSON.parse(sourceMapText);
902 sourceMap.file = fileName;
903 sourceMap.sources = [fileName];
904 delete sourceMap.sourceRoot;
905 return JSON.stringify(sourceMap);
906}
907/**
908 * Filter diagnostics.
909 */
910function filterDiagnostics(diagnostics, filters) {
911 return diagnostics.filter((d) => filters.every((f) => {
912 var _a;
913 return (!f.appliesToAllFiles &&
914 f.filenamesAbsolute.indexOf((_a = d.file) === null || _a === void 0 ? void 0 : _a.fileName) === -1) ||
915 f.diagnosticsIgnored.indexOf(d.code) === -1;
916 }));
917}
918/**
919 * Get token at file position.
920 *
921 * Reference: https://github.com/microsoft/TypeScript/blob/fcd9334f57d85b73dd66ad2d21c02e84822f4841/src/services/utilities.ts#L705-L731
922 */
923function getTokenAtPosition(ts, sourceFile, position) {
924 let current = sourceFile;
925 outer: while (true) {
926 for (const child of current.getChildren(sourceFile)) {
927 const start = child.getFullStart();
928 if (start > position)
929 break;
930 const end = child.getEnd();
931 if (position <= end) {
932 current = child;
933 continue outer;
934 }
935 }
936 return current;
937 }
938}
939/**
940 * Create an implementation of node's ESM loader hooks.
941 *
942 * This may be useful if you
943 * want to wrap or compose the loader hooks to add additional functionality or
944 * combine with another loader.
945 *
946 * Node changed the hooks API, so there are two possible APIs. This function
947 * detects your node version and returns the appropriate API.
948 *
949 * @category ESM Loader
950 */
951const createEsmHooks = (tsNodeService) => require('./esm').createEsmHooks(tsNodeService);
952exports.createEsmHooks = createEsmHooks;
953//# sourceMappingURL=index.js.map
\No newline at end of file