forked from prettier/angular-estree-parser
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtransform.test.ts
More file actions
183 lines (170 loc) · 15.9 KB
/
transform.test.ts
File metadata and controls
183 lines (170 loc) · 15.9 KB
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import type * as angular from '@angular/compiler';
import type * as babelParser from '@babel/parser';
import type * as babel from '@babel/types';
import * as angularParser from '../src/angular-parser.js';
import * as estreeParser from '../src/estree-parser.js';
import type { NGNode } from '../src/types.js';
import {
getAngularNodeType,
massageAst,
parseBabel,
parseBabelExpression,
snapshotAst,
} from './helpers.js';
type BabelParseResult = ReturnType<typeof babelParser.parse>;
type BabelParseExpressionResult = ReturnType<
typeof babelParser.parseExpression
>;
const PARSE_METHODS = [
'parseAction',
'parseBinding',
'parseSimpleBinding',
'parseInterpolationExpression',
] as const;
describe.each`
expectedAngularType | expectedEstreeType | text | parseAction | parseBinding | parseSimpleBinding | parseInterpolationExpression
${'Binary'} | ${'BinaryExpression'} | ${' 0 - 1 '} | ${true} | ${true} | ${true} | ${true}
${'Binary'} | ${'BinaryExpression'} | ${' a ** b '} | ${true} | ${true} | ${true} | ${true}
${'Binary'} | ${'BinaryExpression'} | ${' ( ( ( ( a ) ) in ( ( b ) ) ) ) '} | ${true} | ${true} | ${true} | ${true}
${'Binary'} | ${'LogicalExpression'} | ${' a && b '} | ${true} | ${true} | ${true} | ${true}
${'Binary'} | ${'LogicalExpression'} | ${' a ?? b '} | ${true} | ${true} | ${true} | ${true}
${'Unary'} | ${'UnaryExpression'} | ${' - 1 '} | ${true} | ${true} | ${true} | ${true}
${'Unary'} | ${'UnaryExpression'} | ${' + 1 '} | ${true} | ${true} | ${true} | ${true}
${'BindingPipe'} | ${'NGPipeExpression'} | ${' a | b '} | ${false} | ${true} | ${false} | ${true}
${'BindingPipe'} | ${'NGPipeExpression'} | ${' a | b : c '} | ${false} | ${true} | ${false} | ${true}
${'Chain'} | ${'NGChainedExpression'} | ${' a ; b '} | ${true} | ${false} | ${false} | ${false}
${'Conditional'} | ${'ConditionalExpression'} | ${' a ? 1 : 2 '} | ${true} | ${true} | ${true} | ${true}
${'EmptyExpr'} | ${'NGEmptyExpression'} | ${''} | ${true} | ${true} | ${true} | ${true}
${'Call'} | ${'CallExpression'} | ${' ( a . b ) ( 1 , 2 ) '} | ${true} | ${true} | ${true} | ${true}
${'SafeCall'} | ${'OptionalCallExpression'} | ${' ( a . b )?.( 1 , 2 ) '} | ${true} | ${true} | ${true} | ${true}
${'Call'} | ${'CallExpression'} | ${' ( a ) ( 1 , 2 ) '} | ${true} | ${true} | ${true} | ${true}
${'SafeCall'} | ${'OptionalCallExpression'} | ${' ( a )?.( 1 , 2 ) '} | ${true} | ${true} | ${true} | ${true}
${'Call'} | ${'CallExpression'} | ${' a ( 1 ) ( 2 ) '} | ${true} | ${true} | ${true} | ${true}
${'SafeCall'} | ${'OptionalCallExpression'} | ${' a ( 1 )?.( 2 ) '} | ${true} | ${true} | ${true} | ${true}
${'KeyedRead'} | ${'MemberExpression'} | ${' a [ b ] '} | ${true} | ${true} | ${true} | ${true}
${'SafeKeyedRead'} | ${'OptionalMemberExpression'} | ${' a ?. [ b ] '} | ${true} | ${true} | ${true} | ${true}
${'KeyedRead'} | ${'OptionalMemberExpression'} | ${' a ?. b [ c ] '} | ${true} | ${true} | ${true} | ${true}
${'SafeKeyedRead'} | ${'OptionalMemberExpression'} | ${' a ?. b ?. [ c ] '} | ${true} | ${true} | ${true} | ${true}
${'KeyedRead'} | ${'OptionalMemberExpression'} | ${' a ?. b () [ c ] '} | ${true} | ${true} | ${true} | ${true}
${'SafeKeyedRead'} | ${'OptionalMemberExpression'} | ${' a ?. b () ?. [ c ] '} | ${true} | ${true} | ${true} | ${true}
${'KeyedWrite'} | ${'AssignmentExpression'} | ${' a [ b ] = 1 '} | ${true} | ${true} | ${true} | ${true}
${'ImplicitReceiver'} | ${'ThisExpression'} | ${' this '} | ${true} | ${true} | ${true} | ${true}
${'LiteralArray'} | ${'ArrayExpression'} | ${' [ 1 ] '} | ${true} | ${true} | ${true} | ${true}
${'LiteralMap'} | ${'ObjectExpression'} | ${' ( { "a" : 1 } )'} | ${true} | ${true} | ${true} | ${true}
${'LiteralMap'} | ${'ObjectExpression'} | ${' ( { a : 1 } ) '} | ${true} | ${true} | ${true} | ${true}
${'Call'} | ${'CallExpression'} | ${' f ( { a : 1 } ) '} | ${true} | ${true} | ${true} | ${true}
${'LiteralMap'} | ${'ObjectExpression'} | ${' ( {a, b: 2} ) '} | ${true} | ${true} | ${true} | ${true}
${'Call'} | ${'CallExpression'} | ${' f ( {a, b: 2} ) '} | ${true} | ${true} | ${true} | ${true}
${'LiteralMap'} | ${'ObjectExpression'} | ${' ( {a, b} ) '} | ${true} | ${true} | ${true} | ${true}
${'LiteralMap'} | ${'ObjectExpression'} | ${' ( { a, b} ) '} | ${true} | ${true} | ${true} | ${true}
${'LiteralPrimitive'} | ${'BooleanLiteral'} | ${' true '} | ${true} | ${true} | ${true} | ${true}
${'LiteralPrimitive'} | ${'Identifier'} | ${' undefined '} | ${true} | ${true} | ${true} | ${true}
${'LiteralPrimitive'} | ${'NullLiteral'} | ${' null '} | ${true} | ${true} | ${true} | ${true}
${'LiteralPrimitive'} | ${'NumericLiteral'} | ${' ( 1 ) '} | ${true} | ${true} | ${true} | ${true}
${'LiteralPrimitive'} | ${'NumericLiteral'} | ${' 1 '} | ${true} | ${true} | ${true} | ${true}
${'LiteralPrimitive'} | ${'StringLiteral'} | ${' ( "hello" ) '} | ${true} | ${true} | ${true} | ${true}
${'Call'} | ${'CallExpression'} | ${' a ( this ) '} | ${true} | ${true} | ${true} | ${true}
${'SafeCall'} | ${'OptionalCallExpression'} | ${' a ?.( this ) '} | ${true} | ${true} | ${true} | ${true}
${'Call'} | ${'CallExpression'} | ${' a ( b) '} | ${true} | ${true} | ${true} | ${true}
${'SafeCall'} | ${'OptionalCallExpression'} | ${' a ?.( b) '} | ${true} | ${true} | ${true} | ${true}
${'Call'} | ${'CallExpression'} | ${' a . b ( 1 , 2 ) '} | ${true} | ${true} | ${true} | ${true}
${'SafeCall'} | ${'OptionalCallExpression'} | ${' a . b ?.( 1 , 2 ) '} | ${true} | ${true} | ${true} | ${true}
${'Call'} | ${'CallExpression'} | ${' a ( 1 , 2 ) '} | ${true} | ${true} | ${true} | ${true}
${'SafeCall'} | ${'OptionalCallExpression'} | ${' a ?. ( 1 , 2 ) '} | ${true} | ${true} | ${true} | ${true}
${'Call'} | ${'OptionalCallExpression'} | ${' a ?. b . c ( ) '} | ${true} | ${true} | ${true} | ${true}
${'SafeCall'} | ${'OptionalCallExpression'} | ${' a ?. b . c ?. ( ) '} | ${true} | ${true} | ${true} | ${true}
${'Call'} | ${'OptionalCallExpression'} | ${' a ?. b ( ) . c ( ) '} | ${true} | ${true} | ${true} | ${true}
${'SafeCall'} | ${'OptionalCallExpression'} | ${' a ?. b ( ) . c ?.( ) '} | ${true} | ${true} | ${true} | ${true}
${'NonNullAssert'} | ${'TSNonNullExpression'} | ${' x ! '} | ${true} | ${true} | ${true} | ${true}
${'PrefixNot'} | ${'UnaryExpression'} | ${' ! x '} | ${true} | ${true} | ${true} | ${true}
${'PropertyRead'} | ${'Identifier'} | ${' ( ( a ) ) '} | ${true} | ${true} | ${true} | ${true}
${'PropertyRead'} | ${'Identifier'} | ${' a '} | ${true} | ${true} | ${true} | ${true}
${'PropertyRead'} | ${'Identifier'} | ${' a // hello '} | ${true} | ${true} | ${true} | ${true}
${'PropertyRead'} | ${'MemberExpression'} | ${' a . b '} | ${true} | ${true} | ${true} | ${true}
${'PropertyRead'} | ${'MemberExpression'} | ${' this . a '} | ${true} | ${true} | ${true} | ${true}
${'PropertyRead'} | ${'OptionalMemberExpression'} | ${' a ?. b . c '} | ${true} | ${true} | ${true} | ${true}
${'PropertyRead'} | ${'OptionalMemberExpression'} | ${' a ?. b ( ) . c '} | ${true} | ${true} | ${true} | ${true}
${'PropertyWrite'} | ${'AssignmentExpression'} | ${' a . b = 1 '} | ${true} | ${false} | ${false} | ${false}
${'PropertyWrite'} | ${'AssignmentExpression'} | ${' a = 1 '} | ${true} | ${false} | ${false} | ${false}
${'Call'} | ${'OptionalCallExpression'} | ${' a ?. b ( ) '} | ${true} | ${true} | ${true} | ${true}
${'SafeCall'} | ${'OptionalCallExpression'} | ${' a ?. b ?. ( ) '} | ${true} | ${true} | ${true} | ${true}
${'SafePropertyRead'} | ${'OptionalMemberExpression'} | ${' a ?. b '} | ${true} | ${true} | ${true} | ${true}
${'TypeofExpression'} | ${'UnaryExpression'} | ${' ( ( typeof {} ) ) '} | ${true} | ${true} | ${true} | ${true}
${'Binary'} | ${'BinaryExpression'} | ${' typeof {} === "object" '} | ${true} | ${true} | ${true} | ${true}
${'PrefixNot'} | ${'UnaryExpression'} | ${' ! ( typeof {} === "" ) '} | ${true} | ${true} | ${true} | ${true}
${'VoidExpression'} | ${'UnaryExpression'} | ${' ( ( void ( ( a() ) ) ) ) '} | ${true} | ${true} | ${true} | ${true}
${'TemplateLiteral'} | ${'TemplateLiteral'} | ${' ` a ${ b } \\u0063 ` '} | ${true} | ${true} | ${true} | ${true}
${'TemplateLiteral'} | ${'TemplateLiteral'} | ${' ( ( ` a ${ b } \\u0063 ` ) ) '} | ${true} | ${true} | ${true} | ${true}
${'TemplateLiteral'} | ${'TemplateLiteral'} | ${' ` \\u0063 ` '} | ${true} | ${true} | ${true} | ${true}
${'TemplateLiteral'} | ${'TemplateLiteral'} | ${' ( ( ` ` ) ) '} | ${true} | ${true} | ${true} | ${true}
${'TemplateLiteral'} | ${'TemplateLiteral'} | ${' `` '} | ${true} | ${true} | ${true} | ${true}
${'TaggedTemplateLiteral'} | ${'TaggedTemplateExpression'} | ${' tag ` a ${ b } \\u0063 ` '} | ${true} | ${true} | ${true} | ${true}
${'TaggedTemplateLiteral'} | ${'TaggedTemplateExpression'} | ${' ( ( ( ( tag ) ) ` a ${ b } \\u0063 ` ) ) '} | ${true} | ${true} | ${true} | ${true}
`('($expectedAngularType -> $expectedEstreeType)', (fields) => {
for (const method of PARSE_METHODS) {
testSection(method, fields);
}
});
function testSection(
method: (typeof PARSE_METHODS)[number],
fields: {
expectedAngularType: string;
expectedEstreeType: string;
text: string;
parseAction: boolean;
parseBinding: boolean;
parseSimpleBinding: boolean;
parseInterpolationExpression: boolean;
},
) {
const { expectedAngularType, expectedEstreeType, text } = fields;
const parseAngular = angularParser[method];
const parseEstree = estreeParser[method];
const isAllowed = fields[method];
if (!isAllowed) {
test(`disallowed in ${method}`, () => {
expect(() => parseAngular(text)).toThrow();
expect(() => parseEstree(text)).toThrow();
});
return;
}
let angularNode: angular.AST;
let estreeNode: NGNode;
let babelNode: (
| BabelParseResult
| BabelParseExpressionResult
| babel.Expression
) & { comments?: babel.Comment[] | null };
beforeAll(() => {
angularNode = parseAngular(text).result.ast;
if (method === 'parseInterpolationExpression') {
angularNode = (angularNode as angular.Interpolation).expressions[0];
}
estreeNode = parseEstree(text);
if (!estreeNode.type.startsWith('NG')) {
try {
babelNode = parseBabelExpression(text);
} catch {
babelNode = parseBabel(text);
}
}
});
test(`${method}(${JSON.stringify(text)})`, () => {
expect(angularNode).toBeDefined();
expect(estreeNode).toBeDefined();
expect(getAngularNodeType(angularNode)).toEqual(expectedAngularType);
expect(estreeNode.type).toEqual(expectedEstreeType);
if (estreeNode.type.startsWith('NG')) {
expect(snapshotAst(estreeNode, text)).toMatchSnapshot();
return;
}
expect(babelNode).toBeDefined();
if (babelNode.type === 'File') {
const { comments = [], program } = babelNode;
const statement = program.body[0] as babel.ExpressionStatement;
expect(statement.type).toEqual('ExpressionStatement');
babelNode = { ...statement.expression, comments };
}
expect(massageAst(estreeNode)).toEqual(massageAst(babelNode));
});
}