Skip to content

Commit b31604c

Browse files
committed
fix(app): component template import parsing
fix #1121 #637
1 parent 7b68398 commit b31604c

File tree

5 files changed

+107
-43
lines changed

5 files changed

+107
-43
lines changed

src/app/compiler/angular/deps/helpers/symbol-helper.ts

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -185,29 +185,45 @@ export class SymbolHelper {
185185
*/
186186
private parseSymbols(
187187
node: ts.ObjectLiteralElement,
188-
srcFile: ts.SourceFile
188+
srcFile: ts.SourceFile,
189+
decoratorType: string
189190
): Array<string | boolean> {
190191
let localNode = node;
191192

192-
if (ts.isShorthandPropertyAssignment(localNode)) {
193-
localNode = ImportsUtil.findValueInImportOrLocalVariables(node.name.text, srcFile);
193+
if (ts.isShorthandPropertyAssignment(localNode) && decoratorType !== 'template') {
194+
localNode = ImportsUtil.findValueInImportOrLocalVariables(
195+
node.name.text,
196+
srcFile,
197+
decoratorType
198+
);
199+
}
200+
if (ts.isShorthandPropertyAssignment(localNode) && decoratorType === 'template') {
201+
const data = ImportsUtil.findValueInImportOrLocalVariables(
202+
node.name.text,
203+
srcFile,
204+
decoratorType
205+
);
206+
return [data];
194207
}
195208

196-
if (ts.isArrayLiteralExpression(localNode.initializer)) {
209+
if (localNode.initializer && ts.isArrayLiteralExpression(localNode.initializer)) {
197210
return localNode.initializer.elements.map(x => this.parseSymbolElements(x));
198211
} else if (
199-
ts.isStringLiteral(localNode.initializer) ||
200-
ts.isTemplateLiteral(localNode.initializer) ||
201-
(ts.isPropertyAssignment(localNode) && localNode.initializer.text)
212+
(localNode.initializer && ts.isStringLiteral(localNode.initializer)) ||
213+
(localNode.initializer && ts.isTemplateLiteral(localNode.initializer)) ||
214+
(localNode.initializer &&
215+
ts.isPropertyAssignment(localNode) &&
216+
localNode.initializer.text)
202217
) {
203218
return [localNode.initializer.text];
204219
} else if (
220+
localNode.initializer &&
205221
localNode.initializer.kind &&
206222
(localNode.initializer.kind === SyntaxKind.TrueKeyword ||
207223
localNode.initializer.kind === SyntaxKind.FalseKeyword)
208224
) {
209225
return [localNode.initializer.kind === SyntaxKind.TrueKeyword ? true : false];
210-
} else if (ts.isPropertyAccessExpression(localNode.initializer)) {
226+
} else if (localNode.initializer && ts.isPropertyAccessExpression(localNode.initializer)) {
211227
let identifier = this.parseSymbolElements(localNode.initializer);
212228
return [identifier];
213229
} else if (
@@ -222,7 +238,7 @@ export class SymbolHelper {
222238

223239
public getSymbolDeps(
224240
props: ReadonlyArray<ts.ObjectLiteralElementLike>,
225-
type: string,
241+
decoratorType: string,
226242
srcFile: ts.SourceFile,
227243
multiLine?: boolean
228244
): Array<string> {
@@ -235,12 +251,12 @@ export class SymbolHelper {
235251
filteredProps = [];
236252

237253
for (i; i < len; i++) {
238-
if (props[i].name && props[i].name.text === type) {
254+
if (props[i].name && props[i].name.text === decoratorType) {
239255
filteredProps.push(props[i]);
240256
}
241257
}
242258

243-
return filteredProps.map(x => this.parseSymbols(x, srcFile)).pop() || [];
259+
return filteredProps.map(x => this.parseSymbols(x, srcFile, decoratorType)).pop() || [];
244260
}
245261

246262
public getSymbolDepsRaw(

src/utils/imports.util.ts

Lines changed: 68 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as path from 'path';
22

3-
import { Project, ts, PropertyDeclaration, SyntaxKind } from 'ts-morph';
3+
import { Project, ts, PropertyDeclaration, SyntaxKind, VariableDeclaration } from 'ts-morph';
4+
import FileEngine from '../app/engines/file.engine';
45

56
const ast = new Project();
67

@@ -100,10 +101,16 @@ export class ImportsUtil {
100101
* @param {string} inputVariableName like myvar
101102
* @return {[type]} myvar value
102103
*/
103-
public findValueInImportOrLocalVariables(inputVariableName: string, sourceFile: ts.SourceFile) {
104+
public findValueInImportOrLocalVariables(
105+
inputVariableName: string,
106+
sourceFile: ts.SourceFile,
107+
decoratorType?: string
108+
) {
104109
let metadataVariableName = inputVariableName,
105110
searchedImport,
106111
aliasOriginalName = '',
112+
foundWithNamedImport = false,
113+
foundWithDefaultImport = false,
107114
foundWithAlias = false;
108115

109116
const file =
@@ -129,17 +136,37 @@ export class ImportsUtil {
129136
importAlias = namedImports[j].getAliasNode().getText();
130137
}
131138
if (importName === metadataVariableName) {
139+
foundWithNamedImport = true;
132140
searchedImport = i;
133141
break;
134142
}
135143
if (importAlias === metadataVariableName) {
144+
foundWithNamedImport = true;
136145
foundWithAlias = true;
137146
aliasOriginalName = importName;
138147
searchedImport = i;
139148
break;
140149
}
141150
}
142151
}
152+
const namespaceImport = i.getNamespaceImport();
153+
if (namespaceImport) {
154+
const namespaceImportLocalName = namespaceImport.getText();
155+
if (namespaceImportLocalName === metadataVariableName) {
156+
searchedImport = i;
157+
}
158+
}
159+
160+
if (!foundWithNamedImport) {
161+
const defaultImport = i.getDefaultImport();
162+
if (defaultImport) {
163+
const defaultImportText = defaultImport.getText();
164+
if (defaultImportText === metadataVariableName) {
165+
foundWithDefaultImport = true;
166+
searchedImport = i;
167+
}
168+
}
169+
}
143170
});
144171

145172
function hasFoundValues(variableDeclaration) {
@@ -176,40 +203,41 @@ export class ImportsUtil {
176203
return hasFoundValues(variableDeclaration);
177204
} else {
178205
// Try with exports
179-
const exportDeclarations = sourceFileImport.getExportDeclarations();
180-
if (exportDeclarations && exportDeclarations.length > 0) {
181-
let i = 0,
182-
len = exportDeclarations.length;
183-
for (i; i < len; i++) {
184-
let exportDeclaration = exportDeclarations[i];
185-
let sourceFileExportedReference =
186-
exportDeclaration.getModuleSpecifierSourceFile();
187-
if (sourceFileExportedReference) {
188-
let sourceFileExportedReferencePath =
189-
sourceFileExportedReference.getFilePath();
190-
191-
const sourceFileExported =
192-
typeof ast.getSourceFile(
193-
sourceFileExportedReferencePath
194-
) !== 'undefined'
195-
? ast.getSourceFile(sourceFileExportedReferencePath)
196-
: ast.addSourceFileAtPathIfExists(
197-
sourceFileExportedReferencePath
198-
);
199-
200-
if (sourceFileExported) {
201-
variableDeclaration =
202-
sourceFileExported.getVariableDeclaration(variableName);
203-
if (variableDeclaration) {
204-
return hasFoundValues(variableDeclaration);
205-
}
206+
const exportDeclarations = sourceFileImport.getExportedDeclarations();
207+
208+
if (exportDeclarations && exportDeclarations.size > 0) {
209+
for (const [
210+
exportDeclarationKey,
211+
exportDeclarationValues
212+
] of exportDeclarations) {
213+
exportDeclarationValues.forEach(exportDeclarationValue => {
214+
if (
215+
exportDeclarationValue instanceof VariableDeclaration &&
216+
exportDeclarationValue.getName() === variableName
217+
) {
218+
return hasFoundValues(exportDeclarationValue);
206219
}
207-
}
220+
});
208221
}
209222
}
210223
}
211224
}
212225
}
226+
if (
227+
!importPathReference &&
228+
decoratorType === 'template' &&
229+
searchedImport.getModuleSpecifierValue().indexOf('.html') !== -1
230+
) {
231+
const originalSourceFilePath = sourceFile.path;
232+
const originalSourceFilePathFolder = originalSourceFilePath.substring(
233+
0,
234+
originalSourceFilePath.lastIndexOf('/')
235+
);
236+
const finalImportedPath =
237+
originalSourceFilePathFolder + '/' + searchedImport.getModuleSpecifierValue();
238+
const finalImportedPathData = FileEngine.getSync(finalImportedPath);
239+
return finalImportedPathData;
240+
}
213241
} else {
214242
// Find in local variables of the file
215243
const variableDeclaration = file.getVariableDeclaration(metadataVariableName);
@@ -227,6 +255,16 @@ export class ImportsUtil {
227255
let compilerNode =
228256
initializer.compilerNode as ts.ObjectLiteralExpression;
229257
return compilerNode.properties;
258+
} else if (
259+
initializerKind &&
260+
(initializerKind === SyntaxKind.StringLiteral ||
261+
initializerKind === SyntaxKind.NoSubstitutionTemplateLiteral)
262+
) {
263+
if (decoratorType === 'template') {
264+
return initializer.getText();
265+
} else {
266+
return variableDeclaration.compilerNode;
267+
}
230268
} else if (initializerKind) {
231269
return variableDeclaration.compilerNode;
232270
}

test/fixtures/todomvc-ng2/src/app/about/about.component.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { Component, HostListener, Input } from '@angular/core';
22

3+
import template from './about.component.html';
4+
35
import { Subscription } from 'rxjs/Subscription';
46

57
/**
@@ -17,7 +19,7 @@ import { Subscription } from 'rxjs/Subscription';
1719
*/
1820
@Component({
1921
selector: 'about',
20-
templateUrl: './about.component.html',
22+
template,
2123
providers: [EmitterService],
2224
entryComponents: [TodoComponent, ListComponent],
2325
preserveWhitespaces: false

test/src/cli/cli-generation-big-app.spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,13 @@ describe('CLI simple generation - big app', () => {
123123
expect(file).to.contain('[donothing]');
124124
});
125125

126+
/**
127+
* Import for component template
128+
*/
129+
it('should have metadatas - component', () => {
130+
expect(aboutComponentFile).to.contain('example written using');
131+
});
132+
126133
/**
127134
* Routing
128135
*/

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"compilerOptions": {
3-
"lib": ["es6", "es7"]
3+
"lib": ["es6", "es7"],
4+
"downlevelIteration": true
45
},
56
"exclude": ["test"]
67
}

0 commit comments

Comments
 (0)