1 |
|
2 |
|
3 |
|
4 |
|
5 | import * as ts from 'typescript';
|
6 | import {
|
7 | isJsxAttribute,
|
8 | isJsxExpression,
|
9 | isStringLiteral,
|
10 | isNumericLiteral,
|
11 | isJsxElement,
|
12 | isJsxSelfClosingElement,
|
13 | isJsxOpeningElement,
|
14 | isFalseKeyword,
|
15 | isTrueKeyword,
|
16 | } from './TypeGuard';
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | export function getJsxAttributesFromJsxElement(node: ts.Node): { [propName: string]: ts.JsxAttribute } {
|
23 | const attributesDictionary: { [propName: string]: ts.JsxAttribute } = {};
|
24 |
|
25 | getAllAttributesFromJsxElement(node).forEach(attr => {
|
26 | if (isJsxAttribute(attr)) {
|
27 | attributesDictionary[getPropName(attr).toLowerCase()] = attr;
|
28 | }
|
29 | });
|
30 |
|
31 | return attributesDictionary;
|
32 | }
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 | export function getAllAttributesFromJsxElement(node: ts.Node): ts.NodeArray<ts.JsxAttributeLike> {
|
39 | let attributes: ts.NodeArray<ts.JsxAttributeLike>;
|
40 |
|
41 | if (node == null) {
|
42 | return <ts.NodeArray<ts.JsxAttributeLike>>(<any>[]);
|
43 | } else if (isJsxElement(node)) {
|
44 | attributes = node.openingElement.attributes.properties;
|
45 | } else if (isJsxSelfClosingElement(node)) {
|
46 | attributes = node.attributes.properties;
|
47 | } else if (isJsxOpeningElement(node)) {
|
48 | attributes = node.attributes.properties;
|
49 | } else {
|
50 | throw new Error('The node must be a JsxElement, JsxSelfClosingElement or JsxOpeningElement.');
|
51 | }
|
52 |
|
53 | return attributes;
|
54 | }
|
55 |
|
56 | export function getPropName(node: ts.JsxAttribute): string {
|
57 | if (!isJsxAttribute(node)) {
|
58 | throw new Error('The node must be a JsxAttribute collected by the AST parser.');
|
59 | }
|
60 |
|
61 | return node.name ? node.name.text : undefined;
|
62 | }
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 | export function getJsxElementFromCode(code: string, exceptTagName: string): ts.JsxElement | ts.JsxSelfClosingElement {
|
71 | const sourceFile: ts.SourceFile = ts.createSourceFile('test.tsx', code, ts.ScriptTarget.ES2015, true);
|
72 |
|
73 | return delintNode(sourceFile, exceptTagName);
|
74 | }
|
75 |
|
76 | function delintNode(node: ts.Node, tagName: string): ts.JsxElement | ts.JsxSelfClosingElement {
|
77 | if (isJsxElement(node) && node.openingElement.tagName.getText() === tagName) {
|
78 | return node;
|
79 | } else if (isJsxSelfClosingElement(node) && node.tagName.getText() === tagName) {
|
80 | return node;
|
81 | } else if (!node || node.getChildCount() === 0) {
|
82 | return undefined;
|
83 | }
|
84 |
|
85 | return ts.forEachChild(node, (childNode: ts.Node) => delintNode(childNode, tagName));
|
86 | }
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 | export function getAncestorNode(node: ts.Node, ancestorTagName: string): ts.JsxElement {
|
93 | if (!node) {
|
94 | return undefined;
|
95 | }
|
96 |
|
97 | const ancestorNode: ts.Node = node.parent;
|
98 |
|
99 | if (isJsxElement(ancestorNode) && ancestorNode.openingElement.tagName.getText() === ancestorTagName) {
|
100 | return ancestorNode;
|
101 | } else {
|
102 | return getAncestorNode(ancestorNode, ancestorTagName);
|
103 | }
|
104 | }
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 | export function getBooleanLiteral(node: ts.JsxAttribute): boolean {
|
116 | if (!isJsxAttribute(node)) {
|
117 | throw new Error('The node must be a JsxAttribute collected by the AST parser.');
|
118 | }
|
119 |
|
120 | const initializer: ts.Expression = node == null ? null : node.initializer;
|
121 | const getBooleanFromString: (value: string) => boolean = (value: string) => {
|
122 | if (value.toLowerCase() === 'true') {
|
123 | return true;
|
124 | } else if (value.toLowerCase() === 'false') {
|
125 | return false;
|
126 | } else {
|
127 | return undefined;
|
128 | }
|
129 | };
|
130 |
|
131 | if (isStringLiteral(initializer)) {
|
132 | return getBooleanFromString(initializer.text);
|
133 | } else if (isJsxExpression(initializer)) {
|
134 | const expression: ts.Expression = initializer.expression;
|
135 |
|
136 | if (isStringLiteral(expression)) {
|
137 | return getBooleanFromString(expression.text);
|
138 | } else {
|
139 | if (isTrueKeyword(expression)) {
|
140 | return true;
|
141 | } else if (isFalseKeyword(expression)) {
|
142 | return false;
|
143 | } else {
|
144 | return undefined;
|
145 | }
|
146 | }
|
147 | }
|
148 |
|
149 | return false;
|
150 | }
|
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 | export function getNumericLiteral(node: ts.JsxAttribute): string {
|
158 | if (!isJsxAttribute(node)) {
|
159 | throw new Error('The node must be a JsxAttribute collected by the AST parser.');
|
160 | }
|
161 |
|
162 | const initializer: ts.Expression = node == null ? null : node.initializer;
|
163 |
|
164 | return isJsxExpression(initializer) && isNumericLiteral(initializer.expression)
|
165 | ? (<ts.LiteralExpression>initializer.expression).text
|
166 | : undefined;
|
167 | }
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 | export function getStringLiteral(node: ts.JsxAttribute | ts.JsxSpreadAttribute): string {
|
177 | if (!isJsxAttribute(node)) {
|
178 | throw new Error('The node must be a JsxAttribute collected by the AST parser.');
|
179 | }
|
180 |
|
181 | const initializer: ts.Expression = node == null ? null : node.initializer;
|
182 |
|
183 | if (!initializer) {
|
184 |
|
185 | return '';
|
186 | } else if (isStringLiteral(initializer)) {
|
187 |
|
188 | return initializer.text.trim();
|
189 | } else if (isJsxExpression(initializer) && isStringLiteral(initializer.expression)) {
|
190 |
|
191 | return (<ts.StringLiteral>initializer.expression).text;
|
192 | } else if (isJsxExpression(initializer) && !initializer.expression) {
|
193 |
|
194 | return '';
|
195 | } else {
|
196 | return undefined;
|
197 | }
|
198 | }
|
199 |
|
200 | export function isEmpty(node: ts.JsxAttribute): boolean {
|
201 | const initializer: ts.Expression = node == null ? null : node.initializer;
|
202 |
|
203 | if (initializer == null) {
|
204 | return true;
|
205 | } else if (isStringLiteral(initializer)) {
|
206 | return initializer.text.trim() === '';
|
207 | } else if (initializer.kind === ts.SyntaxKind.Identifier) {
|
208 | return initializer.getText() === 'undefined';
|
209 | } else if (initializer.kind === ts.SyntaxKind.NullKeyword) {
|
210 | return true;
|
211 | } else if ((<any>initializer).expression != null) {
|
212 | const expression: ts.Expression = (<any>initializer).expression;
|
213 | if (expression.kind === ts.SyntaxKind.Identifier) {
|
214 | return expression.getText() === 'undefined';
|
215 | } else if (expression.kind === ts.SyntaxKind.NullKeyword) {
|
216 | return true;
|
217 | }
|
218 | }
|
219 | return false;
|
220 | }
|