UNPKG

6.62 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright Google LLC All Rights Reserved.
5 *
6 * Use of this source code is governed by an MIT-style license that can be
7 * found in the LICENSE file at https://angular.io/license
8 */
9var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10 if (k2 === undefined) k2 = k;
11 Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
12}) : (function(o, m, k, k2) {
13 if (k2 === undefined) k2 = k;
14 o[k2] = m[k];
15}));
16var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17 Object.defineProperty(o, "default", { enumerable: true, value: v });
18}) : function(o, v) {
19 o["default"] = v;
20});
21var __importStar = (this && this.__importStar) || function (mod) {
22 if (mod && mod.__esModule) return mod;
23 var result = {};
24 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
25 __setModuleDefault(result, mod);
26 return result;
27};
28Object.defineProperty(exports, "__esModule", { value: true });
29exports.transformJavascript = void 0;
30const ts = __importStar(require("typescript"));
31function validateDiagnostics(diagnostics, strict) {
32 // Print error diagnostics.
33 const hasError = diagnostics.some((diag) => diag.category === ts.DiagnosticCategory.Error);
34 if (hasError) {
35 // Throw only if we're in strict mode, otherwise return original content.
36 if (strict) {
37 const errorMessages = ts.formatDiagnostics(diagnostics, {
38 getCurrentDirectory: () => ts.sys.getCurrentDirectory(),
39 getNewLine: () => ts.sys.newLine,
40 getCanonicalFileName: (f) => f,
41 });
42 throw new Error(`
43 TS failed with the following error messages:
44
45 ${errorMessages}
46 `);
47 }
48 else {
49 return false;
50 }
51 }
52 return true;
53}
54function transformJavascript(options) {
55 const { content, getTransforms, emitSourceMap, inputFilePath, outputFilePath, strict } = options;
56 // Bail if there's no transform to do.
57 if (getTransforms.length === 0) {
58 return {
59 content: null,
60 sourceMap: null,
61 emitSkipped: true,
62 };
63 }
64 const allowFastPath = options.typeCheck === false && !emitSourceMap;
65 const outputs = new Map();
66 const tempFilename = 'bo-default-file.js';
67 const tempSourceFile = ts.createSourceFile(tempFilename, content, ts.ScriptTarget.Latest, allowFastPath);
68 const parseDiagnostics = tempSourceFile.parseDiagnostics;
69 const tsOptions = {
70 // We target latest so that there is no downleveling.
71 target: ts.ScriptTarget.Latest,
72 isolatedModules: true,
73 suppressOutputPathCheck: true,
74 allowNonTsExtensions: true,
75 noLib: true,
76 noResolve: true,
77 sourceMap: emitSourceMap,
78 inlineSources: emitSourceMap,
79 inlineSourceMap: false,
80 };
81 if (allowFastPath && parseDiagnostics) {
82 if (!validateDiagnostics(parseDiagnostics, strict)) {
83 return {
84 content: null,
85 sourceMap: null,
86 emitSkipped: true,
87 };
88 }
89 // All fast path transformers do not use a program
90 const transforms = getTransforms.map((getTf) => getTf(/* program */ undefined));
91 const result = ts.transform(tempSourceFile, transforms, tsOptions);
92 if (result.transformed.length === 0 || result.transformed[0] === tempSourceFile) {
93 return {
94 content: null,
95 sourceMap: null,
96 emitSkipped: true,
97 };
98 }
99 const printer = ts.createPrinter(undefined, {
100 onEmitNode: result.emitNodeWithNotification,
101 substituteNode: result.substituteNode,
102 });
103 const output = printer.printFile(result.transformed[0]);
104 result.dispose();
105 return {
106 content: output,
107 sourceMap: null,
108 emitSkipped: false,
109 };
110 }
111 const host = {
112 getSourceFile: (fileName) => {
113 if (fileName !== tempFilename) {
114 throw new Error(`File ${fileName} does not have a sourceFile.`);
115 }
116 return tempSourceFile;
117 },
118 getDefaultLibFileName: () => 'lib.d.ts',
119 getCurrentDirectory: () => '',
120 getDirectories: () => [],
121 getCanonicalFileName: (fileName) => fileName,
122 useCaseSensitiveFileNames: () => true,
123 getNewLine: () => '\n',
124 fileExists: (fileName) => fileName === tempFilename,
125 readFile: (_fileName) => '',
126 writeFile: (fileName, text) => outputs.set(fileName, text),
127 };
128 const program = ts.createProgram([tempFilename], tsOptions, host);
129 const diagnostics = program.getSyntacticDiagnostics(tempSourceFile);
130 if (!validateDiagnostics(diagnostics, strict)) {
131 return {
132 content: null,
133 sourceMap: null,
134 emitSkipped: true,
135 };
136 }
137 // We need the checker inside transforms.
138 const transforms = getTransforms.map((getTf) => getTf(program));
139 program.emit(undefined, undefined, undefined, undefined, { before: transforms, after: [] });
140 let transformedContent = outputs.get(tempFilename);
141 if (!transformedContent) {
142 return {
143 content: null,
144 sourceMap: null,
145 emitSkipped: true,
146 };
147 }
148 let sourceMap = null;
149 const tsSourceMap = outputs.get(`${tempFilename}.map`);
150 if (emitSourceMap && tsSourceMap) {
151 const urlRegExp = /^\/\/# sourceMappingURL=[^\r\n]*/gm;
152 sourceMap = JSON.parse(tsSourceMap);
153 // Fix sourcemaps file references.
154 if (outputFilePath) {
155 sourceMap.file = outputFilePath;
156 transformedContent = transformedContent.replace(urlRegExp, `//# sourceMappingURL=${sourceMap.file}.map\n`);
157 if (inputFilePath) {
158 sourceMap.sources = [inputFilePath];
159 }
160 else {
161 sourceMap.sources = [''];
162 }
163 }
164 else {
165 // TODO: figure out if we should inline sources here.
166 transformedContent = transformedContent.replace(urlRegExp, '');
167 sourceMap.file = '';
168 sourceMap.sources = [''];
169 }
170 }
171 return {
172 content: transformedContent,
173 sourceMap,
174 emitSkipped: false,
175 };
176}
177exports.transformJavascript = transformJavascript;