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:

committed by
Misko Hevery

parent
d8657ddb5c
commit
a0756e9fa4
@ -78,7 +78,7 @@ export * from './ml_parser/tags';
|
||||
export {LexerRange} from './ml_parser/lexer';
|
||||
export * from './ml_parser/xml_parser';
|
||||
export {NgModuleCompiler} from './ng_module_compiler';
|
||||
export {ArrayType, AssertNotNull, DYNAMIC_TYPE, BinaryOperator, BinaryOperatorExpr, BuiltinMethod, BuiltinType, BuiltinTypeName, BuiltinVar, CastExpr, ClassField, ClassMethod, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, Expression, ExpressionStatement, ExpressionType, ExpressionVisitor, ExternalExpr, ExternalReference, literalMap, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, MapType, NotExpr, NONE_TYPE, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, StatementVisitor, ThrowStmt, TryCatchStmt, Type, TypeVisitor, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, StmtModifier, Statement, STRING_TYPE, TypeofExpr, collectExternalReferences} from './output/output_ast';
|
||||
export {ArrayType, AssertNotNull, DYNAMIC_TYPE, BinaryOperator, BinaryOperatorExpr, BuiltinMethod, BuiltinType, BuiltinTypeName, BuiltinVar, CastExpr, ClassField, ClassMethod, ClassStmt, CommaExpr, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, Expression, ExpressionStatement, ExpressionType, ExpressionVisitor, ExternalExpr, ExternalReference, literalMap, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, MapType, NotExpr, NONE_TYPE, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, StatementVisitor, ThrowStmt, TryCatchStmt, Type, TypeVisitor, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, StmtModifier, Statement, STRING_TYPE, TypeofExpr, collectExternalReferences, jsDocComment, leadingComment, LeadingComment, JSDocComment, UnaryOperator, UnaryOperatorExpr, LocalizedString} from './output/output_ast';
|
||||
export {EmitterVisitorContext} from './output/abstract_emitter';
|
||||
export {JitEvaluator} from './output/output_jit';
|
||||
export * from './output/ts_emitter';
|
||||
|
@ -202,13 +202,34 @@ export class EmitterVisitorContext {
|
||||
export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.ExpressionVisitor {
|
||||
constructor(private _escapeDollarInStrings: boolean) {}
|
||||
|
||||
protected printLeadingComments(stmt: o.Statement, ctx: EmitterVisitorContext): void {
|
||||
if (stmt.leadingComments === undefined) {
|
||||
return;
|
||||
}
|
||||
for (const comment of stmt.leadingComments) {
|
||||
if (comment instanceof o.JSDocComment) {
|
||||
ctx.print(stmt, `/*${comment.toString()}*/`, comment.trailingNewline);
|
||||
} else {
|
||||
if (comment.multiline) {
|
||||
ctx.print(stmt, `/* ${comment.text} */`, comment.trailingNewline);
|
||||
} else {
|
||||
comment.text.split('\n').forEach((line) => {
|
||||
ctx.println(stmt, `// ${line}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visitExpressionStmt(stmt: o.ExpressionStatement, ctx: EmitterVisitorContext): any {
|
||||
this.printLeadingComments(stmt, ctx);
|
||||
stmt.expr.visitExpression(this, ctx);
|
||||
ctx.println(stmt, ';');
|
||||
return null;
|
||||
}
|
||||
|
||||
visitReturnStmt(stmt: o.ReturnStatement, ctx: EmitterVisitorContext): any {
|
||||
this.printLeadingComments(stmt, ctx);
|
||||
ctx.print(stmt, `return `);
|
||||
stmt.value.visitExpression(this, ctx);
|
||||
ctx.println(stmt, ';');
|
||||
@ -220,6 +241,7 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex
|
||||
abstract visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any;
|
||||
|
||||
visitIfStmt(stmt: o.IfStmt, ctx: EmitterVisitorContext): any {
|
||||
this.printLeadingComments(stmt, ctx);
|
||||
ctx.print(stmt, `if (`);
|
||||
stmt.condition.visitExpression(this, ctx);
|
||||
ctx.print(stmt, `) {`);
|
||||
@ -248,25 +270,12 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex
|
||||
abstract visitTryCatchStmt(stmt: o.TryCatchStmt, ctx: EmitterVisitorContext): any;
|
||||
|
||||
visitThrowStmt(stmt: o.ThrowStmt, ctx: EmitterVisitorContext): any {
|
||||
this.printLeadingComments(stmt, ctx);
|
||||
ctx.print(stmt, `throw `);
|
||||
stmt.error.visitExpression(this, ctx);
|
||||
ctx.println(stmt, `;`);
|
||||
return null;
|
||||
}
|
||||
visitCommentStmt(stmt: o.CommentStmt, ctx: EmitterVisitorContext): any {
|
||||
if (stmt.multiline) {
|
||||
ctx.println(stmt, `/* ${stmt.comment} */`);
|
||||
} else {
|
||||
stmt.comment.split('\n').forEach((line) => {
|
||||
ctx.println(stmt, `// ${line}`);
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
visitJSDocCommentStmt(stmt: o.JSDocCommentStmt, ctx: EmitterVisitorContext) {
|
||||
ctx.println(stmt, `/*${stmt.toString()}*/`);
|
||||
return null;
|
||||
}
|
||||
|
||||
abstract visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any;
|
||||
|
||||
|
@ -16,15 +16,11 @@ export enum TypeModifier {
|
||||
}
|
||||
|
||||
export abstract class Type {
|
||||
constructor(public modifiers: TypeModifier[]|null = null) {
|
||||
if (!modifiers) {
|
||||
this.modifiers = [];
|
||||
}
|
||||
}
|
||||
constructor(public modifiers: TypeModifier[] = []) {}
|
||||
abstract visitType(visitor: TypeVisitor, context: any): any;
|
||||
|
||||
hasModifier(modifier: TypeModifier): boolean {
|
||||
return this.modifiers!.indexOf(modifier) !== -1;
|
||||
return this.modifiers.indexOf(modifier) !== -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +36,7 @@ export enum BuiltinTypeName {
|
||||
}
|
||||
|
||||
export class BuiltinType extends Type {
|
||||
constructor(public name: BuiltinTypeName, modifiers: TypeModifier[]|null = null) {
|
||||
constructor(public name: BuiltinTypeName, modifiers?: TypeModifier[]) {
|
||||
super(modifiers);
|
||||
}
|
||||
visitType(visitor: TypeVisitor, context: any): any {
|
||||
@ -50,8 +46,7 @@ export class BuiltinType extends Type {
|
||||
|
||||
export class ExpressionType extends Type {
|
||||
constructor(
|
||||
public value: Expression, modifiers: TypeModifier[]|null = null,
|
||||
public typeParams: Type[]|null = null) {
|
||||
public value: Expression, modifiers?: TypeModifier[], public typeParams: Type[]|null = null) {
|
||||
super(modifiers);
|
||||
}
|
||||
visitType(visitor: TypeVisitor, context: any): any {
|
||||
@ -61,7 +56,7 @@ export class ExpressionType extends Type {
|
||||
|
||||
|
||||
export class ArrayType extends Type {
|
||||
constructor(public of: Type, modifiers: TypeModifier[]|null = null) {
|
||||
constructor(public of: Type, modifiers?: TypeModifier[]) {
|
||||
super(modifiers);
|
||||
}
|
||||
visitType(visitor: TypeVisitor, context: any): any {
|
||||
@ -72,7 +67,7 @@ export class ArrayType extends Type {
|
||||
|
||||
export class MapType extends Type {
|
||||
public valueType: Type|null;
|
||||
constructor(valueType: Type|null|undefined, modifiers: TypeModifier[]|null = null) {
|
||||
constructor(valueType: Type|null|undefined, modifiers?: TypeModifier[]) {
|
||||
super(modifiers);
|
||||
this.valueType = valueType || null;
|
||||
}
|
||||
@ -357,7 +352,7 @@ export class WriteVarExpr extends Expression {
|
||||
return visitor.visitWriteVarExpr(this, context);
|
||||
}
|
||||
|
||||
toDeclStmt(type?: Type|null, modifiers?: StmtModifier[]|null): DeclareVarStmt {
|
||||
toDeclStmt(type?: Type|null, modifiers?: StmtModifier[]): DeclareVarStmt {
|
||||
return new DeclareVarStmt(this.name, this.value, type, modifiers, this.sourceSpan);
|
||||
}
|
||||
|
||||
@ -764,7 +759,7 @@ export class FunctionExpr extends Expression {
|
||||
return visitor.visitFunctionExpr(this, context);
|
||||
}
|
||||
|
||||
toDeclStmt(name: string, modifiers: StmtModifier[]|null = null): DeclareFunctionStmt {
|
||||
toDeclStmt(name: string, modifiers?: StmtModifier[]): DeclareFunctionStmt {
|
||||
return new DeclareFunctionStmt(
|
||||
name, this.params, this.statements, this.type, modifiers, this.sourceSpan);
|
||||
}
|
||||
@ -978,13 +973,25 @@ export enum StmtModifier {
|
||||
Static,
|
||||
}
|
||||
|
||||
export abstract class Statement {
|
||||
public modifiers: StmtModifier[];
|
||||
public sourceSpan: ParseSourceSpan|null;
|
||||
constructor(modifiers?: StmtModifier[]|null, sourceSpan?: ParseSourceSpan|null) {
|
||||
this.modifiers = modifiers || [];
|
||||
this.sourceSpan = sourceSpan || null;
|
||||
export class LeadingComment {
|
||||
constructor(public text: string, public multiline: boolean, public trailingNewline: boolean) {}
|
||||
toString() {
|
||||
return this.multiline ? ` ${this.text} ` : this.text;
|
||||
}
|
||||
}
|
||||
export class JSDocComment extends LeadingComment {
|
||||
constructor(public tags: JSDocTag[]) {
|
||||
super('', /* multiline */ true, /* trailingNewline */ true);
|
||||
}
|
||||
toString(): string {
|
||||
return serializeTags(this.tags);
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class Statement {
|
||||
constructor(
|
||||
public modifiers: StmtModifier[] = [], public sourceSpan: ParseSourceSpan|null = null,
|
||||
public leadingComments?: LeadingComment[]) {}
|
||||
/**
|
||||
* Calculates whether this statement produces the same value as the given statement.
|
||||
* Note: We don't check Types nor ParseSourceSpans nor function arguments.
|
||||
@ -994,7 +1001,12 @@ export abstract class Statement {
|
||||
abstract visitStatement(visitor: StatementVisitor, context: any): any;
|
||||
|
||||
hasModifier(modifier: StmtModifier): boolean {
|
||||
return this.modifiers!.indexOf(modifier) !== -1;
|
||||
return this.modifiers.indexOf(modifier) !== -1;
|
||||
}
|
||||
|
||||
addLeadingComment(leadingComment: LeadingComment): void {
|
||||
this.leadingComments = this.leadingComments ?? [];
|
||||
this.leadingComments.push(leadingComment);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1002,9 +1014,9 @@ export abstract class Statement {
|
||||
export class DeclareVarStmt extends Statement {
|
||||
public type: Type|null;
|
||||
constructor(
|
||||
public name: string, public value?: Expression, type?: Type|null,
|
||||
modifiers: StmtModifier[]|null = null, sourceSpan?: ParseSourceSpan|null) {
|
||||
super(modifiers, sourceSpan);
|
||||
public name: string, public value?: Expression, type?: Type|null, modifiers?: StmtModifier[],
|
||||
sourceSpan?: ParseSourceSpan|null, leadingComments?: LeadingComment[]) {
|
||||
super(modifiers, sourceSpan, leadingComments);
|
||||
this.type = type || (value && value.type) || null;
|
||||
}
|
||||
isEquivalent(stmt: Statement): boolean {
|
||||
@ -1020,28 +1032,29 @@ export class DeclareFunctionStmt extends Statement {
|
||||
public type: Type|null;
|
||||
constructor(
|
||||
public name: string, public params: FnParam[], public statements: Statement[],
|
||||
type?: Type|null, modifiers: StmtModifier[]|null = null, sourceSpan?: ParseSourceSpan|null) {
|
||||
super(modifiers, sourceSpan);
|
||||
type?: Type|null, modifiers?: StmtModifier[], sourceSpan?: ParseSourceSpan|null,
|
||||
leadingComments?: LeadingComment[]) {
|
||||
super(modifiers, sourceSpan, leadingComments);
|
||||
this.type = type || null;
|
||||
}
|
||||
isEquivalent(stmt: Statement): boolean {
|
||||
return stmt instanceof DeclareFunctionStmt && areAllEquivalent(this.params, stmt.params) &&
|
||||
areAllEquivalent(this.statements, stmt.statements);
|
||||
}
|
||||
|
||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||
return visitor.visitDeclareFunctionStmt(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExpressionStatement extends Statement {
|
||||
constructor(public expr: Expression, sourceSpan?: ParseSourceSpan|null) {
|
||||
super(null, sourceSpan);
|
||||
constructor(
|
||||
public expr: Expression, sourceSpan?: ParseSourceSpan|null,
|
||||
leadingComments?: LeadingComment[]) {
|
||||
super([], sourceSpan, leadingComments);
|
||||
}
|
||||
isEquivalent(stmt: Statement): boolean {
|
||||
return stmt instanceof ExpressionStatement && this.expr.isEquivalent(stmt.expr);
|
||||
}
|
||||
|
||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||
return visitor.visitExpressionStmt(this, context);
|
||||
}
|
||||
@ -1049,8 +1062,10 @@ export class ExpressionStatement extends Statement {
|
||||
|
||||
|
||||
export class ReturnStatement extends Statement {
|
||||
constructor(public value: Expression, sourceSpan?: ParseSourceSpan|null) {
|
||||
super(null, sourceSpan);
|
||||
constructor(
|
||||
public value: Expression, sourceSpan: ParseSourceSpan|null = null,
|
||||
leadingComments?: LeadingComment[]) {
|
||||
super([], sourceSpan, leadingComments);
|
||||
}
|
||||
isEquivalent(stmt: Statement): boolean {
|
||||
return stmt instanceof ReturnStatement && this.value.isEquivalent(stmt.value);
|
||||
@ -1061,21 +1076,15 @@ export class ReturnStatement extends Statement {
|
||||
}
|
||||
|
||||
export class AbstractClassPart {
|
||||
public type: Type|null;
|
||||
constructor(type: Type|null|undefined, public modifiers: StmtModifier[]|null) {
|
||||
if (!modifiers) {
|
||||
this.modifiers = [];
|
||||
}
|
||||
this.type = type || null;
|
||||
}
|
||||
constructor(public type: Type|null = null, public modifiers: StmtModifier[] = []) {}
|
||||
hasModifier(modifier: StmtModifier): boolean {
|
||||
return this.modifiers!.indexOf(modifier) !== -1;
|
||||
return this.modifiers.indexOf(modifier) !== -1;
|
||||
}
|
||||
}
|
||||
|
||||
export class ClassField extends AbstractClassPart {
|
||||
constructor(
|
||||
public name: string, type?: Type|null, modifiers: StmtModifier[]|null = null,
|
||||
public name: string, type?: Type|null, modifiers?: StmtModifier[],
|
||||
public initializer?: Expression) {
|
||||
super(type, modifiers);
|
||||
}
|
||||
@ -1088,7 +1097,7 @@ export class ClassField extends AbstractClassPart {
|
||||
export class ClassMethod extends AbstractClassPart {
|
||||
constructor(
|
||||
public name: string|null, public params: FnParam[], public body: Statement[],
|
||||
type?: Type|null, modifiers: StmtModifier[]|null = null) {
|
||||
type?: Type|null, modifiers?: StmtModifier[]) {
|
||||
super(type, modifiers);
|
||||
}
|
||||
isEquivalent(m: ClassMethod) {
|
||||
@ -1099,8 +1108,7 @@ export class ClassMethod extends AbstractClassPart {
|
||||
|
||||
export class ClassGetter extends AbstractClassPart {
|
||||
constructor(
|
||||
public name: string, public body: Statement[], type?: Type|null,
|
||||
modifiers: StmtModifier[]|null = null) {
|
||||
public name: string, public body: Statement[], type?: Type|null, modifiers?: StmtModifier[]) {
|
||||
super(type, modifiers);
|
||||
}
|
||||
isEquivalent(m: ClassGetter) {
|
||||
@ -1113,9 +1121,9 @@ export class ClassStmt extends Statement {
|
||||
constructor(
|
||||
public name: string, public parent: Expression|null, public fields: ClassField[],
|
||||
public getters: ClassGetter[], public constructorMethod: ClassMethod,
|
||||
public methods: ClassMethod[], modifiers: StmtModifier[]|null = null,
|
||||
sourceSpan?: ParseSourceSpan|null) {
|
||||
super(modifiers, sourceSpan);
|
||||
public methods: ClassMethod[], modifiers?: StmtModifier[], sourceSpan?: ParseSourceSpan|null,
|
||||
leadingComments?: LeadingComment[]) {
|
||||
super(modifiers, sourceSpan, leadingComments);
|
||||
}
|
||||
isEquivalent(stmt: Statement): boolean {
|
||||
return stmt instanceof ClassStmt && this.name === stmt.name &&
|
||||
@ -1134,8 +1142,9 @@ export class ClassStmt extends Statement {
|
||||
export class IfStmt extends Statement {
|
||||
constructor(
|
||||
public condition: Expression, public trueCase: Statement[],
|
||||
public falseCase: Statement[] = [], sourceSpan?: ParseSourceSpan|null) {
|
||||
super(null, sourceSpan);
|
||||
public falseCase: Statement[] = [], sourceSpan?: ParseSourceSpan|null,
|
||||
leadingComments?: LeadingComment[]) {
|
||||
super([], sourceSpan, leadingComments);
|
||||
}
|
||||
isEquivalent(stmt: Statement): boolean {
|
||||
return stmt instanceof IfStmt && this.condition.isEquivalent(stmt.condition) &&
|
||||
@ -1147,38 +1156,11 @@ export class IfStmt extends Statement {
|
||||
}
|
||||
}
|
||||
|
||||
export class CommentStmt extends Statement {
|
||||
constructor(public comment: string, public multiline = false, sourceSpan?: ParseSourceSpan|null) {
|
||||
super(null, sourceSpan);
|
||||
}
|
||||
isEquivalent(stmt: Statement): boolean {
|
||||
return stmt instanceof CommentStmt;
|
||||
}
|
||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||
return visitor.visitCommentStmt(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class JSDocCommentStmt extends Statement {
|
||||
constructor(public tags: JSDocTag[] = [], sourceSpan?: ParseSourceSpan|null) {
|
||||
super(null, sourceSpan);
|
||||
}
|
||||
isEquivalent(stmt: Statement): boolean {
|
||||
return stmt instanceof JSDocCommentStmt && this.toString() === stmt.toString();
|
||||
}
|
||||
visitStatement(visitor: StatementVisitor, context: any): any {
|
||||
return visitor.visitJSDocCommentStmt(this, context);
|
||||
}
|
||||
toString(): string {
|
||||
return serializeTags(this.tags);
|
||||
}
|
||||
}
|
||||
|
||||
export class TryCatchStmt extends Statement {
|
||||
constructor(
|
||||
public bodyStmts: Statement[], public catchStmts: Statement[],
|
||||
sourceSpan?: ParseSourceSpan|null) {
|
||||
super(null, sourceSpan);
|
||||
sourceSpan: ParseSourceSpan|null = null, leadingComments?: LeadingComment[]) {
|
||||
super([], sourceSpan, leadingComments);
|
||||
}
|
||||
isEquivalent(stmt: Statement): boolean {
|
||||
return stmt instanceof TryCatchStmt && areAllEquivalent(this.bodyStmts, stmt.bodyStmts) &&
|
||||
@ -1191,8 +1173,10 @@ export class TryCatchStmt extends Statement {
|
||||
|
||||
|
||||
export class ThrowStmt extends Statement {
|
||||
constructor(public error: Expression, sourceSpan?: ParseSourceSpan|null) {
|
||||
super(null, sourceSpan);
|
||||
constructor(
|
||||
public error: Expression, sourceSpan: ParseSourceSpan|null = null,
|
||||
leadingComments?: LeadingComment[]) {
|
||||
super([], sourceSpan, leadingComments);
|
||||
}
|
||||
isEquivalent(stmt: ThrowStmt): boolean {
|
||||
return stmt instanceof TryCatchStmt && this.error.isEquivalent(stmt.error);
|
||||
@ -1211,8 +1195,6 @@ export interface StatementVisitor {
|
||||
visitIfStmt(stmt: IfStmt, context: any): any;
|
||||
visitTryCatchStmt(stmt: TryCatchStmt, context: any): any;
|
||||
visitThrowStmt(stmt: ThrowStmt, context: any): any;
|
||||
visitCommentStmt(stmt: CommentStmt, context: any): any;
|
||||
visitJSDocCommentStmt(stmt: JSDocCommentStmt, context: any): any;
|
||||
}
|
||||
|
||||
export class AstTransformer implements StatementVisitor, ExpressionVisitor {
|
||||
@ -1374,7 +1356,7 @@ export class AstTransformer implements StatementVisitor, ExpressionVisitor {
|
||||
const entries = ast.entries.map(
|
||||
(entry): LiteralMapEntry => new LiteralMapEntry(
|
||||
entry.key, entry.value.visitExpression(this, context), entry.quoted));
|
||||
const mapType = new MapType(ast.valueType, null);
|
||||
const mapType = new MapType(ast.valueType);
|
||||
return this.transformExpr(new LiteralMapExpr(entries, mapType, ast.sourceSpan), context);
|
||||
}
|
||||
visitCommaExpr(ast: CommaExpr, context: any): any {
|
||||
@ -1388,25 +1370,30 @@ export class AstTransformer implements StatementVisitor, ExpressionVisitor {
|
||||
visitDeclareVarStmt(stmt: DeclareVarStmt, context: any): any {
|
||||
const value = stmt.value && stmt.value.visitExpression(this, context);
|
||||
return this.transformStmt(
|
||||
new DeclareVarStmt(stmt.name, value, stmt.type, stmt.modifiers, stmt.sourceSpan), context);
|
||||
new DeclareVarStmt(
|
||||
stmt.name, value, stmt.type, stmt.modifiers, stmt.sourceSpan, stmt.leadingComments),
|
||||
context);
|
||||
}
|
||||
visitDeclareFunctionStmt(stmt: DeclareFunctionStmt, context: any): any {
|
||||
return this.transformStmt(
|
||||
new DeclareFunctionStmt(
|
||||
stmt.name, stmt.params, this.visitAllStatements(stmt.statements, context), stmt.type,
|
||||
stmt.modifiers, stmt.sourceSpan),
|
||||
stmt.modifiers, stmt.sourceSpan, stmt.leadingComments),
|
||||
context);
|
||||
}
|
||||
|
||||
visitExpressionStmt(stmt: ExpressionStatement, context: any): any {
|
||||
return this.transformStmt(
|
||||
new ExpressionStatement(stmt.expr.visitExpression(this, context), stmt.sourceSpan),
|
||||
new ExpressionStatement(
|
||||
stmt.expr.visitExpression(this, context), stmt.sourceSpan, stmt.leadingComments),
|
||||
context);
|
||||
}
|
||||
|
||||
visitReturnStmt(stmt: ReturnStatement, context: any): any {
|
||||
return this.transformStmt(
|
||||
new ReturnStatement(stmt.value.visitExpression(this, context), stmt.sourceSpan), context);
|
||||
new ReturnStatement(
|
||||
stmt.value.visitExpression(this, context), stmt.sourceSpan, stmt.leadingComments),
|
||||
context);
|
||||
}
|
||||
|
||||
visitDeclareClassStmt(stmt: ClassStmt, context: any): any {
|
||||
@ -1435,7 +1422,8 @@ export class AstTransformer implements StatementVisitor, ExpressionVisitor {
|
||||
new IfStmt(
|
||||
stmt.condition.visitExpression(this, context),
|
||||
this.visitAllStatements(stmt.trueCase, context),
|
||||
this.visitAllStatements(stmt.falseCase, context), stmt.sourceSpan),
|
||||
this.visitAllStatements(stmt.falseCase, context), stmt.sourceSpan,
|
||||
stmt.leadingComments),
|
||||
context);
|
||||
}
|
||||
|
||||
@ -1443,21 +1431,16 @@ export class AstTransformer implements StatementVisitor, ExpressionVisitor {
|
||||
return this.transformStmt(
|
||||
new TryCatchStmt(
|
||||
this.visitAllStatements(stmt.bodyStmts, context),
|
||||
this.visitAllStatements(stmt.catchStmts, context), stmt.sourceSpan),
|
||||
this.visitAllStatements(stmt.catchStmts, context), stmt.sourceSpan,
|
||||
stmt.leadingComments),
|
||||
context);
|
||||
}
|
||||
|
||||
visitThrowStmt(stmt: ThrowStmt, context: any): any {
|
||||
return this.transformStmt(
|
||||
new ThrowStmt(stmt.error.visitExpression(this, context), stmt.sourceSpan), context);
|
||||
}
|
||||
|
||||
visitCommentStmt(stmt: CommentStmt, context: any): any {
|
||||
return this.transformStmt(stmt, context);
|
||||
}
|
||||
|
||||
visitJSDocCommentStmt(stmt: JSDocCommentStmt, context: any): any {
|
||||
return this.transformStmt(stmt, context);
|
||||
new ThrowStmt(
|
||||
stmt.error.visitExpression(this, context), stmt.sourceSpan, stmt.leadingComments),
|
||||
context);
|
||||
}
|
||||
|
||||
visitAllStatements(stmts: Statement[], context: any): Statement[] {
|
||||
@ -1647,12 +1630,6 @@ export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor
|
||||
stmt.error.visitExpression(this, context);
|
||||
return stmt;
|
||||
}
|
||||
visitCommentStmt(stmt: CommentStmt, context: any): any {
|
||||
return stmt;
|
||||
}
|
||||
visitJSDocCommentStmt(stmt: JSDocCommentStmt, context: any): any {
|
||||
return stmt;
|
||||
}
|
||||
visitAllStatements(stmts: Statement[], context: any): void {
|
||||
stmts.forEach(stmt => stmt.visitStatement(this, context));
|
||||
}
|
||||
@ -1743,6 +1720,15 @@ class _ApplySourceSpanTransformer extends AstTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
export function leadingComment(
|
||||
text: string, multiline: boolean = false, trailingNewline: boolean = true): LeadingComment {
|
||||
return new LeadingComment(text, multiline, trailingNewline);
|
||||
}
|
||||
|
||||
export function jsDocComment(tags: JSDocTag[] = []): JSDocComment {
|
||||
return new JSDocComment(tags);
|
||||
}
|
||||
|
||||
export function variable(
|
||||
name: string, type?: Type|null, sourceSpan?: ParseSourceSpan|null): ReadVarExpr {
|
||||
return new ReadVarExpr(name, type, sourceSpan);
|
||||
@ -1755,14 +1741,13 @@ export function importExpr(
|
||||
}
|
||||
|
||||
export function importType(
|
||||
id: ExternalReference, typeParams: Type[]|null = null,
|
||||
typeModifiers: TypeModifier[]|null = null): ExpressionType|null {
|
||||
id: ExternalReference, typeParams?: Type[]|null,
|
||||
typeModifiers?: TypeModifier[]): ExpressionType|null {
|
||||
return id != null ? expressionType(importExpr(id, typeParams, null), typeModifiers) : null;
|
||||
}
|
||||
|
||||
export function expressionType(
|
||||
expr: Expression, typeModifiers: TypeModifier[]|null = null,
|
||||
typeParams: Type[]|null = null): ExpressionType {
|
||||
expr: Expression, typeModifiers?: TypeModifier[], typeParams?: Type[]|null): ExpressionType {
|
||||
return new ExpressionType(expr, typeModifiers, typeParams);
|
||||
}
|
||||
|
||||
@ -1802,8 +1787,10 @@ export function fn(
|
||||
return new FunctionExpr(params, body, type, sourceSpan, name);
|
||||
}
|
||||
|
||||
export function ifStmt(condition: Expression, thenClause: Statement[], elseClause?: Statement[]) {
|
||||
return new IfStmt(condition, thenClause, elseClause);
|
||||
export function ifStmt(
|
||||
condition: Expression, thenClause: Statement[], elseClause?: Statement[],
|
||||
sourceSpan?: ParseSourceSpan, leadingComments?: LeadingComment[]) {
|
||||
return new IfStmt(condition, thenClause, elseClause, sourceSpan, leadingComments);
|
||||
}
|
||||
|
||||
export function literal(
|
||||
@ -1865,10 +1852,15 @@ function tagToString(tag: JSDocTag): string {
|
||||
function serializeTags(tags: JSDocTag[]): string {
|
||||
if (tags.length === 0) return '';
|
||||
|
||||
if (tags.length === 1 && tags[0].tagName && !tags[0].text) {
|
||||
// The JSDOC comment is a single simple tag: e.g `/** @tagname */`.
|
||||
return `*${tagToString(tags[0])} `;
|
||||
}
|
||||
|
||||
let out = '*\n';
|
||||
for (const tag of tags) {
|
||||
out += ' *';
|
||||
// If the tagToString is multi-line, insert " * " prefixes on subsequent lines.
|
||||
// If the tagToString is multi-line, insert " * " prefixes on lines.
|
||||
out += tagToString(tag).replace(/\n/g, '\n * ');
|
||||
out += '\n';
|
||||
}
|
||||
|
@ -233,12 +233,6 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor {
|
||||
visitThrowStmt(stmt: o.ThrowStmt, ctx: _ExecutionContext): any {
|
||||
throw stmt.error.visitExpression(this, ctx);
|
||||
}
|
||||
visitCommentStmt(stmt: o.CommentStmt, context?: any): any {
|
||||
return null;
|
||||
}
|
||||
visitJSDocCommentStmt(stmt: o.JSDocCommentStmt, context?: any): any {
|
||||
return null;
|
||||
}
|
||||
visitInstantiateExpr(ast: o.InstantiateExpr, ctx: _ExecutionContext): any {
|
||||
const args = this.visitAllExpressions(ast.args, ctx);
|
||||
const clazz = ast.classExpr.visitExpression(this, ctx);
|
||||
|
@ -45,14 +45,14 @@ export function convertMetaToOutput(meta: any, ctx: OutputContext): o.Expression
|
||||
}
|
||||
|
||||
export function typeWithParameters(type: o.Expression, numParams: number): o.ExpressionType {
|
||||
let params: o.Type[]|null = null;
|
||||
if (numParams > 0) {
|
||||
params = [];
|
||||
for (let i = 0; i < numParams; i++) {
|
||||
params.push(o.DYNAMIC_TYPE);
|
||||
}
|
||||
if (numParams === 0) {
|
||||
return o.expressionType(type);
|
||||
}
|
||||
return o.expressionType(type, null, params);
|
||||
const params: o.Type[] = [];
|
||||
for (let i = 0; i < numParams; i++) {
|
||||
params.push(o.DYNAMIC_TYPE);
|
||||
}
|
||||
return o.expressionType(type, undefined, params);
|
||||
}
|
||||
|
||||
export interface R3Reference {
|
||||
|
@ -10,7 +10,7 @@ import {mapLiteral} from '../../../output/map_util';
|
||||
import * as o from '../../../output/output_ast';
|
||||
|
||||
import {serializeIcuNode} from './icu_serializer';
|
||||
import {i18nMetaToDocStmt} from './meta';
|
||||
import {i18nMetaToJSDoc} from './meta';
|
||||
import {formatI18nPlaceholderName} from './util';
|
||||
|
||||
/** Closure uses `goog.getMsg(message)` to lookup translations */
|
||||
@ -31,15 +31,13 @@ export function createGoogleGetMsgStatements(
|
||||
// */
|
||||
// const MSG_... = goog.getMsg(..);
|
||||
// I18N_X = MSG_...;
|
||||
const statements = [];
|
||||
const jsdocComment = i18nMetaToDocStmt(message);
|
||||
if (jsdocComment !== null) {
|
||||
statements.push(jsdocComment);
|
||||
const googGetMsgStmt = closureVar.set(o.variable(GOOG_GET_MSG).callFn(args)).toConstDecl();
|
||||
const metaComment = i18nMetaToJSDoc(message);
|
||||
if (metaComment !== null) {
|
||||
googGetMsgStmt.addLeadingComment(metaComment);
|
||||
}
|
||||
statements.push(closureVar.set(o.variable(GOOG_GET_MSG).callFn(args)).toConstDecl());
|
||||
statements.push(new o.ExpressionStatement(variable.set(closureVar)));
|
||||
|
||||
return statements;
|
||||
const i18nAssignmentStmt = new o.ExpressionStatement(variable.set(closureVar));
|
||||
return [googGetMsgStmt, i18nAssignmentStmt];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -231,7 +231,7 @@ export function parseI18nMeta(meta: string = ''): I18nMeta {
|
||||
|
||||
// Converts i18n meta information for a message (id, description, meaning)
|
||||
// to a JsDoc statement formatted as expected by the Closure compiler.
|
||||
export function i18nMetaToDocStmt(meta: I18nMeta): o.JSDocCommentStmt|null {
|
||||
export function i18nMetaToJSDoc(meta: I18nMeta): o.JSDocComment|null {
|
||||
const tags: o.JSDocTag[] = [];
|
||||
if (meta.description) {
|
||||
tags.push({tagName: o.JSDocTagName.Desc, text: meta.description});
|
||||
@ -239,5 +239,5 @@ export function i18nMetaToDocStmt(meta: I18nMeta): o.JSDocCommentStmt|null {
|
||||
if (meta.meaning) {
|
||||
tags.push({tagName: o.JSDocTagName.Meaning, text: meta.meaning});
|
||||
}
|
||||
return tags.length == 0 ? null : new o.JSDocCommentStmt(tags);
|
||||
return tags.length == 0 ? null : o.jsDocComment(tags);
|
||||
}
|
||||
|
@ -179,5 +179,5 @@ export function getTranslationConstPrefix(extra: string): string {
|
||||
*/
|
||||
export function declareI18nVariable(variable: o.ReadVarExpr): o.Statement {
|
||||
return new o.DeclareVarStmt(
|
||||
variable.name!, undefined, o.INFERRED_TYPE, null, variable.sourceSpan);
|
||||
variable.name!, undefined, o.INFERRED_TYPE, undefined, variable.sourceSpan);
|
||||
}
|
||||
|
@ -892,7 +892,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||
const templateFunctionExpr = templateVisitor.buildTemplateFunction(
|
||||
template.children, template.variables,
|
||||
this._ngContentReservedSlots.length + this._ngContentSelectorsOffset, template.i18n);
|
||||
this.constantPool.statements.push(templateFunctionExpr.toDeclStmt(templateName, null));
|
||||
this.constantPool.statements.push(templateFunctionExpr.toDeclStmt(templateName));
|
||||
if (templateVisitor._ngContentReservedSlots.length) {
|
||||
this._ngContentReservedSlots.push(...templateVisitor._ngContentReservedSlots);
|
||||
}
|
||||
|
Reference in New Issue
Block a user