From 866d500324e20682c30aa90eeb4fef52bdb81e71 Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh Date: Fri, 1 Mar 2019 15:17:26 -0800 Subject: [PATCH] fix(ivy): copy top-level comments into generated factory shims (#29065) When ngtsc generates a .ngfactory shim, it does so based on the contents of an original file in the program. Occasionally these original files have comments at the top which are load-bearing (e.g. they contain jsdoc annotations which are significant to downstream bundling tools). The generated factory shims should preserve this comment. This commit adds a step to the ngfactory generator to preserve the top-level comment from the original source file. FW-1006 #resolve FW-1095 #resolve PR Close #29065 --- .../src/ngtsc/shims/src/factory_generator.ts | 15 +++++++++++++-- packages/compiler-cli/test/ngtsc/ngtsc_spec.ts | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts b/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts index c32a288ca3..a9487be803 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts @@ -56,14 +56,25 @@ export class FactoryGenerator implements ShimGenerator { // Grab the symbol name. .map(decl => decl.name !.text); - let sourceText = ''; + + // If there is a top-level comment in the original file, copy it over at the top of the + // generated factory file. This is important for preserving any load-bearing jsdoc comments. + let comment: string = ''; + if (original.statements.length > 0) { + const firstStatement = original.statements[0]; + if (firstStatement.getLeadingTriviaWidth() > 0) { + comment = firstStatement.getFullText().substr(0, firstStatement.getLeadingTriviaWidth()); + } + } + + let sourceText = comment; if (symbolNames.length > 0) { // For each symbol name, generate a constant export of the corresponding NgFactory. // This will encompass a lot of symbols which don't need factories, but that's okay // because it won't miss any that do. const varLines = symbolNames.map( name => `export const ${name}NgFactory = new i0.ɵNgModuleFactory(${name});`); - sourceText = [ + sourceText += [ // This might be incorrect if the current package being compiled is Angular core, but it's // okay to leave in at type checking time. TypeScript can handle this reference via its path // mapping, but downstream bundlers can't. If the current package is core itself, this will diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts index a54f684084..a19e1c6a3e 100644 --- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts +++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts @@ -1694,6 +1694,22 @@ describe('ngtsc behavioral tests', () => { expect(emptyFactory).toContain(`export var ɵNonEmptyModule = true;`); }); + it('should copy a top-level comment into a factory stub', () => { + env.tsconfig({'allowEmptyCodegenFiles': true}); + + env.write('test.ts', `/** I am a top-level comment. */ + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class TestModule {} + `); + + env.driveMain(); + + const factoryContents = env.getContents('test.ngfactory.js'); + expect(factoryContents).toMatch(/^\/\*\* I am a top-level comment\. \*\//); + }); + it('should be able to compile an app using the factory shim', () => { env.tsconfig({'allowEmptyCodegenFiles': true});