diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts b/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts index 06778fbc10..997c60c96e 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts @@ -353,10 +353,10 @@ export class SelectorScopeRegistry { return []; } return def.elementTypes.map(element => { - if (!ts.isTypeReferenceNode(element)) { - throw new Error(`Expected TypeReferenceNode`); + if (!ts.isTypeQueryNode(element)) { + throw new Error(`Expected TypeQueryNode`); } - const type = element.typeName; + const type = element.exprName; const {node, from} = reflectTypeEntityToDeclaration(type, this.checker); const moduleName = (from !== null && !from.startsWith('.') ? from : ngModuleImportedFrom); const clazz = node as ts.Declaration; diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/selector_scope_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/test/selector_scope_spec.ts index 87ff276bd0..a4a287e444 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/selector_scope_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/test/selector_scope_spec.ts @@ -31,7 +31,7 @@ describe('SelectorScopeRegistry', () => { import * as i0 from './component'; export declare class SomeModule { - static ngModuleDef: NgModuleDef; + static ngModuleDef: NgModuleDef; } export declare class SomeCmp { diff --git a/packages/compiler-cli/src/ngtsc/transform/src/translator.ts b/packages/compiler-cli/src/ngtsc/transform/src/translator.ts index 32b3ada9ec..b5353da37c 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/translator.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/translator.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ArrayType, AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinType, BuiltinTypeName, CastExpr, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, Expression, ExpressionStatement, ExpressionType, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, MapType, NotExpr, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, Statement, StatementVisitor, StmtModifier, ThrowStmt, TryCatchStmt, Type, TypeVisitor, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr} from '@angular/compiler'; +import {ArrayType, AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinType, BuiltinTypeName, CastExpr, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, Expression, ExpressionStatement, ExpressionType, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, MapType, NotExpr, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, Statement, StatementVisitor, StmtModifier, ThrowStmt, TryCatchStmt, Type, TypeVisitor, TypeofExpr, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr} from '@angular/compiler'; import * as ts from 'typescript'; import {relativePathBetween} from '../../util/src/path'; @@ -278,6 +278,10 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor } visitWrappedNodeExpr(ast: WrappedNodeExpr, context: Context): any { return ast.node; } + + visitTypeofExpr(ast: TypeofExpr, context: Context): ts.TypeOfExpression { + return ts.createTypeOf(ast.expr.visitExpression(this, context)); + } } export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor { @@ -294,6 +298,8 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor { return 'number'; case BuiltinTypeName.String: return 'string'; + case BuiltinTypeName.None: + return 'never'; default: throw new Error(`Unsupported builtin type: ${BuiltinTypeName[type.name]}`); } @@ -417,4 +423,8 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor { `Unsupported WrappedNodeExpr in TypeTranslatorVisitor: ${ts.SyntaxKind[node.kind]}`); } } + + visitTypeofExpr(ast: TypeofExpr, context: Context): string { + return `typeof ${ast.expr.visitExpression(this, context)}`; + } } \ No newline at end of file diff --git a/packages/compiler-cli/src/transformers/node_emitter.ts b/packages/compiler-cli/src/transformers/node_emitter.ts index 35fba0943f..66c31a1458 100644 --- a/packages/compiler-cli/src/transformers/node_emitter.ts +++ b/packages/compiler-cli/src/transformers/node_emitter.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinMethod, BuiltinVar, CastExpr, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, ExpressionStatement, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, NotExpr, ParseSourceFile, ParseSourceSpan, PartialModule, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, Statement, StatementVisitor, StmtModifier, ThrowStmt, TryCatchStmt, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr} from '@angular/compiler'; +import {AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinMethod, BuiltinVar, CastExpr, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, ExpressionStatement, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, NotExpr, ParseSourceFile, ParseSourceSpan, PartialModule, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, Statement, StatementVisitor, StmtModifier, ThrowStmt, TryCatchStmt, TypeofExpr, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr} from '@angular/compiler'; import * as ts from 'typescript'; import {error} from './util'; @@ -465,6 +465,11 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { // ExpressionVisitor visitWrappedNodeExpr(expr: WrappedNodeExpr) { return this.record(expr, expr.node); } + visitTypeofExpr(expr: TypeofExpr) { + const typeOf = ts.createTypeOf(expr.expr.visitExpression(this, null)); + return this.record(expr, typeOf); + } + // ExpressionVisitor visitReadVarExpr(expr: ReadVarExpr) { switch (expr.builtin) { diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts index 38769fc2b9..044480c114 100644 --- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts +++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts @@ -198,7 +198,8 @@ describe('ngtsc behavioral tests', () => { const dtsContents = getContents('test.d.ts'); expect(dtsContents).toContain('static ngComponentDef: i0.ɵComponentDef'); expect(dtsContents) - .toContain('static ngModuleDef: i0.ɵNgModuleDef'); + .toContain( + 'static ngModuleDef: i0.ɵNgModuleDef'); expect(dtsContents).not.toContain('__decorate'); }); @@ -240,7 +241,8 @@ describe('ngtsc behavioral tests', () => { const dtsContents = getContents('test.d.ts'); expect(dtsContents) - .toContain('static ngModuleDef: i0.ɵNgModuleDef'); + .toContain( + 'static ngModuleDef: i0.ɵNgModuleDef'); expect(dtsContents).toContain('static ngInjectorDef: i0.ɵInjectorDef'); }); @@ -342,7 +344,8 @@ describe('ngtsc behavioral tests', () => { expect(jsContents).toContain('pipes: [TestPipe]'); const dtsContents = getContents('test.d.ts'); - expect(dtsContents).toContain('i0.ɵNgModuleDef'); + expect(dtsContents) + .toContain('i0.ɵNgModuleDef'); }); it('should unwrap a ModuleWithProviders function if a generic type is provided for it', () => { @@ -372,7 +375,8 @@ describe('ngtsc behavioral tests', () => { const dtsContents = getContents('test.d.ts'); expect(dtsContents).toContain(`import * as i1 from 'router';`); - expect(dtsContents).toContain('i0.ɵNgModuleDef'); + expect(dtsContents) + .toContain('i0.ɵNgModuleDef'); }); it('should inject special types according to the metadata', () => { diff --git a/packages/compiler/src/compiler.ts b/packages/compiler/src/compiler.ts index 98398f2716..2f81a1cd85 100644 --- a/packages/compiler/src/compiler.ts +++ b/packages/compiler/src/compiler.ts @@ -68,7 +68,7 @@ export * from './ml_parser/html_tags'; export * from './ml_parser/interpolation_config'; export * from './ml_parser/tags'; export {NgModuleCompiler} from './ng_module_compiler'; -export {ArrayType, AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinMethod, BuiltinType, BuiltinTypeName, BuiltinVar, CastExpr, ClassField, ClassMethod, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, Expression, ExpressionStatement, ExpressionType, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, MapType, NotExpr, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, StatementVisitor, ThrowStmt, TryCatchStmt, Type, TypeVisitor, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, StmtModifier, Statement, collectExternalReferences} from './output/output_ast'; +export {ArrayType, AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinMethod, BuiltinType, BuiltinTypeName, BuiltinVar, CastExpr, ClassField, ClassMethod, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, Expression, ExpressionStatement, ExpressionType, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, MapType, NotExpr, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, StatementVisitor, ThrowStmt, TryCatchStmt, Type, TypeVisitor, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, StmtModifier, Statement, TypeofExpr, collectExternalReferences} from './output/output_ast'; export {EmitterVisitorContext} from './output/abstract_emitter'; export * from './output/ts_emitter'; export * from './parse_util'; diff --git a/packages/compiler/src/constant_pool.ts b/packages/compiler/src/constant_pool.ts index 81feef39f0..aa95cd0a8a 100644 --- a/packages/compiler/src/constant_pool.ts +++ b/packages/compiler/src/constant_pool.ts @@ -298,6 +298,10 @@ class KeyVisitor implements o.ExpressionVisitor { visitReadVarExpr(node: o.ReadVarExpr) { return `VAR:${node.name}`; } + visitTypeofExpr(node: o.TypeofExpr, context: any): string { + return `TYPEOF:${node.expr.visitExpression(this, context)}`; + } + visitWrappedNodeExpr = invalid; visitWriteVarExpr = invalid; visitWriteKeyExpr = invalid; diff --git a/packages/compiler/src/output/abstract_emitter.ts b/packages/compiler/src/output/abstract_emitter.ts index 9780ded14f..ac26cdba21 100644 --- a/packages/compiler/src/output/abstract_emitter.ts +++ b/packages/compiler/src/output/abstract_emitter.ts @@ -315,6 +315,10 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex visitWrappedNodeExpr(ast: o.WrappedNodeExpr, ctx: EmitterVisitorContext): any { throw new Error('Abstract emitter cannot visit WrappedNodeExpr.'); } + visitTypeofExpr(expr: o.TypeofExpr, ctx: EmitterVisitorContext): any { + ctx.print(expr, 'typeof '); + expr.expr.visitExpression(this, ctx); + } visitReadVarExpr(ast: o.ReadVarExpr, ctx: EmitterVisitorContext): any { let varName = ast.name !; if (ast.builtin != null) { diff --git a/packages/compiler/src/output/output_ast.ts b/packages/compiler/src/output/output_ast.ts index 69d05c67fe..dd58b7fecd 100644 --- a/packages/compiler/src/output/output_ast.ts +++ b/packages/compiler/src/output/output_ast.ts @@ -33,7 +33,8 @@ export enum BuiltinTypeName { Int, Number, Function, - Inferred + Inferred, + None, } export class BuiltinType extends Type { @@ -77,6 +78,7 @@ 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); export interface TypeVisitor { visitBuiltinType(type: BuiltinType, context: any): any; @@ -279,6 +281,22 @@ export class ReadVarExpr extends Expression { } } +export class TypeofExpr extends Expression { + constructor(public expr: Expression, type?: Type|null, sourceSpan?: ParseSourceSpan|null) { + super(type, sourceSpan); + } + + visitExpression(visitor: ExpressionVisitor, context: any) { + return visitor.visitTypeofExpr(this, context); + } + + isEquivalent(e: Expression): boolean { + return e instanceof TypeofExpr && e.expr.isEquivalent(this.expr); + } + + isConstant(): boolean { return this.expr.isConstant(); } +} + export class WrappedNodeExpr extends Expression { constructor(public node: T, type?: Type|null, sourceSpan?: ParseSourceSpan|null) { super(type, sourceSpan); @@ -738,6 +756,7 @@ export interface ExpressionVisitor { visitLiteralMapExpr(ast: LiteralMapExpr, context: any): any; visitCommaExpr(ast: CommaExpr, context: any): any; visitWrappedNodeExpr(ast: WrappedNodeExpr, context: any): any; + visitTypeofExpr(ast: TypeofExpr, context: any): any; } export const THIS_EXPR = new ReadVarExpr(BuiltinVar.This, null, null); @@ -993,6 +1012,12 @@ export class AstTransformer implements StatementVisitor, ExpressionVisitor { return this.transformExpr(ast, context); } + visitTypeofExpr(expr: TypeofExpr, context: any): any { + return this.transformExpr( + new TypeofExpr(expr.expr.visitExpression(this, context), expr.type, expr.sourceSpan), + context); + } + visitWriteVarExpr(expr: WriteVarExpr, context: any): any { return this.transformExpr( new WriteVarExpr( @@ -1220,6 +1245,7 @@ export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor visitArrayType(type: ArrayType, context: any): any { return this.visitType(type, context); } visitMapType(type: MapType, context: any): any { return this.visitType(type, context); } visitWrappedNodeExpr(ast: WrappedNodeExpr, context: any): any { return ast; } + visitTypeofExpr(ast: TypeofExpr, context: any): any { return this.visitExpression(ast, context); } visitReadVarExpr(ast: ReadVarExpr, context: any): any { return this.visitExpression(ast, context); } @@ -1474,6 +1500,10 @@ export function expressionType( return new ExpressionType(expr, typeModifiers); } +export function typeofExpr(expr: Expression) { + return new TypeofExpr(expr); +} + export function literalArr( values: Expression[], type?: Type | null, sourceSpan?: ParseSourceSpan | null): LiteralArrayExpr { diff --git a/packages/compiler/src/output/output_interpreter.ts b/packages/compiler/src/output/output_interpreter.ts index fdf3d61ac1..7f63f7bb6c 100644 --- a/packages/compiler/src/output/output_interpreter.ts +++ b/packages/compiler/src/output/output_interpreter.ts @@ -117,6 +117,9 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor { visitWrappedNodeExpr(ast: o.WrappedNodeExpr, ctx: _ExecutionContext): never { throw new Error('Cannot interpret a WrappedNodeExpr.'); } + visitTypeofExpr(ast: o.TypeofExpr, ctx: _ExecutionContext): never { + throw new Error('Cannot interpret a TypeofExpr'); + } visitReadVarExpr(ast: o.ReadVarExpr, ctx: _ExecutionContext): any { let varName = ast.name !; if (ast.builtin != null) { diff --git a/packages/compiler/src/output/ts_emitter.ts b/packages/compiler/src/output/ts_emitter.ts index eff352943e..ad01cf1a67 100644 --- a/packages/compiler/src/output/ts_emitter.ts +++ b/packages/compiler/src/output/ts_emitter.ts @@ -349,6 +349,9 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor case o.BuiltinTypeName.String: typeStr = 'string'; break; + case o.BuiltinTypeName.None: + typeStr = 'never'; + break; default: throw new Error(`Unsupported builtin type ${type.name}`); } diff --git a/packages/compiler/src/render3/r3_module_compiler.ts b/packages/compiler/src/render3/r3_module_compiler.ts index 921bae7ecf..e9938bf5a5 100644 --- a/packages/compiler/src/render3/r3_module_compiler.ts +++ b/packages/compiler/src/render3/r3_module_compiler.ts @@ -74,8 +74,8 @@ export function compileNgModule(meta: R3NgModuleMetadata): R3NgModuleDef { })]); const type = new o.ExpressionType(o.importExpr(R3.NgModuleDef, [ - new o.ExpressionType(moduleType), new o.ExpressionType(o.literalArr(declarations)), - new o.ExpressionType(o.literalArr(imports)), new o.ExpressionType(o.literalArr(exports)) + new o.ExpressionType(moduleType), tupleTypeOf(declarations), tupleTypeOf(imports), + tupleTypeOf(exports) ])); const additionalStatements: o.Statement[] = []; @@ -147,3 +147,8 @@ function accessExportScope(module: o.Expression): o.Expression { const selectorScope = new o.ReadPropExpr(module, 'ngModuleDef'); return new o.ReadPropExpr(selectorScope, 'exported'); } + +function tupleTypeOf(exp: o.Expression[]): o.Type { + const types = exp.map(type => o.typeofExpr(type)); + return exp.length > 0 ? o.expressionType(o.literalArr(types)) : o.NONE_TYPE; +} \ No newline at end of file diff --git a/packages/core/test/bundling/hello_world_r2/bundle.golden_symbols.json b/packages/core/test/bundling/hello_world_r2/bundle.golden_symbols.json index ce849e0a5f..cfb0615eeb 100644 --- a/packages/core/test/bundling/hello_world_r2/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hello_world_r2/bundle.golden_symbols.json @@ -1559,6 +1559,9 @@ { "name": "TypeModifier" }, + { + "name": "TypeofExpr" + }, { "name": "UNDEFINED_RENDERER_TYPE_ID" },