1import { parse } from './parser';
2
3const parseTag = (quasis, ...expressions) => parse(quasis, expressions);
4
5it('supports parsing expressions', () => {
6 expect(parseTag`${1}`).toEqual({
7 type: 'sequence',
8 sequence: [
9 {
10 type: 'expression',
11 expression: 1,
12 quantifier: null,
13 },
14 ],
15 alternation: null,
16 });
17});
18
19it('supports parsing expressions with quantifiers', () => {
20 let ast;
21
22 ast = parseTag`${1}?`;
23 expect(ast).toHaveProperty('sequence.0.type', 'expression');
24 expect(ast).toHaveProperty('sequence.0.quantifier', {
25 type: 'quantifier',
26 required: false,
27 singular: true,
28 });
29
30 ast = parseTag`${1}+`;
31 expect(ast).toHaveProperty('sequence.0.type', 'expression');
32 expect(ast).toHaveProperty('sequence.0.quantifier', {
33 type: 'quantifier',
34 required: true,
35 singular: false,
36 });
37
38 ast = parseTag`${1}*`;
39 expect(ast).toHaveProperty('sequence.0.type', 'expression');
40 expect(ast).toHaveProperty('sequence.0.quantifier', {
41 type: 'quantifier',
42 required: false,
43 singular: false,
44 });
45});
46
47it('supports top-level alternations', () => {
48 let ast;
49
50 ast = parseTag`${1} | ${2}`;
51 expect(ast).toHaveProperty('sequence.length', 1);
52 expect(ast).toHaveProperty('sequence.0.type', 'expression');
53 expect(ast).toHaveProperty('sequence.0.expression', 1);
54 expect(ast).toHaveProperty('alternation.type', 'sequence');
55 expect(ast).toHaveProperty('alternation.sequence.0.expression', 2);
56
57 ast = parseTag`${1}? | ${2}?`;
58 expect(ast).toHaveProperty('sequence.0.quantifier.type', 'quantifier');
59 expect(ast).toHaveProperty(
60 'alternation.sequence.0.quantifier.type',
61 'quantifier'
62 );
63});
64
65it('supports groups with quantifiers', () => {
66 let ast;
67
68 ast = parseTag`(${1} ${2})`;
69 expect(ast).toHaveProperty('sequence.length', 1);
70 expect(ast).toHaveProperty('sequence.0.type', 'group');
71 expect(ast).toHaveProperty('sequence.0.sequence.sequence.length', 2);
72 expect(ast).toHaveProperty('sequence.0.sequence.sequence.0.expression', 1);
73 expect(ast).toHaveProperty('sequence.0.sequence.sequence.1.expression', 2);
74
75 ast = parseTag`(${1} ${2}?)?`;
76 expect(ast).toHaveProperty('sequence.length', 1);
77 expect(ast).toHaveProperty('sequence.0.type', 'group');
78 expect(ast).toHaveProperty('sequence.0.quantifier.type', 'quantifier');
79 expect(ast).toHaveProperty('sequence.0.sequence.sequence.0.quantifier', null);
80 expect(ast).toHaveProperty(
81 'sequence.0.sequence.sequence.1.quantifier.type',
82 'quantifier'
83 );
84});
85
86it('supports non-capturing groups', () => {
87 const ast = parseTag`(?: ${1})`;
88 expect(ast).toHaveProperty('sequence.length', 1);
89 expect(ast).toHaveProperty('sequence.0.type', 'group');
90 expect(ast).toHaveProperty('sequence.0.capturing', false);
91 expect(ast).toHaveProperty('sequence.0.lookahead', null);
92 expect(ast).toHaveProperty('sequence.0.sequence.sequence.length', 1);
93});
94
95it('supports positive lookahead groups', () => {
96 const ast = parseTag`(?= ${1})`;
97 expect(ast).toHaveProperty('sequence.length', 1);
98 expect(ast).toHaveProperty('sequence.0.type', 'group');
99 expect(ast).toHaveProperty('sequence.0.capturing', false);
100 expect(ast).toHaveProperty('sequence.0.lookahead', 'positive');
101 expect(ast).toHaveProperty('sequence.0.sequence.sequence.length', 1);
102});
103
104it('supports negative lookahead groups', () => {
105 const ast = parseTag`(?! ${1})`;
106 expect(ast).toHaveProperty('sequence.length', 1);
107 expect(ast).toHaveProperty('sequence.0.type', 'group');
108 expect(ast).toHaveProperty('sequence.0.capturing', false);
109 expect(ast).toHaveProperty('sequence.0.lookahead', 'negative');
110 expect(ast).toHaveProperty('sequence.0.sequence.sequence.length', 1);
111});
112
113it('throws when a quantifier is combined with a lookahead', () => {
114 expect(() => parseTag`(?! ${1})+`).toThrow();
115 expect(() => parseTag`(?! ${1})?`).toThrow();
116 expect(() => parseTag`(?! ${1})*`).toThrow();
117});
118
119it('supports groups with alternates', () => {
120 expect(parseTag`(${1} | ${2}) ${3}`).toMatchInlineSnapshot(`
121 Object {
122 "alternation": null,
123 "sequence": Array [
124 Object {
125 "capturing": true,
126 "lookahead": null,
127 "quantifier": null,
128 "sequence": Object {
129 "alternation": Object {
130 "alternation": null,
131 "sequence": Array [
132 Object {
133 "expression": 2,
134 "quantifier": null,
135 "type": "expression",
136 },
137 ],
138 "type": "sequence",
139 },
140 "sequence": Array [
141 Object {
142 "expression": 1,
143 "quantifier": null,
144 "type": "expression",
145 },
146 ],
147 "type": "sequence",
148 },
149 "type": "group",
150 },
151 Object {
152 "expression": 3,
153 "quantifier": null,
154 "type": "expression",
155 },
156 ],
157 "type": "sequence",
158 }
159 `);
160});