refactor(compiler): replace Comment nodes with leadingComments property (#38811)

Common AST formats such as TS and Babel do not use a separate
node for comments, but instead attach comments to other AST nodes.
Previously this was worked around in TS by creating a `NotEmittedStatement`
AST node to attach the comment to. But Babel does not have this facility,
so it will not be a viable approach for the linker.

This commit refactors the output AST, to remove the `CommentStmt` and
`JSDocCommentStmt` nodes. Instead statements have a collection of
`leadingComments` that are rendered/attached to the final AST nodes
when being translated or printed.

PR Close #38811
This commit is contained in:
Pete Bacon Darwin
2020-09-11 16:43:23 +01:00
committed by Misko Hevery
parent d8657ddb5c
commit a0756e9fa4
24 changed files with 427 additions and 363 deletions

View File

@ -5,7 +5,7 @@
* 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 {CommentStmt, ConstantPool, Expression, Statement, WrappedNodeExpr, WritePropExpr} from '@angular/compiler';
import {ConstantPool, Expression, jsDocComment, LeadingComment, Statement, WrappedNodeExpr, WritePropExpr} from '@angular/compiler';
import MagicString from 'magic-string';
import * as ts from 'typescript';
@ -166,11 +166,11 @@ export class Renderer {
sourceFile: ts.SourceFile, compiledClass: CompiledClass, imports: ImportManager,
annotateForClosureCompiler: boolean): string {
const name = this.host.getInternalNameOfClass(compiledClass.declaration);
const statements: Statement[][] = compiledClass.compilation.map(c => {
return createAssignmentStatements(
name, c.name, c.initializer, annotateForClosureCompiler ? '* @nocollapse ' : undefined);
});
return this.renderStatements(sourceFile, Array.prototype.concat.apply([], statements), imports);
const leadingComment =
annotateForClosureCompiler ? jsDocComment([{tagName: 'nocollapse'}]) : undefined;
const statements: Statement[] = compiledClass.compilation.map(
c => createAssignmentStatement(name, c.name, c.initializer, leadingComment));
return this.renderStatements(sourceFile, statements, imports);
}
/**
@ -213,16 +213,16 @@ export function renderConstantPool(
* compiled decorator to be applied to the class.
* @param analyzedClass The info about the class whose statement we want to create.
*/
function createAssignmentStatements(
function createAssignmentStatement(
receiverName: ts.DeclarationName, propName: string, initializer: Expression,
leadingComment?: string): Statement[] {
leadingComment?: LeadingComment): Statement {
const receiver = new WrappedNodeExpr(receiverName);
const statements =
[new WritePropExpr(
receiver, propName, initializer, /* type */ undefined, /* sourceSpan */ undefined)
.toStmt()];
const statement =
new WritePropExpr(
receiver, propName, initializer, /* type */ undefined, /* sourceSpan */ undefined)
.toStmt();
if (leadingComment !== undefined) {
statements.unshift(new CommentStmt(leadingComment, true));
statement.addLeadingComment(leadingComment);
}
return statements;
return statement;
}

View File

@ -1663,12 +1663,12 @@ runInEachFileSystem(() => {
JSON.stringify({angularCompilerOptions: {annotateForClosureCompiler: true}}));
mainNgcc({basePath: '/dist', propertiesToConsider: ['es2015']});
const jsContents = fs.readFile(_(`/dist/local-package/index.js`));
expect(jsContents).toContain('/** @nocollapse */ \nAppComponent.ɵcmp =');
expect(jsContents).toContain('/** @nocollapse */\nAppComponent.ɵcmp =');
});
it('should default to not give closure annotated output', () => {
mainNgcc({basePath: '/dist', propertiesToConsider: ['es2015']});
const jsContents = fs.readFile(_(`/dist/local-package/index.js`));
expect(jsContents).not.toContain('/** @nocollapse */');
expect(jsContents).not.toContain('@nocollapse');
});
});