index.js 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. "use strict";
  2. var _a;
  3. Object.defineProperty(exports, "__esModule", { value: true });
  4. exports.create = exports.register = exports.getExtensions = exports.TSError = exports.normalizeSlashes = exports.parse = exports.split = exports.DEFAULTS = exports.VERSION = exports.debug = exports.INSPECT_CUSTOM = exports.REGISTER_INSTANCE = exports.createRepl = void 0;
  5. const path_1 = require("path");
  6. const sourceMapSupport = require("source-map-support");
  7. const ynModule = require("yn");
  8. const make_error_1 = require("make-error");
  9. const util = require("util");
  10. const url_1 = require("url");
  11. const module_1 = require("module");
  12. // tslint:disable-next-line
  13. const createRequire = (_a = module_1.createRequire !== null && module_1.createRequire !== void 0 ? module_1.createRequire : module_1.createRequireFromPath) !== null && _a !== void 0 ? _a : require('create-require');
  14. var repl_1 = require("./repl");
  15. Object.defineProperty(exports, "createRepl", { enumerable: true, get: function () { return repl_1.createRepl; } });
  16. /**
  17. * Does this version of node obey the package.json "type" field
  18. * and throw ERR_REQUIRE_ESM when attempting to require() an ESM modules.
  19. */
  20. const engineSupportsPackageTypeField = parseInt(process.versions.node.split('.')[0], 10) >= 12;
  21. // Loaded conditionally so we don't need to support older node versions
  22. let assertScriptCanLoadAsCJSImpl;
  23. /**
  24. * Assert that script can be loaded as CommonJS when we attempt to require it.
  25. * If it should be loaded as ESM, throw ERR_REQUIRE_ESM like node does.
  26. */
  27. function assertScriptCanLoadAsCJS(filename) {
  28. if (!engineSupportsPackageTypeField)
  29. return;
  30. if (!assertScriptCanLoadAsCJSImpl)
  31. assertScriptCanLoadAsCJSImpl = require('../dist-raw/node-cjs-loader-utils').assertScriptCanLoadAsCJSImpl;
  32. assertScriptCanLoadAsCJSImpl(filename);
  33. }
  34. /**
  35. * Registered `ts-node` instance information.
  36. */
  37. exports.REGISTER_INSTANCE = Symbol.for('ts-node.register.instance');
  38. /**
  39. * @internal
  40. */
  41. exports.INSPECT_CUSTOM = util.inspect.custom || 'inspect';
  42. /**
  43. * Wrapper around yn module that returns `undefined` instead of `null`.
  44. * This is implemented by yn v4, but we're staying on v3 to avoid v4's node 10 requirement.
  45. */
  46. function yn(value) {
  47. var _a;
  48. return (_a = ynModule(value)) !== null && _a !== void 0 ? _a : undefined;
  49. }
  50. /**
  51. * Debugging `ts-node`.
  52. */
  53. const shouldDebug = yn(process.env.TS_NODE_DEBUG);
  54. /** @internal */
  55. exports.debug = shouldDebug ?
  56. (...args) => console.log(`[ts-node ${new Date().toISOString()}]`, ...args)
  57. : () => undefined;
  58. const debugFn = shouldDebug ?
  59. (key, fn) => {
  60. let i = 0;
  61. return (x) => {
  62. exports.debug(key, x, ++i);
  63. return fn(x);
  64. };
  65. } :
  66. (_, fn) => fn;
  67. /**
  68. * Export the current version.
  69. */
  70. exports.VERSION = require('../package.json').version;
  71. /**
  72. * Like `Object.assign`, but ignores `undefined` properties.
  73. */
  74. function assign(initialValue, ...sources) {
  75. for (const source of sources) {
  76. for (const key of Object.keys(source)) {
  77. const value = source[key];
  78. if (value !== undefined)
  79. initialValue[key] = value;
  80. }
  81. }
  82. return initialValue;
  83. }
  84. /**
  85. * Default register options, including values specified via environment
  86. * variables.
  87. */
  88. exports.DEFAULTS = {
  89. dir: process.env.TS_NODE_DIR,
  90. emit: yn(process.env.TS_NODE_EMIT),
  91. scope: yn(process.env.TS_NODE_SCOPE),
  92. files: yn(process.env.TS_NODE_FILES),
  93. pretty: yn(process.env.TS_NODE_PRETTY),
  94. compiler: process.env.TS_NODE_COMPILER,
  95. compilerOptions: parse(process.env.TS_NODE_COMPILER_OPTIONS),
  96. ignore: split(process.env.TS_NODE_IGNORE),
  97. project: process.env.TS_NODE_PROJECT,
  98. skipProject: yn(process.env.TS_NODE_SKIP_PROJECT),
  99. skipIgnore: yn(process.env.TS_NODE_SKIP_IGNORE),
  100. preferTsExts: yn(process.env.TS_NODE_PREFER_TS_EXTS),
  101. ignoreDiagnostics: split(process.env.TS_NODE_IGNORE_DIAGNOSTICS),
  102. transpileOnly: yn(process.env.TS_NODE_TRANSPILE_ONLY),
  103. typeCheck: yn(process.env.TS_NODE_TYPE_CHECK),
  104. compilerHost: yn(process.env.TS_NODE_COMPILER_HOST),
  105. logError: yn(process.env.TS_NODE_LOG_ERROR),
  106. experimentalEsmLoader: false
  107. };
  108. /**
  109. * TypeScript compiler option values required by `ts-node` which cannot be overridden.
  110. */
  111. const TS_NODE_COMPILER_OPTIONS = {
  112. sourceMap: true,
  113. inlineSourceMap: false,
  114. inlineSources: true,
  115. declaration: false,
  116. noEmit: false,
  117. outDir: '.ts-node'
  118. };
  119. /**
  120. * Split a string array of values.
  121. */
  122. function split(value) {
  123. return typeof value === 'string' ? value.split(/ *, */g) : undefined;
  124. }
  125. exports.split = split;
  126. /**
  127. * Parse a string as JSON.
  128. */
  129. function parse(value) {
  130. return typeof value === 'string' ? JSON.parse(value) : undefined;
  131. }
  132. exports.parse = parse;
  133. /**
  134. * Replace backslashes with forward slashes.
  135. */
  136. function normalizeSlashes(value) {
  137. return value.replace(/\\/g, '/');
  138. }
  139. exports.normalizeSlashes = normalizeSlashes;
  140. /**
  141. * TypeScript diagnostics error.
  142. */
  143. class TSError extends make_error_1.BaseError {
  144. constructor(diagnosticText, diagnosticCodes) {
  145. super(`⨯ Unable to compile TypeScript:\n${diagnosticText}`);
  146. this.diagnosticText = diagnosticText;
  147. this.diagnosticCodes = diagnosticCodes;
  148. this.name = 'TSError';
  149. }
  150. /**
  151. * @internal
  152. */
  153. [exports.INSPECT_CUSTOM]() {
  154. return this.diagnosticText;
  155. }
  156. }
  157. exports.TSError = TSError;
  158. /**
  159. * Cached fs operation wrapper.
  160. */
  161. function cachedLookup(fn) {
  162. const cache = new Map();
  163. return (arg) => {
  164. if (!cache.has(arg)) {
  165. cache.set(arg, fn(arg));
  166. }
  167. return cache.get(arg);
  168. };
  169. }
  170. /** @internal */
  171. function getExtensions(config) {
  172. const tsExtensions = ['.ts'];
  173. const jsExtensions = [];
  174. // Enable additional extensions when JSX or `allowJs` is enabled.
  175. if (config.options.jsx)
  176. tsExtensions.push('.tsx');
  177. if (config.options.allowJs)
  178. jsExtensions.push('.js');
  179. if (config.options.jsx && config.options.allowJs)
  180. jsExtensions.push('.jsx');
  181. return { tsExtensions, jsExtensions };
  182. }
  183. exports.getExtensions = getExtensions;
  184. /**
  185. * Register TypeScript compiler instance onto node.js
  186. */
  187. function register(opts = {}) {
  188. const originalJsHandler = require.extensions['.js']; // tslint:disable-line
  189. const service = create(opts);
  190. const { tsExtensions, jsExtensions } = getExtensions(service.config);
  191. const extensions = [...tsExtensions, ...jsExtensions];
  192. // Expose registered instance globally.
  193. process[exports.REGISTER_INSTANCE] = service;
  194. // Register the extensions.
  195. registerExtensions(service.options.preferTsExts, extensions, service, originalJsHandler);
  196. module_1.Module._preloadModules(service.options.require);
  197. return service;
  198. }
  199. exports.register = register;
  200. /**
  201. * Create TypeScript compiler instance.
  202. */
  203. function create(rawOptions = {}) {
  204. var _a, _b;
  205. const dir = (_a = rawOptions.dir) !== null && _a !== void 0 ? _a : exports.DEFAULTS.dir;
  206. const compilerName = (_b = rawOptions.compiler) !== null && _b !== void 0 ? _b : exports.DEFAULTS.compiler;
  207. const cwd = dir ? path_1.resolve(dir) : process.cwd();
  208. /**
  209. * Load the typescript compiler. It is required to load the tsconfig but might
  210. * be changed by the tsconfig, so we sometimes have to do this twice.
  211. */
  212. function loadCompiler(name) {
  213. const compiler = require.resolve(name || 'typescript', { paths: [cwd, __dirname] });
  214. const ts = require(compiler);
  215. return { compiler, ts };
  216. }
  217. // Compute minimum options to read the config file.
  218. let { compiler, ts } = loadCompiler(compilerName);
  219. // Read config file and merge new options between env and CLI options.
  220. const { config, options: tsconfigOptions } = readConfig(cwd, ts, rawOptions);
  221. const options = assign({}, exports.DEFAULTS, tsconfigOptions || {}, rawOptions);
  222. options.require = [
  223. ...tsconfigOptions.require || [],
  224. ...rawOptions.require || []
  225. ];
  226. // If `compiler` option changed based on tsconfig, re-load the compiler.
  227. if (options.compiler !== compilerName) {
  228. ({ compiler, ts } = loadCompiler(options.compiler));
  229. }
  230. const readFile = options.readFile || ts.sys.readFile;
  231. const fileExists = options.fileExists || ts.sys.fileExists;
  232. // typeCheck can override transpileOnly, useful for CLI flag to override config file
  233. const transpileOnly = options.transpileOnly === true && options.typeCheck !== true;
  234. const transformers = options.transformers || undefined;
  235. const ignoreDiagnostics = [
  236. 6059,
  237. 18002,
  238. 18003,
  239. ...(options.ignoreDiagnostics || [])
  240. ].map(Number);
  241. const configDiagnosticList = filterDiagnostics(config.errors, ignoreDiagnostics);
  242. const outputCache = new Map();
  243. const isScoped = options.scope ? (relname) => relname.charAt(0) !== '.' : () => true;
  244. const shouldIgnore = createIgnore(options.skipIgnore ? [] : (options.ignore || ['(?:^|/)node_modules/']).map(str => new RegExp(str)));
  245. const diagnosticHost = {
  246. getNewLine: () => ts.sys.newLine,
  247. getCurrentDirectory: () => cwd,
  248. getCanonicalFileName: ts.sys.useCaseSensitiveFileNames ? x => x : x => x.toLowerCase()
  249. };
  250. // Install source map support and read from memory cache.
  251. sourceMapSupport.install({
  252. environment: 'node',
  253. retrieveFile(pathOrUrl) {
  254. var _a;
  255. let path = pathOrUrl;
  256. // If it's a file URL, convert to local path
  257. // Note: fileURLToPath does not exist on early node v10
  258. // I could not find a way to handle non-URLs except to swallow an error
  259. if (options.experimentalEsmLoader && path.startsWith('file://')) {
  260. try {
  261. path = url_1.fileURLToPath(path);
  262. }
  263. catch (e) { /* swallow error */ }
  264. }
  265. path = normalizeSlashes(path);
  266. return ((_a = outputCache.get(path)) === null || _a === void 0 ? void 0 : _a.content) || '';
  267. }
  268. });
  269. const formatDiagnostics = process.stdout.isTTY || options.pretty
  270. ? (ts.formatDiagnosticsWithColorAndContext || ts.formatDiagnostics)
  271. : ts.formatDiagnostics;
  272. function createTSError(diagnostics) {
  273. const diagnosticText = formatDiagnostics(diagnostics, diagnosticHost);
  274. const diagnosticCodes = diagnostics.map(x => x.code);
  275. return new TSError(diagnosticText, diagnosticCodes);
  276. }
  277. function reportTSError(configDiagnosticList) {
  278. const error = createTSError(configDiagnosticList);
  279. if (options.logError) {
  280. // Print error in red color and continue execution.
  281. console.error('\x1b[31m%s\x1b[0m', error);
  282. }
  283. else {
  284. // Throw error and exit the script.
  285. throw error;
  286. }
  287. }
  288. // Render the configuration errors.
  289. if (configDiagnosticList.length)
  290. reportTSError(configDiagnosticList);
  291. /**
  292. * Get the extension for a transpiled file.
  293. */
  294. const getExtension = config.options.jsx === ts.JsxEmit.Preserve ?
  295. ((path) => /\.[tj]sx$/.test(path) ? '.jsx' : '.js') :
  296. ((_) => '.js');
  297. /**
  298. * Create the basic required function using transpile mode.
  299. */
  300. let getOutput;
  301. let getTypeInfo;
  302. const getCanonicalFileName = ts.createGetCanonicalFileName(ts.sys.useCaseSensitiveFileNames);
  303. // In a factory because these are shared across both CompilerHost and LanguageService codepaths
  304. function createResolverFunctions(serviceHost) {
  305. const moduleResolutionCache = ts.createModuleResolutionCache(cwd, getCanonicalFileName, config.options);
  306. const knownInternalFilenames = new Set();
  307. /** "Buckets" (module directories) whose contents should be marked "internal" */
  308. const internalBuckets = new Set();
  309. // Get bucket for a source filename. Bucket is the containing `./node_modules/*/` directory
  310. // For '/project/node_modules/foo/node_modules/bar/lib/index.js' bucket is '/project/node_modules/foo/node_modules/bar/'
  311. // For '/project/node_modules/foo/node_modules/@scope/bar/lib/index.js' bucket is '/project/node_modules/foo/node_modules/@scope/bar/'
  312. const moduleBucketRe = /.*\/node_modules\/(?:@[^\/]+\/)?[^\/]+\//;
  313. function getModuleBucket(filename) {
  314. const find = moduleBucketRe.exec(filename);
  315. if (find)
  316. return find[0];
  317. return '';
  318. }
  319. // Mark that this file and all siblings in its bucket should be "internal"
  320. function markBucketOfFilenameInternal(filename) {
  321. internalBuckets.add(getModuleBucket(filename));
  322. }
  323. function isFileInInternalBucket(filename) {
  324. return internalBuckets.has(getModuleBucket(filename));
  325. }
  326. function isFileKnownToBeInternal(filename) {
  327. return knownInternalFilenames.has(filename);
  328. }
  329. /**
  330. * If we need to emit JS for a file, force TS to consider it non-external
  331. */
  332. const fixupResolvedModule = (resolvedModule) => {
  333. const { resolvedFileName } = resolvedModule;
  334. if (resolvedFileName === undefined)
  335. return;
  336. // .ts is always switched to internal
  337. // .js is switched on-demand
  338. if (resolvedModule.isExternalLibraryImport && ((resolvedFileName.endsWith('.ts') && !resolvedFileName.endsWith('.d.ts')) ||
  339. isFileKnownToBeInternal(resolvedFileName) ||
  340. isFileInInternalBucket(resolvedFileName))) {
  341. resolvedModule.isExternalLibraryImport = false;
  342. }
  343. if (!resolvedModule.isExternalLibraryImport) {
  344. knownInternalFilenames.add(resolvedFileName);
  345. }
  346. };
  347. /*
  348. * NOTE:
  349. * Older ts versions do not pass `redirectedReference` nor `options`.
  350. * We must pass `redirectedReference` to newer ts versions, but cannot rely on `options`, hence the weird argument name
  351. */
  352. const resolveModuleNames = (moduleNames, containingFile, reusedNames, redirectedReference, optionsOnlyWithNewerTsVersions) => {
  353. return moduleNames.map(moduleName => {
  354. const { resolvedModule } = ts.resolveModuleName(moduleName, containingFile, config.options, serviceHost, moduleResolutionCache, redirectedReference);
  355. if (resolvedModule) {
  356. fixupResolvedModule(resolvedModule);
  357. }
  358. return resolvedModule;
  359. });
  360. };
  361. // language service never calls this, but TS docs recommend that we implement it
  362. const getResolvedModuleWithFailedLookupLocationsFromCache = (moduleName, containingFile) => {
  363. const ret = ts.resolveModuleNameFromCache(moduleName, containingFile, moduleResolutionCache);
  364. if (ret && ret.resolvedModule) {
  365. fixupResolvedModule(ret.resolvedModule);
  366. }
  367. return ret;
  368. };
  369. const resolveTypeReferenceDirectives = (typeDirectiveNames, containingFile, redirectedReference, options) => {
  370. // Note: seems to be called with empty typeDirectiveNames array for all files.
  371. return typeDirectiveNames.map(typeDirectiveName => {
  372. const { resolvedTypeReferenceDirective } = ts.resolveTypeReferenceDirective(typeDirectiveName, containingFile, config.options, serviceHost, redirectedReference);
  373. if (resolvedTypeReferenceDirective) {
  374. fixupResolvedModule(resolvedTypeReferenceDirective);
  375. }
  376. return resolvedTypeReferenceDirective;
  377. });
  378. };
  379. return {
  380. resolveModuleNames,
  381. getResolvedModuleWithFailedLookupLocationsFromCache,
  382. resolveTypeReferenceDirectives,
  383. isFileKnownToBeInternal,
  384. markBucketOfFilenameInternal
  385. };
  386. }
  387. // Use full language services when the fast option is disabled.
  388. if (!transpileOnly) {
  389. const fileContents = new Map();
  390. const rootFileNames = new Set(config.fileNames);
  391. const cachedReadFile = cachedLookup(debugFn('readFile', readFile));
  392. // Use language services by default (TODO: invert next major version).
  393. if (!options.compilerHost) {
  394. let projectVersion = 1;
  395. const fileVersions = new Map(Array.from(rootFileNames).map(fileName => [fileName, 0]));
  396. const getCustomTransformers = () => {
  397. if (typeof transformers === 'function') {
  398. const program = service.getProgram();
  399. return program ? transformers(program) : undefined;
  400. }
  401. return transformers;
  402. };
  403. // Create the compiler host for type checking.
  404. const serviceHost = {
  405. getProjectVersion: () => String(projectVersion),
  406. getScriptFileNames: () => Array.from(rootFileNames),
  407. getScriptVersion: (fileName) => {
  408. const version = fileVersions.get(fileName);
  409. return version ? version.toString() : '';
  410. },
  411. getScriptSnapshot(fileName) {
  412. // TODO ordering of this with getScriptVersion? Should they sync up?
  413. let contents = fileContents.get(fileName);
  414. // Read contents into TypeScript memory cache.
  415. if (contents === undefined) {
  416. contents = cachedReadFile(fileName);
  417. if (contents === undefined)
  418. return;
  419. fileVersions.set(fileName, 1);
  420. fileContents.set(fileName, contents);
  421. projectVersion++;
  422. }
  423. return ts.ScriptSnapshot.fromString(contents);
  424. },
  425. readFile: cachedReadFile,
  426. readDirectory: ts.sys.readDirectory,
  427. getDirectories: cachedLookup(debugFn('getDirectories', ts.sys.getDirectories)),
  428. fileExists: cachedLookup(debugFn('fileExists', fileExists)),
  429. directoryExists: cachedLookup(debugFn('directoryExists', ts.sys.directoryExists)),
  430. realpath: ts.sys.realpath ? cachedLookup(debugFn('realpath', ts.sys.realpath)) : undefined,
  431. getNewLine: () => ts.sys.newLine,
  432. useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames,
  433. getCurrentDirectory: () => cwd,
  434. getCompilationSettings: () => config.options,
  435. getDefaultLibFileName: () => ts.getDefaultLibFilePath(config.options),
  436. getCustomTransformers: getCustomTransformers
  437. };
  438. const { resolveModuleNames, getResolvedModuleWithFailedLookupLocationsFromCache, resolveTypeReferenceDirectives, isFileKnownToBeInternal, markBucketOfFilenameInternal } = createResolverFunctions(serviceHost);
  439. serviceHost.resolveModuleNames = resolveModuleNames;
  440. serviceHost.getResolvedModuleWithFailedLookupLocationsFromCache = getResolvedModuleWithFailedLookupLocationsFromCache;
  441. serviceHost.resolveTypeReferenceDirectives = resolveTypeReferenceDirectives;
  442. const registry = ts.createDocumentRegistry(ts.sys.useCaseSensitiveFileNames, cwd);
  443. const service = ts.createLanguageService(serviceHost, registry);
  444. const updateMemoryCache = (contents, fileName) => {
  445. // Add to `rootFiles` as necessary, either to make TS include a file it has not seen,
  446. // or to trigger a re-classification of files from external to internal.
  447. if (!rootFileNames.has(fileName) && !isFileKnownToBeInternal(fileName)) {
  448. markBucketOfFilenameInternal(fileName);
  449. rootFileNames.add(fileName);
  450. // Increment project version for every change to rootFileNames.
  451. projectVersion++;
  452. }
  453. const previousVersion = fileVersions.get(fileName) || 0;
  454. const previousContents = fileContents.get(fileName);
  455. // Avoid incrementing cache when nothing has changed.
  456. if (contents !== previousContents) {
  457. fileVersions.set(fileName, previousVersion + 1);
  458. fileContents.set(fileName, contents);
  459. // Increment project version for every file change.
  460. projectVersion++;
  461. }
  462. };
  463. let previousProgram = undefined;
  464. getOutput = (code, fileName) => {
  465. updateMemoryCache(code, fileName);
  466. const programBefore = service.getProgram();
  467. if (programBefore !== previousProgram) {
  468. exports.debug(`compiler rebuilt Program instance when getting output for ${fileName}`);
  469. }
  470. const output = service.getEmitOutput(fileName);
  471. // Get the relevant diagnostics - this is 3x faster than `getPreEmitDiagnostics`.
  472. const diagnostics = service.getSemanticDiagnostics(fileName)
  473. .concat(service.getSyntacticDiagnostics(fileName));
  474. const programAfter = service.getProgram();
  475. exports.debug('invariant: Is service.getProject() identical before and after getting emit output and diagnostics? (should always be true) ', programBefore === programAfter);
  476. previousProgram = programAfter;
  477. const diagnosticList = filterDiagnostics(diagnostics, ignoreDiagnostics);
  478. if (diagnosticList.length)
  479. reportTSError(diagnosticList);
  480. if (output.emitSkipped) {
  481. throw new TypeError(`${path_1.relative(cwd, fileName)}: Emit skipped`);
  482. }
  483. // Throw an error when requiring `.d.ts` files.
  484. if (output.outputFiles.length === 0) {
  485. throw new TypeError(`Unable to require file: ${path_1.relative(cwd, fileName)}\n` +
  486. 'This is usually the result of a faulty configuration or import. ' +
  487. 'Make sure there is a `.js`, `.json` or other executable extension with ' +
  488. 'loader attached before `ts-node` available.');
  489. }
  490. return [output.outputFiles[1].text, output.outputFiles[0].text];
  491. };
  492. getTypeInfo = (code, fileName, position) => {
  493. updateMemoryCache(code, fileName);
  494. const info = service.getQuickInfoAtPosition(fileName, position);
  495. const name = ts.displayPartsToString(info ? info.displayParts : []);
  496. const comment = ts.displayPartsToString(info ? info.documentation : []);
  497. return { name, comment };
  498. };
  499. }
  500. else {
  501. const sys = Object.assign(Object.assign(Object.assign({}, ts.sys), diagnosticHost), { readFile: (fileName) => {
  502. const cacheContents = fileContents.get(fileName);
  503. if (cacheContents !== undefined)
  504. return cacheContents;
  505. const contents = cachedReadFile(fileName);
  506. if (contents)
  507. fileContents.set(fileName, contents);
  508. return contents;
  509. }, readDirectory: ts.sys.readDirectory, getDirectories: cachedLookup(debugFn('getDirectories', ts.sys.getDirectories)), fileExists: cachedLookup(debugFn('fileExists', fileExists)), directoryExists: cachedLookup(debugFn('directoryExists', ts.sys.directoryExists)), resolvePath: cachedLookup(debugFn('resolvePath', ts.sys.resolvePath)), realpath: ts.sys.realpath ? cachedLookup(debugFn('realpath', ts.sys.realpath)) : undefined });
  510. const host = ts.createIncrementalCompilerHost
  511. ? ts.createIncrementalCompilerHost(config.options, sys)
  512. : Object.assign(Object.assign({}, sys), { getSourceFile: (fileName, languageVersion) => {
  513. const contents = sys.readFile(fileName);
  514. if (contents === undefined)
  515. return;
  516. return ts.createSourceFile(fileName, contents, languageVersion);
  517. }, getDefaultLibLocation: () => normalizeSlashes(path_1.dirname(compiler)), getDefaultLibFileName: () => normalizeSlashes(path_1.join(path_1.dirname(compiler), ts.getDefaultLibFileName(config.options))), useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames });
  518. const { resolveModuleNames, resolveTypeReferenceDirectives, isFileKnownToBeInternal, markBucketOfFilenameInternal } = createResolverFunctions(host);
  519. host.resolveModuleNames = resolveModuleNames;
  520. host.resolveTypeReferenceDirectives = resolveTypeReferenceDirectives;
  521. // Fallback for older TypeScript releases without incremental API.
  522. let builderProgram = ts.createIncrementalProgram
  523. ? ts.createIncrementalProgram({
  524. rootNames: Array.from(rootFileNames),
  525. options: config.options,
  526. host: host,
  527. configFileParsingDiagnostics: config.errors,
  528. projectReferences: config.projectReferences
  529. })
  530. : ts.createEmitAndSemanticDiagnosticsBuilderProgram(Array.from(rootFileNames), config.options, host, undefined, config.errors, config.projectReferences);
  531. // Read and cache custom transformers.
  532. const customTransformers = typeof transformers === 'function'
  533. ? transformers(builderProgram.getProgram())
  534. : transformers;
  535. // Set the file contents into cache manually.
  536. const updateMemoryCache = (contents, fileName) => {
  537. const previousContents = fileContents.get(fileName);
  538. const contentsChanged = previousContents !== contents;
  539. if (contentsChanged) {
  540. fileContents.set(fileName, contents);
  541. }
  542. // Add to `rootFiles` when discovered by compiler for the first time.
  543. let addedToRootFileNames = false;
  544. if (!rootFileNames.has(fileName) && !isFileKnownToBeInternal(fileName)) {
  545. markBucketOfFilenameInternal(fileName);
  546. rootFileNames.add(fileName);
  547. addedToRootFileNames = true;
  548. }
  549. // Update program when file changes.
  550. if (addedToRootFileNames || contentsChanged) {
  551. builderProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram(Array.from(rootFileNames), config.options, host, builderProgram, config.errors, config.projectReferences);
  552. }
  553. };
  554. getOutput = (code, fileName) => {
  555. const output = ['', ''];
  556. updateMemoryCache(code, fileName);
  557. const sourceFile = builderProgram.getSourceFile(fileName);
  558. if (!sourceFile)
  559. throw new TypeError(`Unable to read file: ${fileName}`);
  560. const program = builderProgram.getProgram();
  561. const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile);
  562. const diagnosticList = filterDiagnostics(diagnostics, ignoreDiagnostics);
  563. if (diagnosticList.length)
  564. reportTSError(diagnosticList);
  565. const result = builderProgram.emit(sourceFile, (path, file, writeByteOrderMark) => {
  566. if (path.endsWith('.map')) {
  567. output[1] = file;
  568. }
  569. else {
  570. output[0] = file;
  571. }
  572. if (options.emit)
  573. sys.writeFile(path, file, writeByteOrderMark);
  574. }, undefined, undefined, customTransformers);
  575. if (result.emitSkipped) {
  576. throw new TypeError(`${path_1.relative(cwd, fileName)}: Emit skipped`);
  577. }
  578. // Throw an error when requiring files that cannot be compiled.
  579. if (output[0] === '') {
  580. if (program.isSourceFileFromExternalLibrary(sourceFile)) {
  581. throw new TypeError(`Unable to compile file from external library: ${path_1.relative(cwd, fileName)}`);
  582. }
  583. throw new TypeError(`Unable to require file: ${path_1.relative(cwd, fileName)}\n` +
  584. 'This is usually the result of a faulty configuration or import. ' +
  585. 'Make sure there is a `.js`, `.json` or other executable extension with ' +
  586. 'loader attached before `ts-node` available.');
  587. }
  588. return output;
  589. };
  590. getTypeInfo = (code, fileName, position) => {
  591. updateMemoryCache(code, fileName);
  592. const sourceFile = builderProgram.getSourceFile(fileName);
  593. if (!sourceFile)
  594. throw new TypeError(`Unable to read file: ${fileName}`);
  595. const node = getTokenAtPosition(ts, sourceFile, position);
  596. const checker = builderProgram.getProgram().getTypeChecker();
  597. const symbol = checker.getSymbolAtLocation(node);
  598. if (!symbol)
  599. return { name: '', comment: '' };
  600. const type = checker.getTypeOfSymbolAtLocation(symbol, node);
  601. const signatures = [...type.getConstructSignatures(), ...type.getCallSignatures()];
  602. return {
  603. name: signatures.length ? signatures.map(x => checker.signatureToString(x)).join('\n') : checker.typeToString(type),
  604. comment: ts.displayPartsToString(symbol ? symbol.getDocumentationComment(checker) : [])
  605. };
  606. };
  607. // Write `.tsbuildinfo` when `--build` is enabled.
  608. if (options.emit && config.options.incremental) {
  609. process.on('exit', () => {
  610. // Emits `.tsbuildinfo` to filesystem.
  611. builderProgram.getProgram().emitBuildInfo();
  612. });
  613. }
  614. }
  615. }
  616. else {
  617. if (typeof transformers === 'function') {
  618. throw new TypeError('Transformers function is unavailable in "--transpile-only"');
  619. }
  620. getOutput = (code, fileName) => {
  621. const result = ts.transpileModule(code, {
  622. fileName,
  623. compilerOptions: config.options,
  624. reportDiagnostics: true,
  625. transformers: transformers
  626. });
  627. const diagnosticList = filterDiagnostics(result.diagnostics || [], ignoreDiagnostics);
  628. if (diagnosticList.length)
  629. reportTSError(diagnosticList);
  630. return [result.outputText, result.sourceMapText];
  631. };
  632. getTypeInfo = () => {
  633. throw new TypeError('Type information is unavailable in "--transpile-only"');
  634. };
  635. }
  636. // Create a simple TypeScript compiler proxy.
  637. function compile(code, fileName, lineOffset = 0) {
  638. const normalizedFileName = normalizeSlashes(fileName);
  639. const [value, sourceMap] = getOutput(code, normalizedFileName);
  640. const output = updateOutput(value, normalizedFileName, sourceMap, getExtension);
  641. outputCache.set(normalizedFileName, { content: output });
  642. return output;
  643. }
  644. let active = true;
  645. const enabled = (enabled) => enabled === undefined ? active : (active = !!enabled);
  646. const extensions = getExtensions(config);
  647. const ignored = (fileName) => {
  648. if (!active)
  649. return true;
  650. const ext = path_1.extname(fileName);
  651. if (extensions.tsExtensions.includes(ext) || extensions.jsExtensions.includes(ext)) {
  652. const relname = path_1.relative(cwd, fileName);
  653. return !isScoped(relname) || shouldIgnore(relname);
  654. }
  655. return true;
  656. };
  657. return { ts, config, compile, getTypeInfo, ignored, enabled, options };
  658. }
  659. exports.create = create;
  660. /**
  661. * Check if the filename should be ignored.
  662. */
  663. function createIgnore(ignore) {
  664. return (relname) => {
  665. const path = normalizeSlashes(relname);
  666. return ignore.some(x => x.test(path));
  667. };
  668. }
  669. /**
  670. * "Refreshes" an extension on `require.extensions`.
  671. *
  672. * @param {string} ext
  673. */
  674. function reorderRequireExtension(ext) {
  675. const old = require.extensions[ext]; // tslint:disable-line
  676. delete require.extensions[ext]; // tslint:disable-line
  677. require.extensions[ext] = old; // tslint:disable-line
  678. }
  679. /**
  680. * Register the extensions to support when importing files.
  681. */
  682. function registerExtensions(preferTsExts, extensions, service, originalJsHandler) {
  683. // Register new extensions.
  684. for (const ext of extensions) {
  685. registerExtension(ext, service, originalJsHandler);
  686. }
  687. if (preferTsExts) {
  688. // tslint:disable-next-line
  689. const preferredExtensions = new Set([...extensions, ...Object.keys(require.extensions)]);
  690. for (const ext of preferredExtensions)
  691. reorderRequireExtension(ext);
  692. }
  693. }
  694. /**
  695. * Register the extension for node.
  696. */
  697. function registerExtension(ext, service, originalHandler) {
  698. const old = require.extensions[ext] || originalHandler; // tslint:disable-line
  699. require.extensions[ext] = function (m, filename) {
  700. if (service.ignored(filename))
  701. return old(m, filename);
  702. if (service.options.experimentalEsmLoader) {
  703. assertScriptCanLoadAsCJS(filename);
  704. }
  705. const _compile = m._compile;
  706. m._compile = function (code, fileName) {
  707. exports.debug('module._compile', fileName);
  708. return _compile.call(this, service.compile(code, fileName), fileName);
  709. };
  710. return old(m, filename);
  711. };
  712. }
  713. /**
  714. * Do post-processing on config options to support `ts-node`.
  715. */
  716. function fixConfig(ts, config) {
  717. // Delete options that *should not* be passed through.
  718. delete config.options.out;
  719. delete config.options.outFile;
  720. delete config.options.composite;
  721. delete config.options.declarationDir;
  722. delete config.options.declarationMap;
  723. delete config.options.emitDeclarationOnly;
  724. // Target ES5 output by default (instead of ES3).
  725. if (config.options.target === undefined) {
  726. config.options.target = ts.ScriptTarget.ES5;
  727. }
  728. // Target CommonJS modules by default (instead of magically switching to ES6 when the target is ES6).
  729. if (config.options.module === undefined) {
  730. config.options.module = ts.ModuleKind.CommonJS;
  731. }
  732. return config;
  733. }
  734. /**
  735. * Load TypeScript configuration. Returns the parsed TypeScript config and
  736. * any `ts-node` options specified in the config file.
  737. */
  738. function readConfig(cwd, ts, rawOptions) {
  739. var _a, _b;
  740. let config = { compilerOptions: {} };
  741. let basePath = cwd;
  742. let configFileName = undefined;
  743. const { fileExists = ts.sys.fileExists, readFile = ts.sys.readFile, skipProject = exports.DEFAULTS.skipProject, project = exports.DEFAULTS.project } = rawOptions;
  744. // Read project configuration when available.
  745. if (!skipProject) {
  746. configFileName = project
  747. ? path_1.resolve(cwd, project)
  748. : ts.findConfigFile(cwd, fileExists);
  749. if (configFileName) {
  750. const result = ts.readConfigFile(configFileName, readFile);
  751. // Return diagnostics.
  752. if (result.error) {
  753. return {
  754. config: { errors: [result.error], fileNames: [], options: {} },
  755. options: {}
  756. };
  757. }
  758. config = result.config;
  759. basePath = path_1.dirname(configFileName);
  760. }
  761. }
  762. // Fix ts-node options that come from tsconfig.json
  763. const tsconfigOptions = Object.assign({}, config['ts-node']);
  764. // Remove resolution of "files".
  765. const files = (_b = (_a = rawOptions.files) !== null && _a !== void 0 ? _a : tsconfigOptions.files) !== null && _b !== void 0 ? _b : exports.DEFAULTS.files;
  766. if (!files) {
  767. config.files = [];
  768. config.include = [];
  769. }
  770. // Override default configuration options `ts-node` requires.
  771. config.compilerOptions = Object.assign({}, config.compilerOptions, exports.DEFAULTS.compilerOptions, tsconfigOptions.compilerOptions, rawOptions.compilerOptions, TS_NODE_COMPILER_OPTIONS);
  772. const fixedConfig = fixConfig(ts, ts.parseJsonConfigFileContent(config, {
  773. fileExists,
  774. readFile,
  775. readDirectory: ts.sys.readDirectory,
  776. useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames
  777. }, basePath, undefined, configFileName));
  778. if (tsconfigOptions.require) {
  779. // Modules are found relative to the tsconfig file, not the `dir` option
  780. const tsconfigRelativeRequire = createRequire(configFileName);
  781. tsconfigOptions.require = tsconfigOptions.require.map((path) => {
  782. return tsconfigRelativeRequire.resolve(path);
  783. });
  784. }
  785. return { config: fixedConfig, options: tsconfigOptions };
  786. }
  787. /**
  788. * Update the output remapping the source map.
  789. */
  790. function updateOutput(outputText, fileName, sourceMap, getExtension) {
  791. const base64Map = Buffer.from(updateSourceMap(sourceMap, fileName), 'utf8').toString('base64');
  792. const sourceMapContent = `data:application/json;charset=utf-8;base64,${base64Map}`;
  793. const sourceMapLength = `${path_1.basename(fileName)}.map`.length + (getExtension(fileName).length - path_1.extname(fileName).length);
  794. return outputText.slice(0, -sourceMapLength) + sourceMapContent;
  795. }
  796. /**
  797. * Update the source map contents for improved output.
  798. */
  799. function updateSourceMap(sourceMapText, fileName) {
  800. const sourceMap = JSON.parse(sourceMapText);
  801. sourceMap.file = fileName;
  802. sourceMap.sources = [fileName];
  803. delete sourceMap.sourceRoot;
  804. return JSON.stringify(sourceMap);
  805. }
  806. /**
  807. * Filter diagnostics.
  808. */
  809. function filterDiagnostics(diagnostics, ignore) {
  810. return diagnostics.filter(x => ignore.indexOf(x.code) === -1);
  811. }
  812. /**
  813. * Get token at file position.
  814. *
  815. * Reference: https://github.com/microsoft/TypeScript/blob/fcd9334f57d85b73dd66ad2d21c02e84822f4841/src/services/utilities.ts#L705-L731
  816. */
  817. function getTokenAtPosition(ts, sourceFile, position) {
  818. let current = sourceFile;
  819. outer: while (true) {
  820. for (const child of current.getChildren(sourceFile)) {
  821. const start = child.getFullStart();
  822. if (start > position)
  823. break;
  824. const end = child.getEnd();
  825. if (position <= end) {
  826. current = child;
  827. continue outer;
  828. }
  829. }
  830. return current;
  831. }
  832. }
  833. //# sourceMappingURL=index.js.map