Skip to content

Commit 7f25548

Browse files
authored
fix(@ngtools/webpack): better ctor parameters in AOT (#4428)
We missed a few cases that were generating errors. Sorry. Fixes #4427
1 parent 6ff0f80 commit 7f25548

File tree

4 files changed

+72
-35
lines changed

4 files changed

+72
-35
lines changed

packages/@ngtools/webpack/src/loader.ts

+47-30
Original file line numberDiff line numberDiff line change
@@ -61,35 +61,57 @@ function _angularImportsFromNode(node: ts.ImportDeclaration, sourceFile: ts.Sour
6161
function _ctorParameterFromTypeReference(paramNode: ts.ParameterDeclaration,
6262
angularImports: string[],
6363
refactor: TypeScriptFileRefactor) {
64-
if (paramNode.type.kind == ts.SyntaxKind.TypeReference) {
65-
const type = paramNode.type as ts.TypeReferenceNode;
66-
const decorators = refactor.findAstNodes(paramNode, ts.SyntaxKind.Decorator) as ts.Decorator[];
67-
const decoratorStr = decorators
68-
.map(decorator => {
69-
const fnName =
70-
(refactor.findFirstAstNode(decorator, ts.SyntaxKind.CallExpression) as ts.CallExpression)
71-
.expression.getText(refactor.sourceFile);
72-
73-
if (angularImports.indexOf(fnName) === -1) {
74-
return null;
64+
let typeName = 'undefined';
65+
66+
if (paramNode.type) {
67+
switch (paramNode.type.kind) {
68+
case ts.SyntaxKind.TypeReference:
69+
const type = paramNode.type as ts.TypeReferenceNode;
70+
if (type.typeName) {
71+
typeName = type.typeName.getText(refactor.sourceFile);
7572
} else {
76-
return fnName;
73+
typeName = type.getText(refactor.sourceFile);
7774
}
78-
})
79-
.filter(x => !!x)
80-
.map(name => `{ type: ${name} }`)
81-
.join(', ');
82-
83-
if (type.typeName.kind == ts.SyntaxKind.Identifier) {
84-
const typeName = type.typeName as ts.Identifier;
85-
if (decorators.length > 0) {
86-
return `{ type: ${typeName.text}, decorators: [${decoratorStr}] }`;
87-
}
88-
return `{ type: ${typeName.text} }`;
75+
break;
76+
case ts.SyntaxKind.AnyKeyword:
77+
typeName = 'undefined';
78+
break;
79+
default:
80+
typeName = 'null';
8981
}
9082
}
9183

92-
return 'null';
84+
const decorators = refactor.findAstNodes(paramNode, ts.SyntaxKind.Decorator) as ts.Decorator[];
85+
const decoratorStr = decorators
86+
.map(decorator => {
87+
const call =
88+
refactor.findFirstAstNode(decorator, ts.SyntaxKind.CallExpression) as ts.CallExpression;
89+
90+
if (!call) {
91+
return null;
92+
}
93+
94+
const fnName = call.expression.getText(refactor.sourceFile);
95+
const args = call.arguments.map(x => x.getText(refactor.sourceFile)).join(', ');
96+
if (angularImports.indexOf(fnName) === -1) {
97+
return null;
98+
} else {
99+
return [fnName, args];
100+
}
101+
})
102+
.filter(x => !!x)
103+
.map(([name, args]: string[]) => {
104+
if (args) {
105+
return `{ type: ${name}, args: [${args}] }`;
106+
}
107+
return `{ type: ${name} }`;
108+
})
109+
.join(', ');
110+
111+
if (decorators.length > 0) {
112+
return `{ type: ${typeName}, decorators: [${decoratorStr}] }`;
113+
}
114+
return `{ type: ${typeName} }`;
93115
}
94116

95117

@@ -106,12 +128,7 @@ function _addCtorParameters(classNode: ts.ClassDeclaration,
106128
}
107129

108130
const params = Array.from(ctor.parameters).map(paramNode => {
109-
switch (paramNode.type.kind) {
110-
case ts.SyntaxKind.TypeReference:
111-
return _ctorParameterFromTypeReference(paramNode, angularImports, refactor);
112-
default:
113-
return 'null';
114-
}
131+
return _ctorParameterFromTypeReference(paramNode, angularImports, refactor);
115132
});
116133

117134
const ctorParametersDecl = `static ctorParameters() { return [ ${params.join(', ')} ]; }`;
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {Component, ViewEncapsulation} from '@angular/core';
2+
import {MyInjectable} from './injectable';
23

34

45
@Component({
@@ -7,4 +8,8 @@ import {Component, ViewEncapsulation} from '@angular/core';
78
styleUrls: ['./app.component.scss'],
89
encapsulation: ViewEncapsulation.None
910
})
10-
export class AppComponent { }
11+
export class AppComponent {
12+
constructor(public inj: MyInjectable) {
13+
console.log(inj);
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import {Injectable, Inject, ViewContainerRef} from '@angular/core';
2+
import {DOCUMENT} from '@angular/platform-browser';
3+
4+
5+
@Injectable()
6+
export class MyInjectable {
7+
constructor(public viewContainer: ViewContainerRef, @Inject(DOCUMENT) public doc) {}
8+
}
+11-4
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
import {normalize} from 'path';
22
import {createProjectFromAsset} from '../../../utils/assets';
33
import {exec} from '../../../utils/process';
4-
import {expectFileSizeToBeUnder, replaceInFile} from '../../../utils/fs';
4+
import {expectFileSizeToBeUnder, replaceInFile, expectFileToMatch} from '../../../utils/fs';
55

66

77
export default function(skipCleaning: () => void) {
88
return Promise.resolve()
99
.then(() => createProjectFromAsset('webpack/test-app'))
1010
.then(() => exec(normalize('node_modules/.bin/webpack'), '-p'))
1111
.then(() => expectFileSizeToBeUnder('dist/app.main.js', 420000))
12-
.then(() => expectFileSizeToBeUnder('dist/0.app.main.js', 40000))
12+
.then(() => expectFileSizeToBeUnder('dist/0.app.main.js', 10000))
1313
// test resource urls without ./
1414
.then(() => replaceInFile('app/app.component.ts',
1515
'./app.component.html', 'app.component.html'))
1616
.then(() => replaceInFile('app/app.component.ts',
1717
'./app.component.scss', 'app.component.scss'))
18-
.then(() => exec(normalize('node_modules/.bin/webpack'), '-p'))
19-
// test
18+
// test the inclusion of metadata
19+
// This build also test resource URLs without ./
20+
.then(() => exec(normalize('node_modules/.bin/webpack')))
21+
.then(() => expectFileToMatch('dist/app.main.js',
22+
new RegExp('MyInjectable.ctorParameters = .*'
23+
+ 'type: .*ViewContainerRef.*'
24+
+ 'type: undefined, decorators.*Inject.*args: .*DOCUMENT.*'))
25+
.then(() => expectFileToMatch('dist/app.main.js',
26+
new RegExp('AppComponent.ctorParameters = .*MyInjectable'))
2027
.then(() => skipCleaning());
2128
}

0 commit comments

Comments
 (0)