| 
									
										
										
										
											2020-11-11 15:29:43 +00:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google LLC All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | import {PluginObj, transformSync} from '@babel/core'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import {createEs2015LinkerPlugin} from '../../../linker/babel'; | 
					
						
							|  |  |  | import {AbsoluteFsPath, FileSystem} from '../../../src/ngtsc/file_system'; | 
					
						
							| 
									
										
										
										
											2020-12-02 21:40:44 +00:00
										 |  |  | import {ConsoleLogger, LogLevel} from '../../../src/ngtsc/logging'; | 
					
						
							|  |  |  | import {MapAndPath, RawSourceMap, SourceFileLoader} from '../../../src/ngtsc/sourcemaps'; | 
					
						
							| 
									
										
										
										
											2020-11-12 19:43:35 +00:00
										 |  |  | import {CompileResult, getBuildOutputDirectory} from '../test_helpers/compile_test'; | 
					
						
							| 
									
										
										
										
											2020-11-11 15:29:43 +00:00
										 |  |  | import {ComplianceTest} from '../test_helpers/get_compliance_tests'; | 
					
						
							|  |  |  | import {parseGoldenPartial} from '../test_helpers/golden_partials'; | 
					
						
							|  |  |  | import {runTests} from '../test_helpers/test_runner'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-02 14:12:03 +00:00
										 |  |  | runTests('linked compile', linkPartials); | 
					
						
							| 
									
										
										
										
											2020-11-11 15:29:43 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Link all the partials specified in the given `test`. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param fs The mock file-system to use for linking the partials. | 
					
						
							|  |  |  |  * @param test The compliance test whose partials will be linked. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-11-12 19:43:35 +00:00
										 |  |  | function linkPartials(fs: FileSystem, test: ComplianceTest): CompileResult { | 
					
						
							| 
									
										
										
										
											2020-12-02 21:40:44 +00:00
										 |  |  |   const logger = new ConsoleLogger(LogLevel.debug); | 
					
						
							|  |  |  |   const loader = new SourceFileLoader(fs, logger, {}); | 
					
						
							| 
									
										
										
										
											2020-11-11 15:29:43 +00:00
										 |  |  |   const builtDirectory = getBuildOutputDirectory(fs); | 
					
						
							| 
									
										
										
										
											2020-11-12 19:43:35 +00:00
										 |  |  |   const linkerPlugin = createEs2015LinkerPlugin({ | 
					
						
							|  |  |  |     // By default we don't render legacy message ids in compliance tests.
 | 
					
						
							|  |  |  |     enableI18nLegacyMessageIdFormat: false, | 
					
						
							|  |  |  |     ...test.angularCompilerOptions | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-11-11 15:29:43 +00:00
										 |  |  |   const goldenPartialPath = fs.resolve('/GOLDEN_PARTIAL.js'); | 
					
						
							|  |  |  |   if (!fs.exists(goldenPartialPath)) { | 
					
						
							|  |  |  |     throw new Error( | 
					
						
							|  |  |  |         'Golden partial does not exist for this test\n' + | 
					
						
							|  |  |  |         'Try generating it by running:\n' + | 
					
						
							|  |  |  |         `bazel run //packages/compiler-cli/test/compliance/test_cases:${ | 
					
						
							|  |  |  |             test.relativePath}.golden.update`);
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   const partialFile = fs.readFile(goldenPartialPath); | 
					
						
							| 
									
										
										
										
											2020-12-02 21:40:44 +00:00
										 |  |  |   const partialFiles = parseGoldenPartial(partialFile); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   partialFiles.forEach(f => safeWrite(fs, fs.resolve(builtDirectory, f.path), f.content)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (const expectation of test.expectations) { | 
					
						
							|  |  |  |     for (const {generated: fileName} of expectation.files) { | 
					
						
							|  |  |  |       const partialPath = fs.resolve(builtDirectory, fileName); | 
					
						
							|  |  |  |       if (!fs.exists(partialPath)) { | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       const source = fs.readFile(partialPath); | 
					
						
							|  |  |  |       const sourceMapPath = fs.resolve(partialPath + '.map'); | 
					
						
							|  |  |  |       const sourceMap = | 
					
						
							|  |  |  |           fs.exists(sourceMapPath) ? JSON.parse(fs.readFile(sourceMapPath)) : undefined; | 
					
						
							|  |  |  |       const {linkedSource, linkedSourceMap} = | 
					
						
							|  |  |  |           applyLinker({fileName, source, sourceMap}, linkerPlugin); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (linkedSourceMap !== undefined) { | 
					
						
							|  |  |  |         const mapAndPath: MapAndPath = {map: linkedSourceMap, mapPath: sourceMapPath}; | 
					
						
							|  |  |  |         const sourceFile = loader.loadSourceFile(partialPath, linkedSource, mapAndPath); | 
					
						
							|  |  |  |         safeWrite(fs, sourceMapPath, JSON.stringify(sourceFile.renderFlattenedSourceMap())); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       safeWrite(fs, partialPath, linkedSource); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-11-11 15:29:43 +00:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-11-12 19:43:35 +00:00
										 |  |  |   return {emittedFiles: [], errors: []}; | 
					
						
							| 
									
										
										
										
											2020-11-11 15:29:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Run the file through the Babel linker plugin. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * It will ignore files that do not have a `.js` extension. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param file The file name and its source to be transformed using the linker. | 
					
						
							|  |  |  |  * @param linkerPlugin The linker plugin to apply. | 
					
						
							|  |  |  |  * @returns The file's source content, which has been transformed using the linker if necessary. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-12-02 21:40:44 +00:00
										 |  |  | function applyLinker( | 
					
						
							|  |  |  |     file: {fileName: string; source: string, sourceMap: RawSourceMap | undefined}, | 
					
						
							|  |  |  |     linkerPlugin: PluginObj): {linkedSource: string, linkedSourceMap: RawSourceMap|undefined} { | 
					
						
							| 
									
										
										
										
											2020-11-11 15:29:43 +00:00
										 |  |  |   if (!file.fileName.endsWith('.js')) { | 
					
						
							| 
									
										
										
										
											2020-12-02 21:40:44 +00:00
										 |  |  |     return {linkedSource: file.source, linkedSourceMap: file.sourceMap}; | 
					
						
							| 
									
										
										
										
											2020-11-11 15:29:43 +00:00
										 |  |  |   } | 
					
						
							|  |  |  |   const result = transformSync(file.source, { | 
					
						
							|  |  |  |     filename: file.fileName, | 
					
						
							| 
									
										
										
										
											2020-12-02 21:40:44 +00:00
										 |  |  |     sourceMaps: !!file.sourceMap, | 
					
						
							| 
									
										
										
										
											2020-11-11 15:29:43 +00:00
										 |  |  |     plugins: [linkerPlugin], | 
					
						
							|  |  |  |     parserOpts: {sourceType: 'unambiguous'}, | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   if (result === null) { | 
					
						
							|  |  |  |     throw fail('Babel transform did not have output'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (result.code == null) { | 
					
						
							|  |  |  |     throw fail('Babel transform result does not have any code'); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-12-02 21:40:44 +00:00
										 |  |  |   return {linkedSource: result.code, linkedSourceMap: result.map || undefined}; | 
					
						
							| 
									
										
										
										
											2020-11-11 15:29:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Write the `content` to the `path` on the `fs` file-system, first ensuring that the containing | 
					
						
							|  |  |  |  * directory exists. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function safeWrite(fs: FileSystem, path: AbsoluteFsPath, content: string): void { | 
					
						
							|  |  |  |   fs.ensureDir(fs.dirname(path)); | 
					
						
							|  |  |  |   fs.writeFile(path, content); | 
					
						
							|  |  |  | } |