Skip to content

Commit

Permalink
fix(ivy): move setClassMetadata calls into a pure iife
Browse files Browse the repository at this point in the history
This commit transforms the setClassMetadata calls generated by ngtsc from:

```typescript
/*@__PURE__*/ setClassMetadata(...);
```

to:

```typescript
/*@__PURE__*/ (function() {
  setClassMetadata(...);
})();
```

This is required for the build optimizer and side-effect-free analysis to
function correctly.
  • Loading branch information
alxhub authored and IgorMinar committed Oct 22, 2019
1 parent 398ff1e commit f379dfa
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 12 deletions.
12 changes: 6 additions & 6 deletions packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts
Expand Up @@ -198,10 +198,10 @@ A.ɵcmp = ɵngcc0.ɵɵdefineComponent({ type: A, selectors: [["a"]], decls: 1, v
} if (rf & 2) {
ɵngcc0.ɵɵtextInterpolate(ctx.person.name);
} }, encapsulation: 2 });
/*@__PURE__*/ ɵngcc0.ɵsetClassMetadata(A, [{
/*@__PURE__*/ (function () { ɵngcc0.ɵsetClassMetadata(A, [{
type: Component,
args: [{ selector: 'a', template: '{{ person!.name }}' }]
}], null, null);`);
}], null, null); })();`);
});


Expand Down Expand Up @@ -235,10 +235,10 @@ A.ɵcmp = ɵngcc0.ɵɵdefineComponent({ type: A, selectors: [["a"]], decls: 1, v
expect(addDefinitionsSpy.calls.first().args[2])
.toEqual(`A.ɵfac = function A_Factory(t) { return new (t || A)(); };
A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });
/*@__PURE__*/ ɵngcc0.ɵsetClassMetadata(A, [{
/*@__PURE__*/ (function () { ɵngcc0.ɵsetClassMetadata(A, [{
type: Directive,
args: [{ selector: '[a]' }]
}], null, { foo: [] });`);
}], null, { foo: [] }); })();`);
});

it('should call removeDecorators with the source code, a map of class decorators that have been analyzed',
Expand Down Expand Up @@ -392,7 +392,7 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
const addDefinitionsSpy = testFormatter.addDefinitions as jasmine.Spy;
expect(addDefinitionsSpy.calls.first().args[2])
.toContain(`/*@__PURE__*/ ɵngcc0.setClassMetadata(`);
.toContain(`/*@__PURE__*/ (function () { ɵngcc0.setClassMetadata(`);
const addImportsSpy = testFormatter.addImports as jasmine.Spy;
expect(addImportsSpy.calls.first().args[1]).toEqual([
{specifier: './r3_symbols', qualifier: 'ɵngcc0'}
Expand All @@ -412,7 +412,7 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
const addDefinitionsSpy = testFormatter.addDefinitions as jasmine.Spy;
expect(addDefinitionsSpy.calls.first().args[2])
.toContain(`/*@__PURE__*/ setClassMetadata(`);
.toContain(`/*@__PURE__*/ (function () { setClassMetadata(`);
const addImportsSpy = testFormatter.addImports as jasmine.Spy;
expect(addImportsSpy.calls.first().args[1]).toEqual([]);
});
Expand Down
10 changes: 7 additions & 3 deletions packages/compiler-cli/src/ngtsc/annotations/src/metadata.ts
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Expression, ExternalExpr, FunctionExpr, Identifiers, InvokeFunctionExpr, LiteralArrayExpr, LiteralExpr, ReturnStatement, Statement, WrappedNodeExpr, literalMap} from '@angular/compiler';
import {Expression, ExternalExpr, FunctionExpr, Identifiers, InvokeFunctionExpr, LiteralArrayExpr, LiteralExpr, NONE_TYPE, ReturnStatement, Statement, WrappedNodeExpr, literalMap} from '@angular/compiler';
import * as ts from 'typescript';

import {DefaultImportRecorder} from '../../imports';
Expand Down Expand Up @@ -74,11 +74,15 @@ export function generateSetClassMetadataCall(
new WrappedNodeExpr(metaDecorators),
metaCtorParameters,
new WrappedNodeExpr(metaPropDecorators),
],
]);
const iifeFn = new FunctionExpr([], [fnCall.toStmt()], NONE_TYPE);
const iife = new InvokeFunctionExpr(
/* fn */ iifeFn,
/* args */[],
/* type */ undefined,
/* sourceSpan */ undefined,
/* pure */ true);
return fnCall.toStmt();
return iife.toStmt();
}

/**
Expand Down
Expand Up @@ -23,7 +23,7 @@ runInEachFileSystem(() => {
@Component('metadata') class Target {}
`);
expect(res).toEqual(
`/*@__PURE__*/ i0.ɵsetClassMetadata(Target, [{ type: Component, args: ['metadata'] }], null, null);`);
`/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(Target, [{ type: Component, args: ['metadata'] }], null, null); })();`);
});

it('should convert namespaced decorated class metadata', () => {
Expand All @@ -33,7 +33,7 @@ runInEachFileSystem(() => {
@core.Component('metadata') class Target {}
`);
expect(res).toEqual(
`/*@__PURE__*/ i0.ɵsetClassMetadata(Target, [{ type: core.Component, args: ['metadata'] }], null, null);`);
`/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(Target, [{ type: core.Component, args: ['metadata'] }], null, null); })();`);
});

it('should convert decorated class constructor parameter metadata', () => {
Expand Down
15 changes: 15 additions & 0 deletions packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
Expand Up @@ -2614,6 +2614,21 @@ runInEachFileSystem(os => {
expect(jsContents).toContain('directives: function () { return [CmpB]; }');
});

it('should wrap setClassMetadata in an iife', () => {
env.write('test.ts', `
import {Injectable} from '@angular/core';
@Injectable({providedIn: 'root'})
export class Service {}
`);

env.driveMain();
const jsContents = env.getContents('test.js').replace(/\s+/g, ' ');
expect(jsContents)
.toContain(
`/*@__PURE__*/ (function () { i0.ɵsetClassMetadata(Service, [{ type: Injectable, args: [{ providedIn: 'root' }] }], null, null); })();`);
});

it('should emit setClassMetadata calls for all types', () => {
env.write('test.ts', `
import {Component, Directive, Injectable, NgModule, Pipe} from '@angular/core';
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler/src/compiler.ts
Expand Up @@ -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, 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, 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 {EmitterVisitorContext} from './output/abstract_emitter';
export {JitEvaluator} from './output/output_jit';
export * from './output/ts_emitter';
Expand Down

0 comments on commit f379dfa

Please sign in to comment.