source: trip-planner-front/node_modules/@angular-devkit/build-angular/src/utils/process-bundle.js@ 188ee53

Last change on this file since 188ee53 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 24.7 KB
Line 
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};
28var __importDefault = (this && this.__importDefault) || function (mod) {
29 return (mod && mod.__esModule) ? mod : { "default": mod };
30};
31Object.defineProperty(exports, "__esModule", { value: true });
32exports.inlineLocales = exports.createI18nPlugins = exports.process = void 0;
33const remapping_1 = __importDefault(require("@ampproject/remapping"));
34const core_1 = require("@babel/core");
35const template_1 = __importDefault(require("@babel/template"));
36const cacache = __importStar(require("cacache"));
37const crypto_1 = require("crypto");
38const fs = __importStar(require("fs"));
39const path = __importStar(require("path"));
40const terser_1 = require("terser");
41const worker_threads_1 = require("worker_threads");
42const environment_options_1 = require("./environment-options");
43// Lazy loaded webpack-sources object
44// Webpack is only imported if needed during the processing
45let webpackSources;
46// If code size is larger than 500KB, consider lower fidelity but faster sourcemap merge
47const FAST_SOURCEMAP_THRESHOLD = 500 * 1024;
48const { cachePath, i18n } = (worker_threads_1.workerData || {});
49async function cachePut(content, key, integrity) {
50 if (cachePath && key) {
51 await cacache.put(cachePath, key, content, {
52 metadata: { integrity },
53 });
54 }
55}
56async function process(options) {
57 var _a;
58 if (!options.cacheKeys) {
59 options.cacheKeys = [];
60 }
61 const result = { name: options.name };
62 if (options.integrityAlgorithm) {
63 // Store unmodified code integrity value -- used for SRI value replacement
64 result.integrity = generateIntegrityValue(options.integrityAlgorithm, options.code);
65 }
66 // Runtime chunk requires specialized handling
67 if (options.runtime) {
68 return { ...result, ...(await processRuntime(options)) };
69 }
70 const basePath = path.dirname(options.filename);
71 const filename = path.basename(options.filename);
72 const downlevelFilename = filename.replace(/\-(es20\d{2}|esnext)/, '-es5');
73 const downlevel = !options.optimizeOnly;
74 const sourceCode = options.code;
75 if (downlevel) {
76 const { supportedBrowsers: targets = [] } = options;
77 // todo: revisit this in version 10, when we update our defaults browserslist
78 // Without this workaround bundles will not be downlevelled because Babel doesn't know handle to 'op_mini all'
79 // See: https://github.com/babel/babel/issues/11155
80 if (Array.isArray(targets) && targets.includes('op_mini all')) {
81 targets.push('ie_mob 11');
82 }
83 else if ('op_mini' in targets) {
84 targets['ie_mob'] = '11';
85 }
86 // Downlevel the bundle
87 const transformResult = await core_1.transformAsync(sourceCode, {
88 filename,
89 // using false ensures that babel will NOT search and process sourcemap comments (large memory usage)
90 // The types do not include the false option even though it is valid
91 // eslint-disable-next-line @typescript-eslint/no-explicit-any
92 inputSourceMap: false,
93 babelrc: false,
94 configFile: false,
95 presets: [
96 [
97 require.resolve('@babel/preset-env'),
98 {
99 // browserslist-compatible query or object of minimum environment versions to support
100 targets,
101 // modules aren't needed since the bundles use webpack's custom module loading
102 modules: false,
103 // 'transform-typeof-symbol' generates slower code
104 exclude: ['transform-typeof-symbol'],
105 },
106 ],
107 ],
108 plugins: [
109 createIifeWrapperPlugin(),
110 ...(options.replacements ? [createReplacePlugin(options.replacements)] : []),
111 ],
112 minified: environment_options_1.allowMinify && !!options.optimize,
113 compact: !environment_options_1.shouldBeautify && !!options.optimize,
114 sourceMaps: !!options.map,
115 });
116 if (!transformResult || !transformResult.code) {
117 throw new Error(`Unknown error occurred processing bundle for "${options.filename}".`);
118 }
119 result.downlevel = await processBundle({
120 ...options,
121 code: transformResult.code,
122 downlevelMap: (_a = transformResult.map) !== null && _a !== void 0 ? _a : undefined,
123 filename: path.join(basePath, downlevelFilename),
124 isOriginal: false,
125 });
126 }
127 if (!result.original && !options.ignoreOriginal) {
128 result.original = await processBundle({
129 ...options,
130 isOriginal: true,
131 });
132 }
133 return result;
134}
135exports.process = process;
136async function processBundle(options) {
137 const { optimize, isOriginal, code, map, downlevelMap, filename: filepath, hiddenSourceMaps, cacheKeys = [], integrityAlgorithm, } = options;
138 const filename = path.basename(filepath);
139 let resultCode = code;
140 let optimizeResult;
141 if (optimize) {
142 optimizeResult = await terserMangle(code, {
143 filename,
144 sourcemap: !!map,
145 compress: !isOriginal,
146 ecma: isOriginal ? 2015 : 5,
147 });
148 resultCode = optimizeResult.code;
149 }
150 let mapContent;
151 if (map) {
152 if (!hiddenSourceMaps) {
153 resultCode += `\n//# sourceMappingURL=${filename}.map`;
154 }
155 const partialSourcemaps = [];
156 if (optimizeResult && optimizeResult.map) {
157 partialSourcemaps.push(optimizeResult.map);
158 }
159 if (downlevelMap) {
160 partialSourcemaps.push(downlevelMap);
161 }
162 if (partialSourcemaps.length > 0) {
163 partialSourcemaps.push(map);
164 const fullSourcemap = remapping_1.default(partialSourcemaps, () => null);
165 mapContent = JSON.stringify(fullSourcemap);
166 }
167 else {
168 mapContent = map;
169 }
170 await cachePut(mapContent, cacheKeys[isOriginal ? 1 /* OriginalMap */ : 3 /* DownlevelMap */]);
171 fs.writeFileSync(filepath + '.map', mapContent);
172 }
173 const fileResult = createFileEntry(filepath, resultCode, mapContent, integrityAlgorithm);
174 await cachePut(resultCode, cacheKeys[isOriginal ? 0 /* OriginalCode */ : 2 /* DownlevelCode */], fileResult.integrity);
175 fs.writeFileSync(filepath, resultCode);
176 return fileResult;
177}
178async function terserMangle(code, options = {}) {
179 // Note: Investigate converting the AST instead of re-parsing
180 // estree -> terser is already supported; need babel -> estree/terser
181 // Mangle downlevel code
182 const minifyOutput = await terser_1.minify(options.filename ? { [options.filename]: code } : code, {
183 compress: environment_options_1.allowMinify && !!options.compress,
184 ecma: options.ecma || 5,
185 mangle: environment_options_1.allowMangle,
186 safari10: true,
187 format: {
188 ascii_only: true,
189 webkit: true,
190 beautify: environment_options_1.shouldBeautify,
191 wrap_func_args: false,
192 },
193 sourceMap: !!options.sourcemap &&
194 {
195 asObject: true,
196 // typings don't include asObject option
197 // eslint-disable-next-line @typescript-eslint/no-explicit-any
198 },
199 });
200 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
201 return { code: minifyOutput.code, map: minifyOutput.map };
202}
203function createFileEntry(filename, code, map, integrityAlgorithm) {
204 return {
205 filename: filename,
206 size: Buffer.byteLength(code),
207 integrity: integrityAlgorithm && generateIntegrityValue(integrityAlgorithm, code),
208 map: !map
209 ? undefined
210 : {
211 filename: filename + '.map',
212 size: Buffer.byteLength(map),
213 },
214 };
215}
216function generateIntegrityValue(hashAlgorithm, code) {
217 return hashAlgorithm + '-' + crypto_1.createHash(hashAlgorithm).update(code).digest('base64');
218}
219// The webpack runtime chunk is already ES5.
220// However, two variants are still needed due to lazy routing and SRI differences
221// NOTE: This should eventually be a babel plugin
222async function processRuntime(options) {
223 let originalCode = options.code;
224 let downlevelCode = options.code;
225 // Replace integrity hashes with updated values
226 if (options.integrityAlgorithm && options.runtimeData) {
227 for (const data of options.runtimeData) {
228 if (!data.integrity) {
229 continue;
230 }
231 if (data.original && data.original.integrity) {
232 originalCode = originalCode.replace(data.integrity, data.original.integrity);
233 }
234 if (data.downlevel && data.downlevel.integrity) {
235 downlevelCode = downlevelCode.replace(data.integrity, data.downlevel.integrity);
236 }
237 }
238 }
239 // Adjust lazy loaded scripts to point to the proper variant
240 // Extra spacing is intentional to align source line positions
241 downlevelCode = downlevelCode.replace(/"\-(es20\d{2}|esnext)\./, ' "-es5.');
242 return {
243 original: await processBundle({
244 ...options,
245 code: originalCode,
246 isOriginal: true,
247 }),
248 downlevel: await processBundle({
249 ...options,
250 code: downlevelCode,
251 filename: options.filename.replace(/\-(es20\d{2}|esnext)/, '-es5'),
252 isOriginal: false,
253 }),
254 };
255}
256function createReplacePlugin(replacements) {
257 return {
258 visitor: {
259 StringLiteral(path) {
260 for (const replacement of replacements) {
261 if (path.node.value === replacement[0]) {
262 path.node.value = replacement[1];
263 }
264 }
265 },
266 },
267 };
268}
269function createIifeWrapperPlugin() {
270 return {
271 visitor: {
272 Program: {
273 exit(path) {
274 // Save existing body and directives
275 const { body, directives } = path.node;
276 // Clear out body and directives for wrapper
277 path.node.body = [];
278 path.node.directives = [];
279 // Create the wrapper - "(function() { ... })();"
280 const wrapper = core_1.types.expressionStatement(core_1.types.callExpression(core_1.types.parenthesizedExpression(core_1.types.functionExpression(undefined, [], core_1.types.blockStatement(body, directives))), []));
281 // Insert the wrapper
282 path.pushContainer('body', wrapper);
283 },
284 },
285 },
286 };
287}
288const USE_LOCALIZE_PLUGINS = false;
289async function createI18nPlugins(locale, translation, missingTranslation, shouldInline, localeDataContent) {
290 const plugins = [];
291 const localizeDiag = await Promise.resolve().then(() => __importStar(require('@angular/localize/src/tools/src/diagnostics')));
292 const diagnostics = new localizeDiag.Diagnostics();
293 if (shouldInline) {
294 const es2015 = await Promise.resolve().then(() => __importStar(require('@angular/localize/src/tools/src/translate/source_files/es2015_translate_plugin')));
295 plugins.push(
296 // eslint-disable-next-line @typescript-eslint/no-explicit-any
297 es2015.makeEs2015TranslatePlugin(diagnostics, (translation || {}), {
298 missingTranslation: translation === undefined ? 'ignore' : missingTranslation,
299 }));
300 const es5 = await Promise.resolve().then(() => __importStar(require('@angular/localize/src/tools/src/translate/source_files/es5_translate_plugin')));
301 plugins.push(
302 // eslint-disable-next-line @typescript-eslint/no-explicit-any
303 es5.makeEs5TranslatePlugin(diagnostics, (translation || {}), {
304 missingTranslation: translation === undefined ? 'ignore' : missingTranslation,
305 }));
306 }
307 const inlineLocale = await Promise.resolve().then(() => __importStar(require('@angular/localize/src/tools/src/translate/source_files/locale_plugin')));
308 plugins.push(inlineLocale.makeLocalePlugin(locale));
309 if (localeDataContent) {
310 plugins.push({
311 visitor: {
312 Program(path) {
313 path.unshiftContainer('body', template_1.default.ast(localeDataContent));
314 },
315 },
316 });
317 }
318 return { diagnostics, plugins };
319}
320exports.createI18nPlugins = createI18nPlugins;
321const localizeName = '$localize';
322async function inlineLocales(options) {
323 var _a;
324 if (!i18n || i18n.inlineLocales.size === 0) {
325 return { file: options.filename, diagnostics: [], count: 0 };
326 }
327 if (i18n.flatOutput && i18n.inlineLocales.size > 1) {
328 throw new Error('Flat output is only supported when inlining one locale.');
329 }
330 const hasLocalizeName = options.code.includes(localizeName);
331 if (!hasLocalizeName && !options.setLocale) {
332 return inlineCopyOnly(options);
333 }
334 let ast;
335 try {
336 ast = core_1.parseSync(options.code, {
337 babelrc: false,
338 configFile: false,
339 sourceType: 'script',
340 filename: options.filename,
341 });
342 }
343 catch (error) {
344 if (error.message) {
345 // Make the error more readable.
346 // Same errors will contain the full content of the file as the error message
347 // Which makes it hard to find the actual error message.
348 const index = error.message.indexOf(')\n');
349 const msg = index !== -1 ? error.message.substr(0, index + 1) : error.message;
350 throw new Error(`${msg}\nAn error occurred inlining file "${options.filename}"`);
351 }
352 }
353 if (!ast) {
354 throw new Error(`Unknown error occurred inlining file "${options.filename}"`);
355 }
356 if (!USE_LOCALIZE_PLUGINS) {
357 return inlineLocalesDirect(ast, options);
358 }
359 const diagnostics = [];
360 for (const locale of i18n.inlineLocales) {
361 const isSourceLocale = locale === i18n.sourceLocale;
362 // eslint-disable-next-line @typescript-eslint/no-explicit-any
363 const translations = isSourceLocale ? {} : i18n.locales[locale].translation || {};
364 let localeDataContent;
365 if (options.setLocale) {
366 // If locale data is provided, load it and prepend to file
367 const localeDataPath = (_a = i18n.locales[locale]) === null || _a === void 0 ? void 0 : _a.dataPath;
368 if (localeDataPath) {
369 localeDataContent = await loadLocaleData(localeDataPath, true, options.es5);
370 }
371 }
372 const { diagnostics: localeDiagnostics, plugins } = await createI18nPlugins(locale, translations, isSourceLocale ? 'ignore' : options.missingTranslation || 'warning', true, localeDataContent);
373 const transformResult = await core_1.transformFromAstSync(ast, options.code, {
374 filename: options.filename,
375 // using false ensures that babel will NOT search and process sourcemap comments (large memory usage)
376 // The types do not include the false option even though it is valid
377 // eslint-disable-next-line @typescript-eslint/no-explicit-any
378 inputSourceMap: false,
379 babelrc: false,
380 configFile: false,
381 plugins,
382 compact: !environment_options_1.shouldBeautify,
383 sourceMaps: !!options.map,
384 });
385 diagnostics.push(...localeDiagnostics.messages);
386 if (!transformResult || !transformResult.code) {
387 throw new Error(`Unknown error occurred processing bundle for "${options.filename}".`);
388 }
389 const outputPath = path.join(options.outputPath, i18n.flatOutput ? '' : locale, options.filename);
390 fs.writeFileSync(outputPath, transformResult.code);
391 if (options.map && transformResult.map) {
392 const outputMap = remapping_1.default([transformResult.map, options.map], () => null);
393 fs.writeFileSync(outputPath + '.map', JSON.stringify(outputMap));
394 }
395 }
396 return { file: options.filename, diagnostics };
397}
398exports.inlineLocales = inlineLocales;
399async function inlineLocalesDirect(ast, options) {
400 if (!i18n || i18n.inlineLocales.size === 0) {
401 return { file: options.filename, diagnostics: [], count: 0 };
402 }
403 const { default: generate } = await Promise.resolve().then(() => __importStar(require('@babel/generator')));
404 const utils = await Promise.resolve().then(() => __importStar(require('@angular/localize/src/tools/src/source_file_utils')));
405 const localizeDiag = await Promise.resolve().then(() => __importStar(require('@angular/localize/src/tools/src/diagnostics')));
406 const diagnostics = new localizeDiag.Diagnostics();
407 const positions = findLocalizePositions(ast, options, utils);
408 if (positions.length === 0 && !options.setLocale) {
409 return inlineCopyOnly(options);
410 }
411 const inputMap = !!options.map && JSON.parse(options.map);
412 // Cleanup source root otherwise it will be added to each source entry
413 const mapSourceRoot = inputMap && inputMap.sourceRoot;
414 if (inputMap) {
415 delete inputMap.sourceRoot;
416 }
417 // Load Webpack only when needed
418 if (webpackSources === undefined) {
419 webpackSources = (await Promise.resolve().then(() => __importStar(require('webpack')))).sources;
420 }
421 const { ConcatSource, OriginalSource, ReplaceSource, SourceMapSource } = webpackSources;
422 for (const locale of i18n.inlineLocales) {
423 const content = new ReplaceSource(inputMap
424 ? new SourceMapSource(options.code, options.filename, inputMap)
425 : new OriginalSource(options.code, options.filename));
426 const isSourceLocale = locale === i18n.sourceLocale;
427 // eslint-disable-next-line @typescript-eslint/no-explicit-any
428 const translations = isSourceLocale ? {} : i18n.locales[locale].translation || {};
429 for (const position of positions) {
430 const translated = utils.translate(diagnostics, translations, position.messageParts, position.expressions, isSourceLocale ? 'ignore' : options.missingTranslation || 'warning');
431 const expression = utils.buildLocalizeReplacement(translated[0], translated[1]);
432 const { code } = generate(expression);
433 content.replace(position.start, position.end - 1, code);
434 }
435 let outputSource = content;
436 if (options.setLocale) {
437 const setLocaleText = `var $localize=Object.assign(void 0===$localize?{}:$localize,{locale:"${locale}"});\n`;
438 // If locale data is provided, load it and prepend to file
439 let localeDataSource;
440 const localeDataPath = i18n.locales[locale] && i18n.locales[locale].dataPath;
441 if (localeDataPath) {
442 const localeDataContent = await loadLocaleData(localeDataPath, true, options.es5);
443 localeDataSource = new OriginalSource(localeDataContent, path.basename(localeDataPath));
444 }
445 outputSource = localeDataSource
446 ? // The semicolon ensures that there is no syntax error between statements
447 new ConcatSource(setLocaleText, localeDataSource, ';\n', content)
448 : new ConcatSource(setLocaleText, content);
449 }
450 const { source: outputCode, map: outputMap } = outputSource.sourceAndMap();
451 const outputPath = path.join(options.outputPath, i18n.flatOutput ? '' : locale, options.filename);
452 fs.writeFileSync(outputPath, outputCode);
453 if (inputMap && outputMap) {
454 outputMap.file = options.filename;
455 if (mapSourceRoot) {
456 outputMap.sourceRoot = mapSourceRoot;
457 }
458 fs.writeFileSync(outputPath + '.map', JSON.stringify(outputMap));
459 }
460 }
461 return { file: options.filename, diagnostics: diagnostics.messages, count: positions.length };
462}
463function inlineCopyOnly(options) {
464 if (!i18n) {
465 throw new Error('i18n options are missing');
466 }
467 for (const locale of i18n.inlineLocales) {
468 const outputPath = path.join(options.outputPath, i18n.flatOutput ? '' : locale, options.filename);
469 fs.writeFileSync(outputPath, options.code);
470 if (options.map) {
471 fs.writeFileSync(outputPath + '.map', options.map);
472 }
473 }
474 return { file: options.filename, diagnostics: [], count: 0 };
475}
476function findLocalizePositions(ast, options, utils) {
477 const positions = [];
478 // Workaround to ensure a path hub is present for traversal
479 const { File } = require('@babel/core');
480 const file = new File({}, { code: options.code, ast });
481 if (options.es5) {
482 core_1.traverse(file.ast, {
483 CallExpression(path) {
484 const callee = path.get('callee');
485 if (callee.isIdentifier() &&
486 callee.node.name === localizeName &&
487 utils.isGlobalIdentifier(callee)) {
488 const [messageParts, expressions] = unwrapLocalizeCall(path, utils);
489 positions.push({
490 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
491 start: path.node.start,
492 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
493 end: path.node.end,
494 messageParts,
495 expressions,
496 });
497 }
498 },
499 });
500 }
501 else {
502 core_1.traverse(file.ast, {
503 TaggedTemplateExpression(path) {
504 if (core_1.types.isIdentifier(path.node.tag) && path.node.tag.name === localizeName) {
505 const [messageParts, expressions] = unwrapTemplateLiteral(path, utils);
506 positions.push({
507 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
508 start: path.node.start,
509 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
510 end: path.node.end,
511 messageParts,
512 expressions,
513 });
514 }
515 },
516 });
517 }
518 return positions;
519}
520function unwrapTemplateLiteral(path, utils) {
521 const [messageParts] = utils.unwrapMessagePartsFromTemplateLiteral(path.get('quasi').get('quasis'));
522 const [expressions] = utils.unwrapExpressionsFromTemplateLiteral(path.get('quasi'));
523 return [messageParts, expressions];
524}
525function unwrapLocalizeCall(path, utils) {
526 const [messageParts] = utils.unwrapMessagePartsFromLocalizeCall(path);
527 const [expressions] = utils.unwrapSubstitutionsFromLocalizeCall(path);
528 return [messageParts, expressions];
529}
530async function loadLocaleData(path, optimize, es5) {
531 // The path is validated during option processing before the build starts
532 const content = fs.readFileSync(path, 'utf8');
533 // Downlevel and optimize the data
534 const transformResult = await core_1.transformAsync(content, {
535 filename: path,
536 // The types do not include the false option even though it is valid
537 // eslint-disable-next-line @typescript-eslint/no-explicit-any
538 inputSourceMap: false,
539 babelrc: false,
540 configFile: false,
541 presets: [
542 [
543 require.resolve('@babel/preset-env'),
544 {
545 bugfixes: true,
546 // IE 11 is the oldest supported browser
547 targets: es5 ? { ie: '11' } : { esmodules: true },
548 },
549 ],
550 ],
551 minified: environment_options_1.allowMinify && optimize,
552 compact: !environment_options_1.shouldBeautify && optimize,
553 comments: !optimize,
554 });
555 if (!transformResult || !transformResult.code) {
556 throw new Error(`Unknown error occurred processing bundle for "${path}".`);
557 }
558 return transformResult.code;
559}
Note: See TracBrowser for help on using the repository browser.