UNPKG

@angular/compiler

Version:

Angular - the compiler library

1,215 lines • 184 kB
/** * @license * Copyright Google Inc. 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 */ //// Types export var TypeModifier; (function (TypeModifier) { TypeModifier[TypeModifier["Const"] = 0] = "Const"; })(TypeModifier || (TypeModifier = {})); export class Type { constructor(modifiers = null) { this.modifiers = modifiers; if (!modifiers) { this.modifiers = []; } } hasModifier(modifier) { return this.modifiers.indexOf(modifier) !== -1; } } export var BuiltinTypeName; (function (BuiltinTypeName) { BuiltinTypeName[BuiltinTypeName["Dynamic"] = 0] = "Dynamic"; BuiltinTypeName[BuiltinTypeName["Bool"] = 1] = "Bool"; BuiltinTypeName[BuiltinTypeName["String"] = 2] = "String"; BuiltinTypeName[BuiltinTypeName["Int"] = 3] = "Int"; BuiltinTypeName[BuiltinTypeName["Number"] = 4] = "Number"; BuiltinTypeName[BuiltinTypeName["Function"] = 5] = "Function"; BuiltinTypeName[BuiltinTypeName["Inferred"] = 6] = "Inferred"; BuiltinTypeName[BuiltinTypeName["None"] = 7] = "None"; })(BuiltinTypeName || (BuiltinTypeName = {})); export class BuiltinType extends Type { constructor(name, modifiers = null) { super(modifiers); this.name = name; } visitType(visitor, context) { return visitor.visitBuiltinType(this, context); } } export class ExpressionType extends Type { constructor(value, modifiers = null, typeParams = null) { super(modifiers); this.value = value; this.typeParams = typeParams; } visitType(visitor, context) { return visitor.visitExpressionType(this, context); } } export class ArrayType extends Type { constructor(of, modifiers = null) { super(modifiers); this.of = of; } visitType(visitor, context) { return visitor.visitArrayType(this, context); } } export class MapType extends Type { constructor(valueType, modifiers = null) { super(modifiers); this.valueType = valueType || null; } visitType(visitor, context) { return visitor.visitMapType(this, context); } } export const DYNAMIC_TYPE = new BuiltinType(BuiltinTypeName.Dynamic); export const INFERRED_TYPE = new BuiltinType(BuiltinTypeName.Inferred); export const BOOL_TYPE = new BuiltinType(BuiltinTypeName.Bool); export const INT_TYPE = new BuiltinType(BuiltinTypeName.Int); export const NUMBER_TYPE = new BuiltinType(BuiltinTypeName.Number); export const STRING_TYPE = new BuiltinType(BuiltinTypeName.String); export const FUNCTION_TYPE = new BuiltinType(BuiltinTypeName.Function); export const NONE_TYPE = new BuiltinType(BuiltinTypeName.None); ///// Expressions export var BinaryOperator; (function (BinaryOperator) { BinaryOperator[BinaryOperator["Equals"] = 0] = "Equals"; BinaryOperator[BinaryOperator["NotEquals"] = 1] = "NotEquals"; BinaryOperator[BinaryOperator["Identical"] = 2] = "Identical"; BinaryOperator[BinaryOperator["NotIdentical"] = 3] = "NotIdentical"; BinaryOperator[BinaryOperator["Minus"] = 4] = "Minus"; BinaryOperator[BinaryOperator["Plus"] = 5] = "Plus"; BinaryOperator[BinaryOperator["Divide"] = 6] = "Divide"; BinaryOperator[BinaryOperator["Multiply"] = 7] = "Multiply"; BinaryOperator[BinaryOperator["Modulo"] = 8] = "Modulo"; BinaryOperator[BinaryOperator["And"] = 9] = "And"; BinaryOperator[BinaryOperator["Or"] = 10] = "Or"; BinaryOperator[BinaryOperator["BitwiseAnd"] = 11] = "BitwiseAnd"; BinaryOperator[BinaryOperator["Lower"] = 12] = "Lower"; BinaryOperator[BinaryOperator["LowerEquals"] = 13] = "LowerEquals"; BinaryOperator[BinaryOperator["Bigger"] = 14] = "Bigger"; BinaryOperator[BinaryOperator["BiggerEquals"] = 15] = "BiggerEquals"; })(BinaryOperator || (BinaryOperator = {})); export function nullSafeIsEquivalent(base, other) { if (base == null || other == null) { return base == other; } return base.isEquivalent(other); } export function areAllEquivalent(base, other) { const len = base.length; if (len !== other.length) { return false; } for (let i = 0; i < len; i++) { if (!base[i].isEquivalent(other[i])) { return false; } } return true; } export class Expression { constructor(type, sourceSpan) { this.type = type || null; this.sourceSpan = sourceSpan || null; } prop(name, sourceSpan) { return new ReadPropExpr(this, name, null, sourceSpan); } key(index, type, sourceSpan) { return new ReadKeyExpr(this, index, type, sourceSpan); } callMethod(name, params, sourceSpan) { return new InvokeMethodExpr(this, name, params, null, sourceSpan); } callFn(params, sourceSpan) { return new InvokeFunctionExpr(this, params, null, sourceSpan); } instantiate(params, type, sourceSpan) { return new InstantiateExpr(this, params, type, sourceSpan); } conditional(trueCase, falseCase = null, sourceSpan) { return new ConditionalExpr(this, trueCase, falseCase, null, sourceSpan); } equals(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Equals, this, rhs, null, sourceSpan); } notEquals(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.NotEquals, this, rhs, null, sourceSpan); } identical(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Identical, this, rhs, null, sourceSpan); } notIdentical(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.NotIdentical, this, rhs, null, sourceSpan); } minus(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Minus, this, rhs, null, sourceSpan); } plus(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Plus, this, rhs, null, sourceSpan); } divide(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Divide, this, rhs, null, sourceSpan); } multiply(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Multiply, this, rhs, null, sourceSpan); } modulo(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Modulo, this, rhs, null, sourceSpan); } and(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.And, this, rhs, null, sourceSpan); } bitwiseAnd(rhs, sourceSpan, parens = true) { return new BinaryOperatorExpr(BinaryOperator.BitwiseAnd, this, rhs, null, sourceSpan, parens); } or(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Or, this, rhs, null, sourceSpan); } lower(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Lower, this, rhs, null, sourceSpan); } lowerEquals(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.LowerEquals, this, rhs, null, sourceSpan); } bigger(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.Bigger, this, rhs, null, sourceSpan); } biggerEquals(rhs, sourceSpan) { return new BinaryOperatorExpr(BinaryOperator.BiggerEquals, this, rhs, null, sourceSpan); } isBlank(sourceSpan) { // Note: We use equals by purpose here to compare to null and undefined in JS. // We use the typed null to allow strictNullChecks to narrow types. return this.equals(TYPED_NULL_EXPR, sourceSpan); } cast(type, sourceSpan) { return new CastExpr(this, type, sourceSpan); } toStmt() { return new ExpressionStatement(this, null); } } export var BuiltinVar; (function (BuiltinVar) { BuiltinVar[BuiltinVar["This"] = 0] = "This"; BuiltinVar[BuiltinVar["Super"] = 1] = "Super"; BuiltinVar[BuiltinVar["CatchError"] = 2] = "CatchError"; BuiltinVar[BuiltinVar["CatchStack"] = 3] = "CatchStack"; })(BuiltinVar || (BuiltinVar = {})); export class ReadVarExpr extends Expression { constructor(name, type, sourceSpan) { super(type, sourceSpan); if (typeof name === 'string') { this.name = name; this.builtin = null; } else { this.name = null; this.builtin = name; } } isEquivalent(e) { return e instanceof ReadVarExpr && this.name === e.name && this.builtin === e.builtin; } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitReadVarExpr(this, context); } set(value) { if (!this.name) { throw new Error(`Built in variable ${this.builtin} can not be assigned to.`); } return new WriteVarExpr(this.name, value, null, this.sourceSpan); } } export class TypeofExpr extends Expression { constructor(expr, type, sourceSpan) { super(type, sourceSpan); this.expr = expr; } visitExpression(visitor, context) { return visitor.visitTypeofExpr(this, context); } isEquivalent(e) { return e instanceof TypeofExpr && e.expr.isEquivalent(this.expr); } isConstant() { return this.expr.isConstant(); } } export class WrappedNodeExpr extends Expression { constructor(node, type, sourceSpan) { super(type, sourceSpan); this.node = node; } isEquivalent(e) { return e instanceof WrappedNodeExpr && this.node === e.node; } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitWrappedNodeExpr(this, context); } } export class WriteVarExpr extends Expression { constructor(name, value, type, sourceSpan) { super(type || value.type, sourceSpan); this.name = name; this.value = value; } isEquivalent(e) { return e instanceof WriteVarExpr && this.name === e.name && this.value.isEquivalent(e.value); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitWriteVarExpr(this, context); } toDeclStmt(type, modifiers) { return new DeclareVarStmt(this.name, this.value, type, modifiers, this.sourceSpan); } } export class WriteKeyExpr extends Expression { constructor(receiver, index, value, type, sourceSpan) { super(type || value.type, sourceSpan); this.receiver = receiver; this.index = index; this.value = value; } isEquivalent(e) { return e instanceof WriteKeyExpr && this.receiver.isEquivalent(e.receiver) && this.index.isEquivalent(e.index) && this.value.isEquivalent(e.value); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitWriteKeyExpr(this, context); } } export class WritePropExpr extends Expression { constructor(receiver, name, value, type, sourceSpan) { super(type || value.type, sourceSpan); this.receiver = receiver; this.name = name; this.value = value; } isEquivalent(e) { return e instanceof WritePropExpr && this.receiver.isEquivalent(e.receiver) && this.name === e.name && this.value.isEquivalent(e.value); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitWritePropExpr(this, context); } } export var BuiltinMethod; (function (BuiltinMethod) { BuiltinMethod[BuiltinMethod["ConcatArray"] = 0] = "ConcatArray"; BuiltinMethod[BuiltinMethod["SubscribeObservable"] = 1] = "SubscribeObservable"; BuiltinMethod[BuiltinMethod["Bind"] = 2] = "Bind"; })(BuiltinMethod || (BuiltinMethod = {})); export class InvokeMethodExpr extends Expression { constructor(receiver, method, args, type, sourceSpan) { super(type, sourceSpan); this.receiver = receiver; this.args = args; if (typeof method === 'string') { this.name = method; this.builtin = null; } else { this.name = null; this.builtin = method; } } isEquivalent(e) { return e instanceof InvokeMethodExpr && this.receiver.isEquivalent(e.receiver) && this.name === e.name && this.builtin === e.builtin && areAllEquivalent(this.args, e.args); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitInvokeMethodExpr(this, context); } } export class InvokeFunctionExpr extends Expression { constructor(fn, args, type, sourceSpan) { super(type, sourceSpan); this.fn = fn; this.args = args; } isEquivalent(e) { return e instanceof InvokeFunctionExpr && this.fn.isEquivalent(e.fn) && areAllEquivalent(this.args, e.args); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitInvokeFunctionExpr(this, context); } } export class InstantiateExpr extends Expression { constructor(classExpr, args, type, sourceSpan) { super(type, sourceSpan); this.classExpr = classExpr; this.args = args; } isEquivalent(e) { return e instanceof InstantiateExpr && this.classExpr.isEquivalent(e.classExpr) && areAllEquivalent(this.args, e.args); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitInstantiateExpr(this, context); } } export class LiteralExpr extends Expression { constructor(value, type, sourceSpan) { super(type, sourceSpan); this.value = value; } isEquivalent(e) { return e instanceof LiteralExpr && this.value === e.value; } isConstant() { return true; } visitExpression(visitor, context) { return visitor.visitLiteralExpr(this, context); } } export class ExternalExpr extends Expression { constructor(value, type, typeParams = null, sourceSpan) { super(type, sourceSpan); this.value = value; this.typeParams = typeParams; } isEquivalent(e) { return e instanceof ExternalExpr && this.value.name === e.value.name && this.value.moduleName === e.value.moduleName && this.value.runtime === e.value.runtime; } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitExternalExpr(this, context); } } export class ExternalReference { constructor(moduleName, name, runtime) { this.moduleName = moduleName; this.name = name; this.runtime = runtime; } } export class ConditionalExpr extends Expression { constructor(condition, trueCase, falseCase = null, type, sourceSpan) { super(type || trueCase.type, sourceSpan); this.condition = condition; this.falseCase = falseCase; this.trueCase = trueCase; } isEquivalent(e) { return e instanceof ConditionalExpr && this.condition.isEquivalent(e.condition) && this.trueCase.isEquivalent(e.trueCase) && nullSafeIsEquivalent(this.falseCase, e.falseCase); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitConditionalExpr(this, context); } } export class NotExpr extends Expression { constructor(condition, sourceSpan) { super(BOOL_TYPE, sourceSpan); this.condition = condition; } isEquivalent(e) { return e instanceof NotExpr && this.condition.isEquivalent(e.condition); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitNotExpr(this, context); } } export class AssertNotNull extends Expression { constructor(condition, sourceSpan) { super(condition.type, sourceSpan); this.condition = condition; } isEquivalent(e) { return e instanceof AssertNotNull && this.condition.isEquivalent(e.condition); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitAssertNotNullExpr(this, context); } } export class CastExpr extends Expression { constructor(value, type, sourceSpan) { super(type, sourceSpan); this.value = value; } isEquivalent(e) { return e instanceof CastExpr && this.value.isEquivalent(e.value); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitCastExpr(this, context); } } export class FnParam { constructor(name, type = null) { this.name = name; this.type = type; } isEquivalent(param) { return this.name === param.name; } } export class FunctionExpr extends Expression { constructor(params, statements, type, sourceSpan, name) { super(type, sourceSpan); this.params = params; this.statements = statements; this.name = name; } isEquivalent(e) { return e instanceof FunctionExpr && areAllEquivalent(this.params, e.params) && areAllEquivalent(this.statements, e.statements); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitFunctionExpr(this, context); } toDeclStmt(name, modifiers = null) { return new DeclareFunctionStmt(name, this.params, this.statements, this.type, modifiers, this.sourceSpan); } } export class BinaryOperatorExpr extends Expression { constructor(operator, lhs, rhs, type, sourceSpan, parens = true) { super(type || lhs.type, sourceSpan); this.operator = operator; this.rhs = rhs; this.parens = parens; this.lhs = lhs; } isEquivalent(e) { return e instanceof BinaryOperatorExpr && this.operator === e.operator && this.lhs.isEquivalent(e.lhs) && this.rhs.isEquivalent(e.rhs); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitBinaryOperatorExpr(this, context); } } export class ReadPropExpr extends Expression { constructor(receiver, name, type, sourceSpan) { super(type, sourceSpan); this.receiver = receiver; this.name = name; } isEquivalent(e) { return e instanceof ReadPropExpr && this.receiver.isEquivalent(e.receiver) && this.name === e.name; } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitReadPropExpr(this, context); } set(value) { return new WritePropExpr(this.receiver, this.name, value, null, this.sourceSpan); } } export class ReadKeyExpr extends Expression { constructor(receiver, index, type, sourceSpan) { super(type, sourceSpan); this.receiver = receiver; this.index = index; } isEquivalent(e) { return e instanceof ReadKeyExpr && this.receiver.isEquivalent(e.receiver) && this.index.isEquivalent(e.index); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitReadKeyExpr(this, context); } set(value) { return new WriteKeyExpr(this.receiver, this.index, value, null, this.sourceSpan); } } export class LiteralArrayExpr extends Expression { constructor(entries, type, sourceSpan) { super(type, sourceSpan); this.entries = entries; } isConstant() { return this.entries.every(e => e.isConstant()); } isEquivalent(e) { return e instanceof LiteralArrayExpr && areAllEquivalent(this.entries, e.entries); } visitExpression(visitor, context) { return visitor.visitLiteralArrayExpr(this, context); } } export class LiteralMapEntry { constructor(key, value, quoted) { this.key = key; this.value = value; this.quoted = quoted; } isEquivalent(e) { return this.key === e.key && this.value.isEquivalent(e.value); } } export class LiteralMapExpr extends Expression { constructor(entries, type, sourceSpan) { super(type, sourceSpan); this.entries = entries; this.valueType = null; if (type) { this.valueType = type.valueType; } } isEquivalent(e) { return e instanceof LiteralMapExpr && areAllEquivalent(this.entries, e.entries); } isConstant() { return this.entries.every(e => e.value.isConstant()); } visitExpression(visitor, context) { return visitor.visitLiteralMapExpr(this, context); } } export class CommaExpr extends Expression { constructor(parts, sourceSpan) { super(parts[parts.length - 1].type, sourceSpan); this.parts = parts; } isEquivalent(e) { return e instanceof CommaExpr && areAllEquivalent(this.parts, e.parts); } isConstant() { return false; } visitExpression(visitor, context) { return visitor.visitCommaExpr(this, context); } } export const THIS_EXPR = new ReadVarExpr(BuiltinVar.This, null, null); export const SUPER_EXPR = new ReadVarExpr(BuiltinVar.Super, null, null); export const CATCH_ERROR_VAR = new ReadVarExpr(BuiltinVar.CatchError, null, null); export const CATCH_STACK_VAR = new ReadVarExpr(BuiltinVar.CatchStack, null, null); export const NULL_EXPR = new LiteralExpr(null, null, null); export const TYPED_NULL_EXPR = new LiteralExpr(null, INFERRED_TYPE, null); //// Statements export var StmtModifier; (function (StmtModifier) { StmtModifier[StmtModifier["Final"] = 0] = "Final"; StmtModifier[StmtModifier["Private"] = 1] = "Private"; StmtModifier[StmtModifier["Exported"] = 2] = "Exported"; StmtModifier[StmtModifier["Static"] = 3] = "Static"; })(StmtModifier || (StmtModifier = {})); export class Statement { constructor(modifiers, sourceSpan) { this.modifiers = modifiers || []; this.sourceSpan = sourceSpan || null; } hasModifier(modifier) { return this.modifiers.indexOf(modifier) !== -1; } } export class DeclareVarStmt extends Statement { constructor(name, value, type, modifiers = null, sourceSpan) { super(modifiers, sourceSpan); this.name = name; this.value = value; this.type = type || (value && value.type) || null; } isEquivalent(stmt) { return stmt instanceof DeclareVarStmt && this.name === stmt.name && (this.value ? !!stmt.value && this.value.isEquivalent(stmt.value) : !stmt.value); } visitStatement(visitor, context) { return visitor.visitDeclareVarStmt(this, context); } } export class DeclareFunctionStmt extends Statement { constructor(name, params, statements, type, modifiers = null, sourceSpan) { super(modifiers, sourceSpan); this.name = name; this.params = params; this.statements = statements; this.type = type || null; } isEquivalent(stmt) { return stmt instanceof DeclareFunctionStmt && areAllEquivalent(this.params, stmt.params) && areAllEquivalent(this.statements, stmt.statements); } visitStatement(visitor, context) { return visitor.visitDeclareFunctionStmt(this, context); } } export class ExpressionStatement extends Statement { constructor(expr, sourceSpan) { super(null, sourceSpan); this.expr = expr; } isEquivalent(stmt) { return stmt instanceof ExpressionStatement && this.expr.isEquivalent(stmt.expr); } visitStatement(visitor, context) { return visitor.visitExpressionStmt(this, context); } } export class ReturnStatement extends Statement { constructor(value, sourceSpan) { super(null, sourceSpan); this.value = value; } isEquivalent(stmt) { return stmt instanceof ReturnStatement && this.value.isEquivalent(stmt.value); } visitStatement(visitor, context) { return visitor.visitReturnStmt(this, context); } } export class AbstractClassPart { constructor(type, modifiers) { this.modifiers = modifiers; if (!modifiers) { this.modifiers = []; } this.type = type || null; } hasModifier(modifier) { return this.modifiers.indexOf(modifier) !== -1; } } export class ClassField extends AbstractClassPart { constructor(name, type, modifiers = null, initializer) { super(type, modifiers); this.name = name; this.initializer = initializer; } isEquivalent(f) { return this.name === f.name; } } export class ClassMethod extends AbstractClassPart { constructor(name, params, body, type, modifiers = null) { super(type, modifiers); this.name = name; this.params = params; this.body = body; } isEquivalent(m) { return this.name === m.name && areAllEquivalent(this.body, m.body); } } export class ClassGetter extends AbstractClassPart { constructor(name, body, type, modifiers = null) { super(type, modifiers); this.name = name; this.body = body; } isEquivalent(m) { return this.name === m.name && areAllEquivalent(this.body, m.body); } } export class ClassStmt extends Statement { constructor(name, parent, fields, getters, constructorMethod, methods, modifiers = null, sourceSpan) { super(modifiers, sourceSpan); this.name = name; this.parent = parent; this.fields = fields; this.getters = getters; this.constructorMethod = constructorMethod; this.methods = methods; } isEquivalent(stmt) { return stmt instanceof ClassStmt && this.name === stmt.name && nullSafeIsEquivalent(this.parent, stmt.parent) && areAllEquivalent(this.fields, stmt.fields) && areAllEquivalent(this.getters, stmt.getters) && this.constructorMethod.isEquivalent(stmt.constructorMethod) && areAllEquivalent(this.methods, stmt.methods); } visitStatement(visitor, context) { return visitor.visitDeclareClassStmt(this, context); } } export class IfStmt extends Statement { constructor(condition, trueCase, falseCase = [], sourceSpan) { super(null, sourceSpan); this.condition = condition; this.trueCase = trueCase; this.falseCase = falseCase; } isEquivalent(stmt) { return stmt instanceof IfStmt && this.condition.isEquivalent(stmt.condition) && areAllEquivalent(this.trueCase, stmt.trueCase) && areAllEquivalent(this.falseCase, stmt.falseCase); } visitStatement(visitor, context) { return visitor.visitIfStmt(this, context); } } export class CommentStmt extends Statement { constructor(comment, multiline = false, sourceSpan) { super(null, sourceSpan); this.comment = comment; this.multiline = multiline; } isEquivalent(stmt) { return stmt instanceof CommentStmt; } visitStatement(visitor, context) { return visitor.visitCommentStmt(this, context); } } export class JSDocCommentStmt extends Statement { constructor(tags = [], sourceSpan) { super(null, sourceSpan); this.tags = tags; } isEquivalent(stmt) { return stmt instanceof JSDocCommentStmt && this.toString() === stmt.toString(); } visitStatement(visitor, context) { return visitor.visitJSDocCommentStmt(this, context); } toString() { return serializeTags(this.tags); } } export class TryCatchStmt extends Statement { constructor(bodyStmts, catchStmts, sourceSpan) { super(null, sourceSpan); this.bodyStmts = bodyStmts; this.catchStmts = catchStmts; } isEquivalent(stmt) { return stmt instanceof TryCatchStmt && areAllEquivalent(this.bodyStmts, stmt.bodyStmts) && areAllEquivalent(this.catchStmts, stmt.catchStmts); } visitStatement(visitor, context) { return visitor.visitTryCatchStmt(this, context); } } export class ThrowStmt extends Statement { constructor(error, sourceSpan) { super(null, sourceSpan); this.error = error; } isEquivalent(stmt) { return stmt instanceof TryCatchStmt && this.error.isEquivalent(stmt.error); } visitStatement(visitor, context) { return visitor.visitThrowStmt(this, context); } } export class AstTransformer { transformExpr(expr, context) { return expr; } transformStmt(stmt, context) { return stmt; } visitReadVarExpr(ast, context) { return this.transformExpr(ast, context); } visitWrappedNodeExpr(ast, context) { return this.transformExpr(ast, context); } visitTypeofExpr(expr, context) { return this.transformExpr(new TypeofExpr(expr.expr.visitExpression(this, context), expr.type, expr.sourceSpan), context); } visitWriteVarExpr(expr, context) { return this.transformExpr(new WriteVarExpr(expr.name, expr.value.visitExpression(this, context), expr.type, expr.sourceSpan), context); } visitWriteKeyExpr(expr, context) { return this.transformExpr(new WriteKeyExpr(expr.receiver.visitExpression(this, context), expr.index.visitExpression(this, context), expr.value.visitExpression(this, context), expr.type, expr.sourceSpan), context); } visitWritePropExpr(expr, context) { return this.transformExpr(new WritePropExpr(expr.receiver.visitExpression(this, context), expr.name, expr.value.visitExpression(this, context), expr.type, expr.sourceSpan), context); } visitInvokeMethodExpr(ast, context) { const method = ast.builtin || ast.name; return this.transformExpr(new InvokeMethodExpr(ast.receiver.visitExpression(this, context), method, this.visitAllExpressions(ast.args, context), ast.type, ast.sourceSpan), context); } visitInvokeFunctionExpr(ast, context) { return this.transformExpr(new InvokeFunctionExpr(ast.fn.visitExpression(this, context), this.visitAllExpressions(ast.args, context), ast.type, ast.sourceSpan), context); } visitInstantiateExpr(ast, context) { return this.transformExpr(new InstantiateExpr(ast.classExpr.visitExpression(this, context), this.visitAllExpressions(ast.args, context), ast.type, ast.sourceSpan), context); } visitLiteralExpr(ast, context) { return this.transformExpr(ast, context); } visitExternalExpr(ast, context) { return this.transformExpr(ast, context); } visitConditionalExpr(ast, context) { return this.transformExpr(new ConditionalExpr(ast.condition.visitExpression(this, context), ast.trueCase.visitExpression(this, context), ast.falseCase.visitExpression(this, context), ast.type, ast.sourceSpan), context); } visitNotExpr(ast, context) { return this.transformExpr(new NotExpr(ast.condition.visitExpression(this, context), ast.sourceSpan), context); } visitAssertNotNullExpr(ast, context) { return this.transformExpr(new AssertNotNull(ast.condition.visitExpression(this, context), ast.sourceSpan), context); } visitCastExpr(ast, context) { return this.transformExpr(new CastExpr(ast.value.visitExpression(this, context), ast.type, ast.sourceSpan), context); } visitFunctionExpr(ast, context) { return this.transformExpr(new FunctionExpr(ast.params, this.visitAllStatements(ast.statements, context), ast.type, ast.sourceSpan), context); } visitBinaryOperatorExpr(ast, context) { return this.transformExpr(new BinaryOperatorExpr(ast.operator, ast.lhs.visitExpression(this, context), ast.rhs.visitExpression(this, context), ast.type, ast.sourceSpan), context); } visitReadPropExpr(ast, context) { return this.transformExpr(new ReadPropExpr(ast.receiver.visitExpression(this, context), ast.name, ast.type, ast.sourceSpan), context); } visitReadKeyExpr(ast, context) { return this.transformExpr(new ReadKeyExpr(ast.receiver.visitExpression(this, context), ast.index.visitExpression(this, context), ast.type, ast.sourceSpan), context); } visitLiteralArrayExpr(ast, context) { return this.transformExpr(new LiteralArrayExpr(this.visitAllExpressions(ast.entries, context), ast.type, ast.sourceSpan), context); } visitLiteralMapExpr(ast, context) { const entries = ast.entries.map((entry) => new LiteralMapEntry(entry.key, entry.value.visitExpression(this, context), entry.quoted)); const mapType = new MapType(ast.valueType, null); return this.transformExpr(new LiteralMapExpr(entries, mapType, ast.sourceSpan), context); } visitCommaExpr(ast, context) { return this.transformExpr(new CommaExpr(this.visitAllExpressions(ast.parts, context), ast.sourceSpan), context); } visitAllExpressions(exprs, context) { return exprs.map(expr => expr.visitExpression(this, context)); } visitDeclareVarStmt(stmt, context) { const value = stmt.value && stmt.value.visitExpression(this, context); return this.transformStmt(new DeclareVarStmt(stmt.name, value, stmt.type, stmt.modifiers, stmt.sourceSpan), context); } visitDeclareFunctionStmt(stmt, context) { return this.transformStmt(new DeclareFunctionStmt(stmt.name, stmt.params, this.visitAllStatements(stmt.statements, context), stmt.type, stmt.modifiers, stmt.sourceSpan), context); } visitExpressionStmt(stmt, context) { return this.transformStmt(new ExpressionStatement(stmt.expr.visitExpression(this, context), stmt.sourceSpan), context); } visitReturnStmt(stmt, context) { return this.transformStmt(new ReturnStatement(stmt.value.visitExpression(this, context), stmt.sourceSpan), context); } visitDeclareClassStmt(stmt, context) { const parent = stmt.parent.visitExpression(this, context); const getters = stmt.getters.map(getter => new ClassGetter(getter.name, this.visitAllStatements(getter.body, context), getter.type, getter.modifiers)); const ctorMethod = stmt.constructorMethod && new ClassMethod(stmt.constructorMethod.name, stmt.constructorMethod.params, this.visitAllStatements(stmt.constructorMethod.body, context), stmt.constructorMethod.type, stmt.constructorMethod.modifiers); const methods = stmt.methods.map(method => new ClassMethod(method.name, method.params, this.visitAllStatements(method.body, context), method.type, method.modifiers)); return this.transformStmt(new ClassStmt(stmt.name, parent, stmt.fields, getters, ctorMethod, methods, stmt.modifiers, stmt.sourceSpan), context); } visitIfStmt(stmt, context) { return this.transformStmt(new IfStmt(stmt.condition.visitExpression(this, context), this.visitAllStatements(stmt.trueCase, context), this.visitAllStatements(stmt.falseCase, context), stmt.sourceSpan), context); } visitTryCatchStmt(stmt, context) { return this.transformStmt(new TryCatchStmt(this.visitAllStatements(stmt.bodyStmts, context), this.visitAllStatements(stmt.catchStmts, context), stmt.sourceSpan), context); } visitThrowStmt(stmt, context) { return this.transformStmt(new ThrowStmt(stmt.error.visitExpression(this, context), stmt.sourceSpan), context); } visitCommentStmt(stmt, context) { return this.transformStmt(stmt, context); } visitJSDocCommentStmt(stmt, context) { return this.transformStmt(stmt, context); } visitAllStatements(stmts, context) { return stmts.map(stmt => stmt.visitStatement(this, context)); } } export class RecursiveAstVisitor { visitType(ast, context) { return ast; } visitExpression(ast, context) { if (ast.type) { ast.type.visitType(this, context); } return ast; } visitBuiltinType(type, context) { return this.visitType(type, context); } visitExpressionType(type, context) { type.value.visitExpression(this, context); if (type.typeParams !== null) { type.typeParams.forEach(param => this.visitType(param, context)); } return this.visitType(type, context); } visitArrayType(type, context) { return this.visitType(type, context); } visitMapType(type, context) { return this.visitType(type, context); } visitWrappedNodeExpr(ast, context) { return ast; } visitTypeofExpr(ast, context) { return this.visitExpression(ast, context); } visitReadVarExpr(ast, context) { return this.visitExpression(ast, context); } visitWriteVarExpr(ast, context) { ast.value.visitExpression(this, context); return this.visitExpression(ast, context); } visitWriteKeyExpr(ast, context) { ast.receiver.visitExpression(this, context); ast.index.visitExpression(this, context); ast.value.visitExpression(this, context); return this.visitExpression(ast, context); } visitWritePropExpr(ast, context) { ast.receiver.visitExpression(this, context); ast.value.visitExpression(this, context); return this.visitExpression(ast, context); } visitInvokeMethodExpr(ast, context) { ast.receiver.visitExpression(this, context); this.visitAllExpressions(ast.args, context); return this.visitExpression(ast, context); } visitInvokeFunctionExpr(ast, context) { ast.fn.visitExpression(this, context); this.visitAllExpressions(ast.args, context); return this.visitExpression(ast, context); } visitInstantiateExpr(ast, context) { ast.classExpr.visitExpression(this, context); this.visitAllExpressions(ast.args, context); return this.visitExpression(ast, context); } visitLiteralExpr(ast, context) { return this.visitExpression(ast, context); } visitExternalExpr(ast, context) { if (ast.typeParams) { ast.typeParams.forEach(type => type.visitType(this, context)); } return this.visitExpression(ast, context); } visitConditionalExpr(ast, context) { ast.condition.visitExpression(this, context); ast.trueCase.visitExpression(this, context); ast.falseCase.visitExpression(this, context); return this.visitExpression(ast, context); } visitNotExpr(ast, context) { ast.condition.visitExpression(this, context); return this.visitExpression(ast, context); } visitAssertNotNullExpr(ast, context) { ast.condition.visitExpression(this, context); return this.visitExpression(ast, context); } visitCastExpr(ast, context) { ast.value.visitExpression(this, context); return this.visitExpression(ast, context); } visitFunctionExpr(ast, context) { this.visitAllStatements(ast.statements, context); return this.visitExpression(ast, context); } visitBinaryOperatorExpr(ast, context) { ast.lhs.visitExpression(this, context); ast.rhs.visitExpression(this, context); return this.visitExpression(ast, context); } visitReadPropExpr(ast, context) { ast.receiver.visitExpression(this, context); return this.visitExpression(ast, context); } visitReadKeyExpr(ast, context) { ast.receiver.visitExpression(this, context); ast.index.visitExpression(this, context); return this.visitExpression(ast, context); } visitLiteralArrayExpr(ast, context) { this.visitAllExpressions(ast.entries, context); return this.visitExpression(ast, context); } visitLiteralMapExpr(ast, context) { ast.entries.forEach((entry) => entry.value.visitExpression(this, context)); return this.visitExpression(ast, context); } visitCommaExpr(ast, context) { this.visitAllExpressions(ast.parts, context); return this.visitExpression(ast, context); } visitAllExpressions(exprs, context) { exprs.forEach(expr => expr.visitExpression(this, context)); } visitDeclareVarStmt(stmt, context) { if (stmt.value) { stmt.value.visitExpression(this, context); } if (stmt.type) { stmt.type.visitType(this, context); } return stmt; } visitDeclareFunctionStmt(stmt, context) { this.visitAllStatements(stmt.statements, context); if (stmt.type) { stmt.type.visitType(this, context); } return stmt; } visitExpressionStmt(stmt, context) { stmt.expr.visitExpression(this, context); return stmt; } visitReturnStmt(stmt, context) { stmt.value.visitExpression(this, context); return stmt; } visitDeclareClassStmt(stmt, context) { stmt.parent.visitExpression(this, context); stmt.getters.forEach(getter => this.visitAllStatements(getter.body, context)); if (stmt.constructorMethod) { this.visitAllStatements(stmt.constructorMethod.body, context); } stmt.methods.forEach(method => this.visitAllStatements(method.body, context)); return stmt; } visitIfStmt(stmt, context) { stmt.condition.visitExpression(this, context); this.visitAllStatements(stmt.trueCase, context); this.visitAllStatements(stmt.falseCase, context); return stmt; } visitTryCatchStmt(stmt, context) { this.visitAllStatements(stmt.bodyStmts, context); this.visitAllStatements(stmt.catchStmts, context); return stmt; } visitThrowStmt(stmt, context) { stmt.error.visitExpression(this, context); return stmt; } visitCommentStmt(stmt, context) { return stmt; } visitJSDocCommentStmt(stmt, context) { return stmt; } visitAllStatements(stmts, context) { stmts.forEach(stmt => stmt.visitStatement(this, context)); } } export function findReadVarNames(stmts) { const visitor = new _ReadVarVisitor(); visitor.visitAllStatements(stmts, null); return visitor.varNames; } class _ReadVarVisitor extends RecursiveAstVisitor { constructor() { super(...arguments); this.varNames = new Set(); } visitDeclareFunctionStmt(stmt, context) { // Don't descend into nested functions return stmt; } visitDeclareClassStmt(stmt, context) { // Don't descend into nested classes return stmt; } visitReadVarExpr(ast, context) { if (ast.name) { this.varNames.add(ast.name); } return null; } } export function collectExternalReferences(stmts) { const visitor = new _FindExternalReferencesVisitor(); visitor.visitAllStatements(stmts, null); return visitor.externalReferences; } class _FindExternalReferencesVisitor extends RecursiveAstVisitor { constructor() { super(...arguments); this.externalReferences = []; } visitExternalExpr(e, context) { this.externalReferences.push(e.value); return super.visitExternalExpr(e, context); } } export function applySourceSpanToStatementIfNeeded(stmt, sourceSpan) { if (!sourceSpan) { return stmt; } const transformer = new _ApplySourceSpanTransformer(sourceSpan); return stmt.visitStatement(transformer, null); } export function applySourceSpanToExpressionIfNeeded(expr, sourceSpan) { if (!sourceSpan) { return expr; } const transformer = new _ApplySourceSpanTransformer(sourceSpan); return expr.visitExpression(transformer, null); } class _ApplySourceSpanTransformer extends AstTransformer { constructor(sourceSpan) { super(); this.sourceSpan = sourceSpan; } _clone(obj) { const clone = Object.create(obj.constructor.prototype); for (let prop in obj) { clone[prop] = obj[prop]; } return clone; } transformExpr(expr, context) { if (!expr.sourceSpan) { expr = this._clone(expr); expr.sourceSpan = this.sourceSpan; } return expr; } transformStmt(stmt, context) { if (!stmt.sourceSpan) { stmt = this._clone(stmt); stmt.sourceSpan = this.sourceSpan; } return stmt; } } export function variable(name, type, sourceSpan) { return new ReadVarExpr(name, type, sourceSpan); } export function importExpr(id, typeParams = null, sourceSpan) { return new ExternalExpr(id, null, typeParams, sourceSpan); } export function importType(id, typeParams = null, typeModifiers = null) { return id != null ? expressionType(importExpr(id, typeParams, null), typeModifiers) : null; } export function expressionType(expr, typeModifiers = null, typeParams = null) { return new ExpressionType(expr, typeModifiers, typeParams); } export function typeofExpr(expr) { return new TypeofExpr(expr); } export function literalArr(values, type, sourceSpan) { return new LiteralArrayExpr(values, type, sourceSpan); } export function literalMap(values, type = null) { return new LiteralMapExpr(values.map(e => new LiteralMapEntry(e.key, e.value, e.quoted)), type, null); } export function not(expr, sourceSpan) { return new NotExpr(expr, sourceSpan); } export function assertNotNull(expr, sourceSpan) { return new AssertNotNull(expr, sourceSpan); } export function fn(params, body, type, sourceSpan, name) { return new FunctionExpr(params, body, type, sourceSpan, name); } export function ifStmt(condition, thenClause, elseClause) { return new IfStmt(condition, thenClause, elseClause); } export function literal(value, type, sourceSpan) { return new LiteralExpr(value, type, sourceSpan); } export function isNull(exp) { return exp instanceof LiteralExpr && exp.value === null; } /* * Serializes a `Tag` into a string. * Returns a string like " @foo {bar} baz" (note the leading whitespace before `@foo`). */ function tagToString(tag) { let out = ''; if (tag.tagName) { out += ` @${tag.tagName}`; } if (tag.text) { if (tag.text.match(/\/\*|\*\//)) { throw new Error('JSDoc text cannot contain "/*" and "*/"'); } out += ' ' + tag.text.replace(/@/g, '\\@'); } return out; } function serializeTags(tags) { if (tags.length === 0) return ''; let out = '*\n'; for (const tag of tags) { out += ' *'; // If the tagToString is multi-line, insert " * " prefixes on subsequent lines. out += tagToString(tag).replace(/\n/g, '\n * '); out += '\n'; } out += ' '; return out; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3V0cHV0X2FzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2NvbXBpbGVyL3NyYy9vdXRwdXQvb3V0cHV0X2FzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFNSCxVQUFVO0FBQ1YsTUFBTSxDQUFOLElBQVksWUFFWDtBQUZELFdBQVksWUFBWTtJQUN0QixpREFBSyxDQUFBO0FBQ1AsQ0FBQyxFQUZXLFlBQVksS0FBWixZQUFZLFFBRXZCO0FBRUQsTUFBTTtJQUNKLFlBQW1CLFlBQWlDLElBQUk7UUFBckMsY0FBUyxHQUFULFNBQVMsQ0FBNEI7UUFDdEQsSUFBSSxDQUFDLFNBQVMsRUFBRTtZQUNkLElBQUksQ0FBQyxTQUFTLEdBQUcsRUFBRSxDQUFDO1NBQ3JCO0lBQ0gsQ0FBQztJQUdELFdBQVcsQ0FBQyxRQUFzQixJQUFhLE9BQU8sSUFBSSxDQUFDLFNBQVcsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0NBQ25HO0FBRUQsTUFBTSxDQUFOLElBQVksZUFTWDtBQVRELFdBQVksZUFBZTtJQUN6QiwyREFBTyxDQUFBO0lBQ1AscURBQUksQ0FBQTtJQUNKLHlEQUFNLENBQUE7SUFDTixtREFBRyxDQUFBO0lBQ0gseURBQU0sQ0FBQTtJQUNOLDZEQUFRLENBQUE7SUFDUiw2REFBUSxDQUFBO0lBQ1IscURBQUksQ0FBQTtBQUNOLENBQUMsRUFUVyxlQUFlLEtBQWYsZUFBZSxRQVMxQjtBQUVELE1BQU0sa0JBQW1CLFNBQVEsSUFBSTtJQUNuQyxZQUFtQixJQUFxQixFQUFFLFlBQWlDLElBQUk7UUFDN0UsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBREEsU0FBSSxHQUFKLElBQUksQ0FBaUI7SUFFeEMsQ0FBQztJQUNELFNBQVMsQ0FBQyxPQUFvQixFQUFFLE9BQVk7UUFDMUMsT0FBTyxPQUFPLENBQUMs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