
BREAKING CHANGE: - Renderer: * renderComponent method is removed form `Renderer`, only present on `RootRenderer` * Renderer.setDebugInfo is removed. Renderer.createElement / createText / createTemplateAnchor now take the DebugInfo directly. - Query semantics: * Queries don't work with dynamically loaded components. * e.g. for router-outlet: loaded components can't be queries via @ViewQuery, but router-outlet emits an event `activate` now that emits the activated component - Exception classes and the context inside changed (renamed fields) - DebugElement.attributes is an Object and not a Map in JS any more - ChangeDetectorGenConfig was renamed into CompilerConfig - AppViewManager.createEmbeddedViewInContainer / AppViewManager.createHostViewInContainer are removed, use the methods in ViewContainerRef instead - Change detection order changed: * 1. dirty check component inputs * 2. dirty check content children * 3. update render nodes Closes #6301 Closes #6567
378 lines
11 KiB
TypeScript
378 lines
11 KiB
TypeScript
import {
|
|
StringWrapper,
|
|
RegExpWrapper,
|
|
isPresent,
|
|
isBlank,
|
|
Math,
|
|
isString,
|
|
isArray
|
|
} from 'angular2/src/facade/lang';
|
|
import {ListWrapper} from 'angular2/src/facade/collection';
|
|
import {BaseException} from 'angular2/src/facade/exceptions';
|
|
import {CompileIdentifierMetadata} from '../compile_metadata';
|
|
import * as o from './output_ast';
|
|
import {
|
|
OutputEmitter,
|
|
EmitterVisitorContext,
|
|
AbstractEmitterVisitor,
|
|
CATCH_ERROR_VAR,
|
|
CATCH_STACK_VAR,
|
|
escapeSingleQuoteString
|
|
} from './abstract_emitter';
|
|
import {getImportModulePath, ImportEnv} from './path_util';
|
|
|
|
var _debugModuleUrl = 'asset://debug/lib';
|
|
|
|
export function debugOutputAstAsDart(ast: o.Statement | o.Expression | o.Type | any[]): string {
|
|
var converter = new _DartEmitterVisitor(_debugModuleUrl);
|
|
var ctx = EmitterVisitorContext.createRoot([]);
|
|
var asts: any[];
|
|
if (isArray(ast)) {
|
|
asts = <any[]>ast;
|
|
} else {
|
|
asts = [ast];
|
|
}
|
|
asts.forEach((ast) => {
|
|
if (ast instanceof o.Statement) {
|
|
ast.visitStatement(converter, ctx);
|
|
} else if (ast instanceof o.Expression) {
|
|
ast.visitExpression(converter, ctx);
|
|
} else if (ast instanceof o.Type) {
|
|
ast.visitType(converter, ctx);
|
|
} else {
|
|
throw new BaseException(`Don't know how to print debug info for ${ast}`);
|
|
}
|
|
});
|
|
return ctx.toSource();
|
|
}
|
|
|
|
export class DartEmitter implements OutputEmitter {
|
|
constructor() {}
|
|
emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string {
|
|
var srcParts = [];
|
|
// Note: We are not creating a library here as Dart does not need it.
|
|
// Dart analzyer might complain about it though.
|
|
|
|
var converter = new _DartEmitterVisitor(moduleUrl);
|
|
var ctx = EmitterVisitorContext.createRoot(exportedVars);
|
|
converter.visitAllStatements(stmts, ctx);
|
|
|
|
converter.importsWithPrefixes.forEach((prefix, importedModuleUrl) => {
|
|
srcParts.push(
|
|
`import '${getImportModulePath(moduleUrl, importedModuleUrl, ImportEnv.Dart)}' as ${prefix};`);
|
|
});
|
|
srcParts.push(ctx.toSource());
|
|
return srcParts.join('\n');
|
|
}
|
|
}
|
|
|
|
class _DartEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor {
|
|
importsWithPrefixes = new Map<string, string>();
|
|
|
|
constructor(private _moduleUrl: string) { super(true); }
|
|
|
|
visitExternalExpr(ast: o.ExternalExpr, ctx: EmitterVisitorContext): any {
|
|
this._visitIdentifier(ast.value, ast.typeParams, ctx);
|
|
return null;
|
|
}
|
|
visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any {
|
|
if (stmt.hasModifier(o.StmtModifier.Final)) {
|
|
if (isConstType(stmt.type)) {
|
|
ctx.print(`const `);
|
|
} else {
|
|
ctx.print(`final `);
|
|
}
|
|
} else if (isBlank(stmt.type)) {
|
|
ctx.print(`var `);
|
|
}
|
|
if (isPresent(stmt.type)) {
|
|
stmt.type.visitType(this, ctx);
|
|
ctx.print(` `);
|
|
}
|
|
ctx.print(`${stmt.name} = `);
|
|
stmt.value.visitExpression(this, ctx);
|
|
ctx.println(`;`);
|
|
return null;
|
|
}
|
|
visitCastExpr(ast: o.CastExpr, ctx: EmitterVisitorContext): any {
|
|
ctx.print(`(`);
|
|
ast.value.visitExpression(this, ctx);
|
|
ctx.print(` as `);
|
|
ast.type.visitType(this, ctx);
|
|
ctx.print(`)`);
|
|
return null;
|
|
}
|
|
visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any {
|
|
ctx.pushClass(stmt);
|
|
ctx.print(`class ${stmt.name}`);
|
|
if (isPresent(stmt.parent)) {
|
|
ctx.print(` extends `);
|
|
stmt.parent.visitExpression(this, ctx);
|
|
}
|
|
ctx.println(` {`);
|
|
ctx.incIndent();
|
|
stmt.fields.forEach((field) => this._visitClassField(field, ctx));
|
|
if (isPresent(stmt.constructorMethod)) {
|
|
this._visitClassConstructor(stmt, ctx);
|
|
}
|
|
stmt.getters.forEach((getter) => this._visitClassGetter(getter, ctx));
|
|
stmt.methods.forEach((method) => this._visitClassMethod(method, ctx));
|
|
ctx.decIndent();
|
|
ctx.println(`}`);
|
|
ctx.popClass();
|
|
return null;
|
|
}
|
|
private _visitClassField(field: o.ClassField, ctx: EmitterVisitorContext) {
|
|
if (field.hasModifier(o.StmtModifier.Final)) {
|
|
ctx.print(`final `);
|
|
} else if (isBlank(field.type)) {
|
|
ctx.print(`var `);
|
|
}
|
|
if (isPresent(field.type)) {
|
|
field.type.visitType(this, ctx);
|
|
ctx.print(` `);
|
|
}
|
|
ctx.println(`${field.name};`);
|
|
}
|
|
private _visitClassGetter(getter: o.ClassGetter, ctx: EmitterVisitorContext) {
|
|
if (isPresent(getter.type)) {
|
|
getter.type.visitType(this, ctx);
|
|
ctx.print(` `);
|
|
}
|
|
ctx.println(`get ${getter.name} {`);
|
|
ctx.incIndent();
|
|
this.visitAllStatements(getter.body, ctx);
|
|
ctx.decIndent();
|
|
ctx.println(`}`);
|
|
}
|
|
private _visitClassConstructor(stmt: o.ClassStmt, ctx: EmitterVisitorContext) {
|
|
ctx.print(`${stmt.name}(`);
|
|
this._visitParams(stmt.constructorMethod.params, ctx);
|
|
ctx.print(`)`);
|
|
|
|
var ctorStmts = stmt.constructorMethod.body;
|
|
var superCtorExpr = ctorStmts.length > 0 ? getSuperConstructorCallExpr(ctorStmts[0]) : null;
|
|
if (isPresent(superCtorExpr)) {
|
|
ctx.print(`: `);
|
|
superCtorExpr.visitExpression(this, ctx);
|
|
ctorStmts = ctorStmts.slice(1);
|
|
}
|
|
ctx.println(` {`);
|
|
ctx.incIndent();
|
|
this.visitAllStatements(ctorStmts, ctx);
|
|
ctx.decIndent();
|
|
ctx.println(`}`);
|
|
}
|
|
private _visitClassMethod(method: o.ClassMethod, ctx: EmitterVisitorContext) {
|
|
if (isPresent(method.type)) {
|
|
method.type.visitType(this, ctx);
|
|
} else {
|
|
ctx.print(`void`);
|
|
}
|
|
ctx.print(` ${method.name}(`);
|
|
this._visitParams(method.params, ctx);
|
|
ctx.println(`) {`);
|
|
ctx.incIndent();
|
|
this.visitAllStatements(method.body, ctx);
|
|
ctx.decIndent();
|
|
ctx.println(`}`);
|
|
}
|
|
|
|
visitFunctionExpr(ast: o.FunctionExpr, ctx: EmitterVisitorContext): any {
|
|
ctx.print(`(`);
|
|
this._visitParams(ast.params, ctx);
|
|
ctx.println(`) {`);
|
|
ctx.incIndent();
|
|
this.visitAllStatements(ast.statements, ctx);
|
|
ctx.decIndent();
|
|
ctx.print(`}`);
|
|
return null;
|
|
}
|
|
visitDeclareFunctionStmt(stmt: o.DeclareFunctionStmt, ctx: EmitterVisitorContext): any {
|
|
if (isPresent(stmt.type)) {
|
|
stmt.type.visitType(this, ctx);
|
|
} else {
|
|
ctx.print(`void`);
|
|
}
|
|
ctx.print(` ${stmt.name}(`);
|
|
this._visitParams(stmt.params, ctx);
|
|
ctx.println(`) {`);
|
|
ctx.incIndent();
|
|
this.visitAllStatements(stmt.statements, ctx);
|
|
ctx.decIndent();
|
|
ctx.println(`}`);
|
|
return null;
|
|
}
|
|
|
|
getBuiltinMethodName(method: o.BuiltinMethod): string {
|
|
var name;
|
|
switch (method) {
|
|
case o.BuiltinMethod.ConcatArray:
|
|
name = '.addAll';
|
|
break;
|
|
case o.BuiltinMethod.SubscribeObservable:
|
|
name = 'listen';
|
|
break;
|
|
default:
|
|
throw new BaseException(`Unknown builtin method: ${method}`);
|
|
}
|
|
return name;
|
|
}
|
|
visitTryCatchStmt(stmt: o.TryCatchStmt, ctx: EmitterVisitorContext): any {
|
|
ctx.println(`try {`);
|
|
ctx.incIndent();
|
|
this.visitAllStatements(stmt.bodyStmts, ctx);
|
|
ctx.decIndent();
|
|
ctx.println(`} catch (${CATCH_ERROR_VAR.name}, ${CATCH_STACK_VAR.name}) {`);
|
|
ctx.incIndent();
|
|
this.visitAllStatements(stmt.catchStmts, ctx);
|
|
ctx.decIndent();
|
|
ctx.println(`}`);
|
|
return null;
|
|
}
|
|
visitBinaryOperatorExpr(ast: o.BinaryOperatorExpr, ctx: EmitterVisitorContext): any {
|
|
switch (ast.operator) {
|
|
case o.BinaryOperator.Identical:
|
|
ctx.print(`identical(`);
|
|
ast.lhs.visitExpression(this, ctx);
|
|
ctx.print(`, `);
|
|
ast.rhs.visitExpression(this, ctx);
|
|
ctx.print(`)`);
|
|
break;
|
|
case o.BinaryOperator.NotIdentical:
|
|
ctx.print(`!identical(`);
|
|
ast.lhs.visitExpression(this, ctx);
|
|
ctx.print(`, `);
|
|
ast.rhs.visitExpression(this, ctx);
|
|
ctx.print(`)`);
|
|
break;
|
|
default:
|
|
super.visitBinaryOperatorExpr(ast, ctx);
|
|
}
|
|
return null;
|
|
}
|
|
visitLiteralArrayExpr(ast: o.LiteralArrayExpr, ctx: EmitterVisitorContext): any {
|
|
if (isConstType(ast.type)) {
|
|
ctx.print(`const `);
|
|
}
|
|
return super.visitLiteralArrayExpr(ast, ctx);
|
|
}
|
|
visitLiteralMapExpr(ast: o.LiteralMapExpr, ctx: EmitterVisitorContext): any {
|
|
if (isConstType(ast.type)) {
|
|
ctx.print(`const `);
|
|
}
|
|
if (isPresent(ast.valueType)) {
|
|
ctx.print(`<String, `);
|
|
ast.valueType.visitType(this, ctx);
|
|
ctx.print(`>`);
|
|
}
|
|
return super.visitLiteralMapExpr(ast, ctx);
|
|
}
|
|
visitInstantiateExpr(ast: o.InstantiateExpr, ctx: EmitterVisitorContext): any {
|
|
ctx.print(isConstType(ast.type) ? `const` : `new`);
|
|
ctx.print(' ');
|
|
ast.classExpr.visitExpression(this, ctx);
|
|
ctx.print(`(`);
|
|
this.visitAllExpressions(ast.args, ctx, `,`);
|
|
ctx.print(`)`);
|
|
return null;
|
|
}
|
|
visitBuiltintType(type: o.BuiltinType, ctx: EmitterVisitorContext): any {
|
|
var typeStr;
|
|
switch (type.name) {
|
|
case o.BuiltinTypeName.Bool:
|
|
typeStr = 'bool';
|
|
break;
|
|
case o.BuiltinTypeName.Dynamic:
|
|
typeStr = 'dynamic';
|
|
break;
|
|
case o.BuiltinTypeName.Function:
|
|
typeStr = 'Function';
|
|
break;
|
|
case o.BuiltinTypeName.Number:
|
|
typeStr = 'num';
|
|
break;
|
|
case o.BuiltinTypeName.Int:
|
|
typeStr = 'int';
|
|
break;
|
|
case o.BuiltinTypeName.String:
|
|
typeStr = 'String';
|
|
break;
|
|
default:
|
|
throw new BaseException(`Unsupported builtin type ${type.name}`);
|
|
}
|
|
ctx.print(typeStr);
|
|
return null;
|
|
}
|
|
visitExternalType(ast: o.ExternalType, ctx: EmitterVisitorContext): any {
|
|
this._visitIdentifier(ast.value, ast.typeParams, ctx);
|
|
return null;
|
|
}
|
|
visitArrayType(type: o.ArrayType, ctx: EmitterVisitorContext): any {
|
|
ctx.print(`List<`);
|
|
if (isPresent(type.of)) {
|
|
type.of.visitType(this, ctx);
|
|
} else {
|
|
ctx.print(`dynamic`);
|
|
}
|
|
ctx.print(`>`);
|
|
return null;
|
|
}
|
|
visitMapType(type: o.MapType, ctx: EmitterVisitorContext): any {
|
|
ctx.print(`Map<String, `);
|
|
if (isPresent(type.valueType)) {
|
|
type.valueType.visitType(this, ctx);
|
|
} else {
|
|
ctx.print(`dynamic`);
|
|
}
|
|
ctx.print(`>`);
|
|
return null;
|
|
}
|
|
|
|
private _visitParams(params: o.FnParam[], ctx: EmitterVisitorContext): void {
|
|
this.visitAllObjects((param) => {
|
|
if (isPresent(param.type)) {
|
|
param.type.visitType(this, ctx);
|
|
ctx.print(' ');
|
|
}
|
|
ctx.print(param.name);
|
|
}, params, ctx, ',');
|
|
}
|
|
|
|
private _visitIdentifier(value: CompileIdentifierMetadata, typeParams: o.Type[],
|
|
ctx: EmitterVisitorContext): void {
|
|
if (isPresent(value.moduleUrl) && value.moduleUrl != this._moduleUrl) {
|
|
var prefix = this.importsWithPrefixes.get(value.moduleUrl);
|
|
if (isBlank(prefix)) {
|
|
prefix = `import${this.importsWithPrefixes.size}`;
|
|
this.importsWithPrefixes.set(value.moduleUrl, prefix);
|
|
}
|
|
ctx.print(`${prefix}.`);
|
|
}
|
|
ctx.print(value.name);
|
|
if (isPresent(typeParams) && typeParams.length > 0) {
|
|
ctx.print(`<`);
|
|
this.visitAllObjects((type) => type.visitType(this, ctx), typeParams, ctx, ',');
|
|
ctx.print(`>`);
|
|
}
|
|
}
|
|
}
|
|
|
|
function getSuperConstructorCallExpr(stmt: o.Statement): o.Expression {
|
|
if (stmt instanceof o.ExpressionStatement) {
|
|
var expr = stmt.expr;
|
|
if (expr instanceof o.InvokeFunctionExpr) {
|
|
var fn = expr.fn;
|
|
if (fn instanceof o.ReadVarExpr) {
|
|
if (fn.builtin === o.BuiltinVar.Super) {
|
|
return expr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function isConstType(type: o.Type): boolean {
|
|
return isPresent(type) && type.hasModifier(o.TypeModifier.Const);
|
|
} |