1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | exports.register = void 0;
|
7 | const path_1 = require("path");
|
8 | const build_utils_1 = __importDefault(require("./build-utils"));
|
9 | const { NowBuildError } = build_utils_1.default;
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | const shouldDebug = false;
|
19 | const debug = shouldDebug
|
20 | ? console.log.bind(console, 'ts-node')
|
21 | : () => undefined;
|
22 | const debugFn = shouldDebug
|
23 | ? (key, fn) => {
|
24 | let i = 0;
|
25 | return (x) => {
|
26 | debug(key, x, ++i);
|
27 | return fn(x);
|
28 | };
|
29 | }
|
30 | : (_, fn) => fn;
|
31 |
|
32 |
|
33 |
|
34 | class MemoryCache {
|
35 | constructor(rootFileNames = []) {
|
36 | this.fileContents = new Map();
|
37 | this.fileVersions = new Map();
|
38 | for (const fileName of rootFileNames)
|
39 | this.fileVersions.set(fileName, 1);
|
40 | }
|
41 | }
|
42 |
|
43 |
|
44 |
|
45 | const DEFAULTS = {
|
46 | files: null,
|
47 | pretty: null,
|
48 | compiler: undefined,
|
49 | compilerOptions: undefined,
|
50 | ignore: undefined,
|
51 | project: undefined,
|
52 | ignoreDiagnostics: undefined,
|
53 | logError: null,
|
54 | };
|
55 |
|
56 |
|
57 |
|
58 | const TS_NODE_COMPILER_OPTIONS = {
|
59 | sourceMap: true,
|
60 | inlineSourceMap: false,
|
61 | inlineSources: true,
|
62 | declaration: false,
|
63 | noEmit: false,
|
64 | outDir: '$$ts-node$$',
|
65 | };
|
66 |
|
67 |
|
68 |
|
69 | function normalizeSlashes(value) {
|
70 | return value.replace(/\\/g, '/');
|
71 | }
|
72 |
|
73 |
|
74 |
|
75 | function cachedLookup(fn) {
|
76 | const cache = new Map();
|
77 | return (arg) => {
|
78 | if (!cache.has(arg)) {
|
79 | cache.set(arg, fn(arg));
|
80 | }
|
81 | return cache.get(arg);
|
82 | };
|
83 | }
|
84 |
|
85 |
|
86 |
|
87 | function register(opts = {}) {
|
88 | const options = Object.assign({}, DEFAULTS, opts);
|
89 | const ignoreDiagnostics = [
|
90 | 6059,
|
91 | 18002,
|
92 | 18003,
|
93 | ...(options.ignoreDiagnostics || []),
|
94 | ].map(Number);
|
95 |
|
96 | const cwd = options.basePath || process.cwd();
|
97 | const nowNodeBase = path_1.resolve(__dirname, '..', '..', '..');
|
98 | let compiler;
|
99 | try {
|
100 | compiler = require.resolve(options.compiler || 'typescript', {
|
101 | paths: [options.project || cwd, nowNodeBase],
|
102 | });
|
103 | }
|
104 | catch (e) {
|
105 | compiler = require.resolve(eval('"typescript"'));
|
106 | }
|
107 |
|
108 | const ts = require(compiler);
|
109 | if (compiler.startsWith(nowNodeBase)) {
|
110 | console.log('Using TypeScript ' + ts.version + ' (no local tsconfig.json)');
|
111 | }
|
112 | else {
|
113 | console.log('Using TypeScript ' + ts.version + ' (local user-provided)');
|
114 | }
|
115 | const transformers = options.transformers || undefined;
|
116 | const readFile = options.readFile || ts.sys.readFile;
|
117 | const fileExists = options.fileExists || ts.sys.fileExists;
|
118 | const formatDiagnostics = process.stdout.isTTY || options.pretty
|
119 | ? ts.formatDiagnosticsWithColorAndContext
|
120 | : ts.formatDiagnostics;
|
121 | const diagnosticHost = {
|
122 | getNewLine: () => ts.sys.newLine,
|
123 | getCurrentDirectory: () => cwd,
|
124 | getCanonicalFileName: path => path,
|
125 | };
|
126 | function createTSError(diagnostics) {
|
127 | const message = formatDiagnostics(diagnostics, diagnosticHost);
|
128 | return new NowBuildError({ code: 'NODE_TYPESCRIPT_ERROR', message });
|
129 | }
|
130 | function reportTSError(diagnostics, shouldExit) {
|
131 | if (!diagnostics || diagnostics.length === 0) {
|
132 | return;
|
133 | }
|
134 | const error = createTSError(diagnostics);
|
135 | if (shouldExit) {
|
136 | throw error;
|
137 | }
|
138 | else {
|
139 |
|
140 | console.error('\x1b[31m%s\x1b[0m', error);
|
141 | }
|
142 | }
|
143 |
|
144 | const builds = new Map();
|
145 | function getBuild(configFileName = '') {
|
146 | let build = builds.get(configFileName);
|
147 | if (build)
|
148 | return build;
|
149 | const config = readConfig(configFileName);
|
150 | |
151 |
|
152 |
|
153 | const getOutput = function (code, fileName) {
|
154 | const result = ts.transpileModule(code, {
|
155 | fileName,
|
156 | transformers,
|
157 | compilerOptions: config.options,
|
158 | reportDiagnostics: true,
|
159 | });
|
160 | const diagnosticList = result.diagnostics
|
161 | ? filterDiagnostics(result.diagnostics, ignoreDiagnostics)
|
162 | : [];
|
163 | reportTSError(diagnosticList, config.options.noEmitOnError);
|
164 | return { code: result.outputText, map: result.sourceMapText };
|
165 | };
|
166 |
|
167 | let getOutputTypeCheck;
|
168 | {
|
169 | const memoryCache = new MemoryCache(config.fileNames);
|
170 | const cachedReadFile = cachedLookup(debugFn('readFile', readFile));
|
171 |
|
172 | const serviceHost = {
|
173 | getScriptFileNames: () => Array.from(memoryCache.fileVersions.keys()),
|
174 | getScriptVersion: (fileName) => {
|
175 | const version = memoryCache.fileVersions.get(fileName);
|
176 | return version === undefined ? '' : version.toString();
|
177 | },
|
178 | getScriptSnapshot(fileName) {
|
179 | let contents = memoryCache.fileContents.get(fileName);
|
180 |
|
181 | if (contents === undefined) {
|
182 | contents = cachedReadFile(fileName);
|
183 | if (contents === undefined)
|
184 | return;
|
185 | memoryCache.fileVersions.set(fileName, 1);
|
186 | memoryCache.fileContents.set(fileName, contents);
|
187 | }
|
188 | return ts.ScriptSnapshot.fromString(contents);
|
189 | },
|
190 | readFile: cachedReadFile,
|
191 | readDirectory: cachedLookup(debugFn('readDirectory', ts.sys.readDirectory)),
|
192 | getDirectories: cachedLookup(debugFn('getDirectories', ts.sys.getDirectories)),
|
193 | fileExists: cachedLookup(debugFn('fileExists', fileExists)),
|
194 | directoryExists: cachedLookup(debugFn('directoryExists', ts.sys.directoryExists)),
|
195 | getNewLine: () => ts.sys.newLine,
|
196 | useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames,
|
197 | getCurrentDirectory: () => cwd,
|
198 | getCompilationSettings: () => config.options,
|
199 | getDefaultLibFileName: () => ts.getDefaultLibFilePath(config.options),
|
200 | getCustomTransformers: () => transformers,
|
201 | };
|
202 | const registry = ts.createDocumentRegistry(ts.sys.useCaseSensitiveFileNames, cwd);
|
203 | const service = ts.createLanguageService(serviceHost, registry);
|
204 |
|
205 | const updateMemoryCache = function (contents, fileName) {
|
206 | const fileVersion = memoryCache.fileVersions.get(fileName) || 0;
|
207 |
|
208 | if (memoryCache.fileContents.get(fileName) === contents)
|
209 | return;
|
210 | memoryCache.fileVersions.set(fileName, fileVersion + 1);
|
211 | memoryCache.fileContents.set(fileName, contents);
|
212 | };
|
213 | getOutputTypeCheck = function (code, fileName) {
|
214 | updateMemoryCache(code, fileName);
|
215 | const output = service.getEmitOutput(fileName);
|
216 |
|
217 | const diagnostics = service
|
218 | .getSemanticDiagnostics(fileName)
|
219 | .concat(service.getSyntacticDiagnostics(fileName));
|
220 | const diagnosticList = filterDiagnostics(diagnostics, ignoreDiagnostics);
|
221 | reportTSError(diagnosticList, config.options.noEmitOnError);
|
222 | if (output.emitSkipped) {
|
223 | throw new TypeError(`${path_1.relative(cwd, fileName)}: Emit skipped`);
|
224 | }
|
225 |
|
226 | if (output.outputFiles.length === 0) {
|
227 | throw new TypeError('Unable to require `.d.ts` file.\n' +
|
228 | 'This is usually the result of a faulty configuration or import. ' +
|
229 | 'Make sure there is a `.js`, `.json` or another executable extension and ' +
|
230 | 'loader (attached before `ts-node`) available alongside ' +
|
231 | `\`${path_1.basename(fileName)}\`.`);
|
232 | }
|
233 | return {
|
234 | code: output.outputFiles[1].text,
|
235 | map: output.outputFiles[0].text,
|
236 | };
|
237 | };
|
238 | }
|
239 | builds.set(configFileName, (build = {
|
240 | getOutput,
|
241 | getOutputTypeCheck,
|
242 | }));
|
243 | return build;
|
244 | }
|
245 |
|
246 | function detectConfig() {
|
247 | let configFileName = undefined;
|
248 |
|
249 | configFileName = options.project
|
250 | ? ts.findConfigFile(normalizeSlashes(options.project), fileExists)
|
251 | : ts.findConfigFile(normalizeSlashes(cwd), fileExists);
|
252 | if (configFileName)
|
253 | return normalizeSlashes(configFileName);
|
254 | }
|
255 | |
256 |
|
257 |
|
258 | function readConfig(configFileName) {
|
259 | let config = { compilerOptions: {} };
|
260 | const basePath = normalizeSlashes(path_1.dirname(configFileName));
|
261 |
|
262 | if (configFileName) {
|
263 | const result = ts.readConfigFile(configFileName, readFile);
|
264 |
|
265 | if (result.error) {
|
266 | const errorResult = {
|
267 | errors: [result.error],
|
268 | fileNames: [],
|
269 | options: {},
|
270 | };
|
271 | const configDiagnosticList = filterDiagnostics(errorResult.errors, ignoreDiagnostics);
|
272 |
|
273 | reportTSError(configDiagnosticList, true);
|
274 | return errorResult;
|
275 | }
|
276 | config = result.config;
|
277 | }
|
278 |
|
279 | if (!options.files) {
|
280 | config.files = [];
|
281 | config.include = [];
|
282 | }
|
283 |
|
284 | config.compilerOptions = Object.assign({}, config.compilerOptions, options.compilerOptions, TS_NODE_COMPILER_OPTIONS);
|
285 | const configResult = fixConfig(ts, ts.parseJsonConfigFileContent(config, ts.sys, basePath, undefined, configFileName));
|
286 | if (configFileName) {
|
287 | const configDiagnosticList = filterDiagnostics(configResult.errors, ignoreDiagnostics);
|
288 |
|
289 | reportTSError(configDiagnosticList, configResult.options.noEmitOnError);
|
290 | }
|
291 | return configResult;
|
292 | }
|
293 |
|
294 | function compile(code, fileName, skipTypeCheck) {
|
295 | const configFileName = detectConfig();
|
296 | const build = getBuild(configFileName);
|
297 | const { code: value, map: sourceMap } = (skipTypeCheck
|
298 | ? build.getOutput
|
299 | : build.getOutputTypeCheck)(code, fileName);
|
300 | const output = {
|
301 | code: value,
|
302 | map: Object.assign(JSON.parse(sourceMap), {
|
303 | file: path_1.basename(fileName),
|
304 | sources: [fileName],
|
305 | }),
|
306 | };
|
307 | delete output.map.sourceRoot;
|
308 | return output;
|
309 | }
|
310 | return compile;
|
311 | }
|
312 | exports.register = register;
|
313 |
|
314 |
|
315 |
|
316 | function fixConfig(ts, config) {
|
317 |
|
318 | delete config.options.out;
|
319 | delete config.options.outFile;
|
320 | delete config.options.composite;
|
321 | delete config.options.declarationDir;
|
322 | delete config.options.declarationMap;
|
323 | delete config.options.emitDeclarationOnly;
|
324 | delete config.options.tsBuildInfoFile;
|
325 | delete config.options.incremental;
|
326 |
|
327 |
|
328 | if (config.options.target === undefined) {
|
329 | config.options.target = ts.ScriptTarget.ESNext;
|
330 | }
|
331 |
|
332 |
|
333 | if (config.options.esModuleInterop === undefined) {
|
334 | config.options.esModuleInterop = true;
|
335 | }
|
336 |
|
337 | config.options.module = ts.ModuleKind.CommonJS;
|
338 | return config;
|
339 | }
|
340 |
|
341 |
|
342 |
|
343 | function filterDiagnostics(diagnostics, ignore) {
|
344 | return diagnostics.filter(x => ignore.indexOf(x.code) === -1);
|
345 | }
|