This commit changes the `PartialComponentLinker` to use the original source of an external template when compiling, if available, to ensure that the source-mapping of the final linked code is accurate. If the linker is given a file-system and logger, then it will attempt to compute the original source of external templates so that the final linked code references the correct template source. PR Close #40237
		
			
				
	
	
		
			80 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			80 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| /**
 | |
|  * @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 * as ts from 'typescript';
 | |
| 
 | |
| import {needsLinking} from '../../../linker';
 | |
| import {createEs2015LinkerPlugin} from '../../../linker/babel';
 | |
| import {MockFileSystemNative} from '../../../src/ngtsc/file_system/testing';
 | |
| import {MockLogger} from '../../../src/ngtsc/logging/testing';
 | |
| import {compileFiles, CompileFn, setCompileFn} from '../mock_compile';
 | |
| 
 | |
| /**
 | |
|  * A function to compile the given code in two steps:
 | |
|  *
 | |
|  * - first compile the code in partial mode
 | |
|  * - then compile the partially compiled code using the linker
 | |
|  *
 | |
|  * This should produce the same output as the full AOT compilation
 | |
|  */
 | |
| const linkedCompile: CompileFn = (data, angularFiles, options) => {
 | |
|   if (options !== undefined && options.target !== undefined &&
 | |
|       options.target < ts.ScriptTarget.ES2015) {
 | |
|     pending('ES5 is not supported in the partial compilation tests');
 | |
|     throw new Error('ES5 is not supported in the partial compilation tests');
 | |
|   }
 | |
| 
 | |
|   const compiledFiles = compileFiles(data, angularFiles, {...options, compilationMode: 'partial'});
 | |
|   const fileSystem = new MockFileSystemNative();
 | |
|   const logger = new MockLogger();
 | |
|   const linkerPlugin = createEs2015LinkerPlugin({
 | |
|     fileSystem,
 | |
|     logger,
 | |
|     // enableI18nLegacyMessageIdFormat defaults to false in `compileFiles`.
 | |
|     enableI18nLegacyMessageIdFormat: false,
 | |
|     ...options,
 | |
|   });
 | |
| 
 | |
|   const source =
 | |
|       compiledFiles
 | |
|           .map(file => applyLinker({path: file.fileName, source: file.source}, linkerPlugin))
 | |
|           .join('\n');
 | |
| 
 | |
|   return {source};
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Runs the provided code through the Babel linker plugin, if the file has the .js extension.
 | |
|  *
 | |
|  * @param file The absolute file path 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.
 | |
|  */
 | |
| function applyLinker(file: {path: string; source: string}, linkerPlugin: PluginObj): string {
 | |
|   if (!file.path.endsWith('.js') || !needsLinking(file.path, file.source)) {
 | |
|     return file.source;
 | |
|   }
 | |
|   const result = transformSync(file.source, {
 | |
|     filename: file.path,
 | |
|     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');
 | |
|   }
 | |
|   return result.code;
 | |
| }
 | |
| 
 | |
| // Update the function that will do the compiling with this specialised version that
 | |
| // runs the prelink and postlink parts of AOT compilation, to check it produces the
 | |
| // same result as a normal full AOT compile.
 | |
| setCompileFn(linkedCompile);
 |