forked from angular/components
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathparse-example-file.ts
95 lines (81 loc) · 2.94 KB
/
parse-example-file.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import ts from 'typescript';
interface ParsedMetadata {
isPrimary: boolean;
componentName: string;
title: string;
selector: string;
templateUrl: string;
styleUrls: string[];
}
interface ParsedMetadataResults {
primaryComponent: ParsedMetadata | undefined;
secondaryComponents: ParsedMetadata[];
}
/** Parse the AST of the given source file and collect Angular component metadata. */
export function parseExampleFile(fileName: string, content: string): ParsedMetadataResults {
const sourceFile = ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, false);
const metas: ParsedMetadata[] = [];
const visitNode = (node: any): void => {
if (node.kind === ts.SyntaxKind.ClassDeclaration) {
const decorators = ts.getDecorators(node);
const meta = {
componentName: node.name.text,
} as ParsedMetadata;
if (node.jsDoc && node.jsDoc.length) {
for (const doc of node.jsDoc) {
if (doc.tags && doc.tags.length) {
for (const tag of doc.tags) {
const tagValue = tag.comment;
const tagName = tag.tagName.text;
if (tagName === 'title') {
meta.title = tagValue;
meta.isPrimary = true;
}
}
}
}
}
if (decorators && decorators.length) {
for (const decorator of decorators) {
const call = decorator.expression;
if (
!ts.isCallExpression(call) ||
!ts.isIdentifier(call.expression) ||
call.expression.text !== 'Component' ||
call.arguments.length === 0 ||
!ts.isObjectLiteralExpression(call.arguments[0])
) {
continue;
}
for (const prop of call.arguments[0].properties) {
if (!ts.isPropertyAssignment(prop) || !prop.name || !ts.isIdentifier(prop.name)) {
continue;
}
const propName = prop.name.text;
// Since additional files can be also stylesheets, we need to properly parse
// the styleUrls metadata property.
if (propName === 'styleUrls' && ts.isArrayLiteralExpression(prop.initializer)) {
meta[propName] = prop.initializer.elements.map(
literal => (literal as ts.StringLiteralLike).text,
);
} else if (propName === 'styleUrl' && ts.isStringLiteralLike(prop.initializer)) {
meta.styleUrls = [prop.initializer.text];
} else if (
ts.isStringLiteralLike(prop.initializer) ||
ts.isIdentifier(prop.initializer)
) {
(meta as any)[propName] = prop.initializer.text;
}
}
metas.push(meta);
}
}
}
ts.forEachChild(node, visitNode);
};
visitNode(sourceFile);
return {
primaryComponent: metas.find(m => m.isPrimary),
secondaryComponents: metas.filter(m => !m.isPrimary),
};
}