diff --git a/packages/compiler-cli/src/ngcc/test/rendering/renderer_spec.ts b/packages/compiler-cli/src/ngcc/test/rendering/renderer_spec.ts index b3a5ee0bf7..6603aa6ad0 100644 --- a/packages/compiler-cli/src/ngcc/test/rendering/renderer_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/rendering/renderer_spec.ts @@ -127,8 +127,11 @@ describe('Renderer', () => { decorators: [jasmine.objectContaining({name: 'Directive'})], })); expect(addDefinitionsSpy.calls.first().args[2]) - .toEqual( - `A.ngDirectiveDef = ɵngcc0.ɵdefineDirective({ type: A, selectors: [["", "a", ""]], factory: function A_Factory(t) { return new (t || A)(); } });`); + .toEqual(`/*@__PURE__*/ ɵngcc0.ɵsetClassMetadata(A, [{ + type: Directive, + args: [{ selector: '[a]' }] + }], null, { foo: [] }); +A.ngDirectiveDef = ɵngcc0.ɵdefineDirective({ type: A, selectors: [["", "a", ""]], factory: function A_Factory(t) { return new (t || A)(); } });`); }); it('should call removeDecorators with the source code, a map of class decorators that have been analyzed', diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts index 8f5b5d931e..f1ecb66353 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ConstantPool, CssSelector, Expression, R3ComponentMetadata, R3DirectiveMetadata, SelectorMatcher, TmplAstNode, WrappedNodeExpr, compileComponentFromMetadata, makeBindingParser, parseTemplate} from '@angular/compiler'; +import {ConstantPool, CssSelector, Expression, R3ComponentMetadata, R3DirectiveMetadata, SelectorMatcher, Statement, TmplAstNode, WrappedNodeExpr, compileComponentFromMetadata, makeBindingParser, parseTemplate} from '@angular/compiler'; import * as path from 'path'; import * as ts from 'typescript'; @@ -18,6 +18,7 @@ import {TypeCheckContext, TypeCheckableDirectiveMeta} from '../../typecheck'; import {ResourceLoader} from './api'; import {extractDirectiveMetadata, extractQueriesFromDecorator, parseFieldArrayValue, queriesFromFields} from './directive'; +import {generateSetClassMetadataCall} from './metadata'; import {ScopeDirective, SelectorScopeRegistry} from './selector_scope'; import {extractDirectiveGuards, isAngularCore, unwrapExpression} from './util'; @@ -26,6 +27,7 @@ const EMPTY_MAP = new Map(); export interface ComponentHandlerData { meta: R3ComponentMetadata; parsedTemplate: TmplAstNode[]; + metadataStmt: Statement|null; } /** @@ -208,6 +210,7 @@ export class ComponentDecoratorHandler implements animations, viewProviders }, + metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.isCore), parsedTemplate: template.nodes, }, typeCheck: true, @@ -242,10 +245,14 @@ export class ComponentDecoratorHandler implements } const res = compileComponentFromMetadata(metadata, pool, makeBindingParser()); + + const statements = res.statements; + if (analysis.metadataStmt !== null) { + statements.push(analysis.metadataStmt); + } return { name: 'ngComponentDef', - initializer: res.expression, - statements: res.statements, + initializer: res.expression, statements, type: res.type, }; } diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts index 79d660688b..0ae80e34d9 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ConstantPool, Expression, R3DirectiveMetadata, R3QueryMetadata, WrappedNodeExpr, compileDirectiveFromMetadata, makeBindingParser, parseHostBindings} from '@angular/compiler'; +import {ConstantPool, Expression, R3DirectiveMetadata, R3QueryMetadata, Statement, WrappedNodeExpr, compileDirectiveFromMetadata, makeBindingParser, parseHostBindings} from '@angular/compiler'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; @@ -14,12 +14,16 @@ import {ClassMember, ClassMemberKind, Decorator, Import, ReflectionHost} from '. import {Reference, ResolvedReference, filterToMembersWithDecorator, reflectObjectLiteral, staticallyResolve} from '../../metadata'; import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform'; +import {generateSetClassMetadataCall} from './metadata'; import {SelectorScopeRegistry} from './selector_scope'; import {extractDirectiveGuards, getConstructorDependencies, isAngularCore, unwrapExpression, unwrapForwardRef} from './util'; const EMPTY_OBJECT: {[key: string]: string} = {}; -export interface DirectiveHandlerData { meta: R3DirectiveMetadata; } +export interface DirectiveHandlerData { + meta: R3DirectiveMetadata; + metadataStmt: Statement|null; +} export class DirectiveDecoratorHandler implements DecoratorHandler { constructor( @@ -63,6 +67,7 @@ export class DirectiveDecoratorHandler implements return { analysis: { meta: analysis, + metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.isCore), } }; } @@ -70,10 +75,14 @@ export class DirectiveDecoratorHandler implements compile(node: ts.ClassDeclaration, analysis: DirectiveHandlerData, pool: ConstantPool): CompileResult { const res = compileDirectiveFromMetadata(analysis.meta, pool, makeBindingParser()); + const statements = res.statements; + if (analysis.metadataStmt !== null) { + statements.push(analysis.metadataStmt); + } return { name: 'ngDirectiveDef', initializer: res.expression, - statements: res.statements, + statements: statements, type: res.type, }; } diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts index 4fe9abda75..6dbfc1a5fd 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Expression, LiteralExpr, R3DependencyMetadata, R3InjectableMetadata, R3ResolvedDependencyType, WrappedNodeExpr, compileInjectable as compileIvyInjectable} from '@angular/compiler'; +import {Expression, LiteralExpr, R3DependencyMetadata, R3InjectableMetadata, R3ResolvedDependencyType, Statement, WrappedNodeExpr, compileInjectable as compileIvyInjectable} from '@angular/compiler'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; @@ -14,9 +14,13 @@ import {Decorator, ReflectionHost} from '../../host'; import {reflectObjectLiteral} from '../../metadata'; import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform'; +import {generateSetClassMetadataCall} from './metadata'; import {getConstructorDependencies, isAngularCore} from './util'; -export interface InjectableHandlerData { meta: R3InjectableMetadata; } +export interface InjectableHandlerData { + meta: R3InjectableMetadata; + metadataStmt: Statement|null; +} /** * Adapts the `compileIvyInjectable` compiler for `@Injectable` decorators to the Ivy compiler. @@ -37,16 +41,20 @@ export class InjectableDecoratorHandler implements return { analysis: { meta: extractInjectableMetadata(node, decorator, this.reflector, this.isCore), + metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.isCore), }, }; } compile(node: ts.ClassDeclaration, analysis: InjectableHandlerData): CompileResult { const res = compileIvyInjectable(analysis.meta); + const statements = res.statements; + if (analysis.metadataStmt !== null) { + statements.push(analysis.metadataStmt); + } return { name: 'ngInjectableDef', - initializer: res.expression, - statements: res.statements, + initializer: res.expression, statements, type: res.type, }; } diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts b/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts index 60ec75abcd..5482a69e12 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ConstantPool, Expression, LiteralArrayExpr, R3DirectiveMetadata, R3InjectorMetadata, R3NgModuleMetadata, WrappedNodeExpr, compileInjector, compileNgModule, makeBindingParser, parseTemplate} from '@angular/compiler'; +import {ConstantPool, Expression, LiteralArrayExpr, R3DirectiveMetadata, R3InjectorMetadata, R3NgModuleMetadata, Statement, WrappedNodeExpr, compileInjector, compileNgModule, makeBindingParser, parseTemplate} from '@angular/compiler'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; @@ -14,12 +14,14 @@ import {Decorator, ReflectionHost} from '../../host'; import {Reference, ResolvedValue, reflectObjectLiteral, staticallyResolve} from '../../metadata'; import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform'; +import {generateSetClassMetadataCall} from './metadata'; import {SelectorScopeRegistry} from './selector_scope'; import {getConstructorDependencies, isAngularCore, toR3Reference, unwrapExpression} from './util'; export interface NgModuleAnalysis { ngModuleDef: R3NgModuleMetadata; ngInjectorDef: R3InjectorMetadata; + metadataStmt: Statement|null; } /** @@ -130,7 +132,9 @@ export class NgModuleDecoratorHandler implements DecoratorHandler { constructor( @@ -85,16 +89,20 @@ export class PipeDecoratorHandler implements DecoratorHandler { const jsContents = env.getContents('test.js'); expect(jsContents).toContain('directives: function () { return [CmpB]; }'); }); + + it('should emit setClassMetadata calls for all types', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Component, Directive, Injectable, NgModule, Pipe} from '@angular/core'; + + @Component({selector: 'cmp', template: 'I am a component!'}) class TestComponent {} + @Directive({selector: 'dir'}) class TestDirective {} + @Injectable() class TestInjectable {} + @NgModule({declarations: [TestComponent, TestDirective]}) class TestNgModule {} + @Pipe({name: 'pipe'}) class TestPipe {} + `); + + env.driveMain(); + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('ɵsetClassMetadata(TestComponent, '); + expect(jsContents).toContain('ɵsetClassMetadata(TestDirective, '); + expect(jsContents).toContain('ɵsetClassMetadata(TestInjectable, '); + expect(jsContents).toContain('ɵsetClassMetadata(TestNgModule, '); + expect(jsContents).toContain('ɵsetClassMetadata(TestPipe, '); + }); }); 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 095ee683a5..f6c76830ee 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 @@ -231,7 +231,7 @@ "name": "AttrAst" }, { - "name": "Attribute" + "name": "Attribute$1" }, { "name": "B64_DIGITS"