@markuplint/astro-parser 3.6.2 → 3.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markuplint/astro-parser",
3
- "version": "3.6.2",
3
+ "version": "3.6.3",
4
4
  "description": "astro parser for markuplint",
5
5
  "repository": "git@github.com:markuplint/markuplint.git",
6
6
  "author": "Yusuke Hirao <yusukehirao@me.com>",
@@ -15,16 +15,13 @@
15
15
  "build": "tsc",
16
16
  "clean": "tsc --build --clean"
17
17
  },
18
- "devDependencies": {
19
- "@astrojs/parser": "0.22.2"
20
- },
21
18
  "dependencies": {
22
- "@astrojs/parser": "0.20",
23
- "@markuplint/html-parser": "3.6.1",
19
+ "@astrojs/parser": "0.22.2",
20
+ "@markuplint/html-parser": "3.7.0",
24
21
  "@markuplint/ml-ast": "3.1.0",
25
- "@markuplint/parser-utils": "3.6.1",
22
+ "@markuplint/parser-utils": "3.7.0",
26
23
  "astro-eslint-parser": "^0.13.2",
27
24
  "tslib": "^2.4.1"
28
25
  },
29
- "gitHead": "884e8dbf60ec2a350761d5cda3cdc0725881b9dc"
26
+ "gitHead": "adc6e432cccba7cfad0dc8bf9f92e5aaf1107359"
30
27
  }
@@ -0,0 +1,444 @@
1
+ const { astroParse } = require('../lib/astro-parser');
2
+
3
+ it('Basic', () => {
4
+ const ast = astroParse(`---
5
+ const name = "World";
6
+ ---
7
+ <!-- Comment -->
8
+ <style>
9
+ div {
10
+ color: red;
11
+ }
12
+ </style>
13
+ <div data-attr="v">Hello {name}!</div>
14
+ `);
15
+ expect(ast).toStrictEqual(
16
+ expect.objectContaining({
17
+ children: [
18
+ {
19
+ position: {
20
+ end: {
21
+ column: 4,
22
+ line: 3,
23
+ offset: 29,
24
+ },
25
+ start: {
26
+ column: 1,
27
+ line: 1,
28
+ offset: 0,
29
+ },
30
+ },
31
+ type: 'frontmatter',
32
+ value: '\nconst name = "World";\n',
33
+ },
34
+ {
35
+ position: {
36
+ end: {
37
+ column: 17,
38
+ line: 4,
39
+ offset: 46,
40
+ },
41
+ start: {
42
+ column: 5,
43
+ line: 4,
44
+ offset: 30,
45
+ },
46
+ },
47
+ type: 'comment',
48
+ value: ' Comment ',
49
+ },
50
+ {
51
+ attributes: [],
52
+ children: [
53
+ {
54
+ position: {
55
+ end: {
56
+ column: 1,
57
+ line: 9,
58
+ offset: 79,
59
+ },
60
+ start: {
61
+ column: 8,
62
+ line: 5,
63
+ offset: 54,
64
+ },
65
+ },
66
+ type: 'text',
67
+ value: '\ndiv {\n color: red;\n}\n',
68
+ },
69
+ ],
70
+ name: 'style',
71
+ position: {
72
+ end: {
73
+ column: 9,
74
+ line: 9,
75
+ offset: 87,
76
+ },
77
+ start: {
78
+ column: 1,
79
+ line: 5,
80
+ offset: 47,
81
+ },
82
+ },
83
+ type: 'element',
84
+ },
85
+ {
86
+ position: {
87
+ end: {
88
+ column: 1,
89
+ line: 10,
90
+ offset: 88,
91
+ },
92
+ start: {
93
+ column: 9,
94
+ line: 9,
95
+ offset: 87,
96
+ },
97
+ },
98
+ type: 'text',
99
+ value: '\n',
100
+ },
101
+ {
102
+ attributes: [
103
+ {
104
+ kind: 'quoted',
105
+ name: 'data-attr',
106
+ position: {
107
+ start: {
108
+ column: 6,
109
+ line: 10,
110
+ offset: 93,
111
+ },
112
+ },
113
+ type: 'attribute',
114
+ value: 'v',
115
+ },
116
+ ],
117
+ children: [
118
+ {
119
+ position: {
120
+ end: {
121
+ column: 26,
122
+ line: 10,
123
+ offset: 113,
124
+ },
125
+ start: {
126
+ column: 20,
127
+ line: 10,
128
+ offset: 107,
129
+ },
130
+ },
131
+ type: 'text',
132
+ value: 'Hello ',
133
+ },
134
+ {
135
+ children: [
136
+ {
137
+ position: {
138
+ end: {
139
+ column: 31,
140
+ line: 10,
141
+ offset: 118,
142
+ },
143
+ start: {
144
+ column: 27,
145
+ line: 10,
146
+ offset: 114,
147
+ },
148
+ },
149
+ type: 'text',
150
+ value: 'name',
151
+ },
152
+ ],
153
+ position: {
154
+ end: {
155
+ column: 9,
156
+ line: 11,
157
+ offset: 119,
158
+ },
159
+ start: {
160
+ column: 25,
161
+ line: 10,
162
+ offset: 113,
163
+ },
164
+ },
165
+ type: 'expression',
166
+ },
167
+ {
168
+ position: {
169
+ end: {
170
+ column: 33,
171
+ line: 10,
172
+ offset: 120,
173
+ },
174
+ start: {
175
+ column: 32,
176
+ line: 10,
177
+ offset: 119,
178
+ },
179
+ },
180
+ type: 'text',
181
+ value: '!',
182
+ },
183
+ ],
184
+ name: 'div',
185
+ position: {
186
+ end: {
187
+ column: 39,
188
+ line: 10,
189
+ offset: 126,
190
+ },
191
+ start: {
192
+ column: 1,
193
+ line: 10,
194
+ offset: 88,
195
+ },
196
+ },
197
+ type: 'element',
198
+ },
199
+ {
200
+ position: {
201
+ end: {
202
+ column: 1,
203
+ line: 11,
204
+ offset: 127,
205
+ },
206
+ start: {
207
+ column: 39,
208
+ line: 10,
209
+ offset: 126,
210
+ },
211
+ },
212
+ type: 'text',
213
+ value: '\n',
214
+ },
215
+ ],
216
+ type: 'root',
217
+ }),
218
+ );
219
+ });
220
+
221
+ it('Attr and Template Directive', () => {
222
+ const ast = astroParse('<div a b=c d="e" f=`g` x:y prop={ prop }></div>');
223
+ expect(ast.children?.[0].attributes).toStrictEqual(
224
+ expect.objectContaining([
225
+ {
226
+ type: 'attribute',
227
+ kind: 'empty',
228
+ name: 'a',
229
+ value: '',
230
+ position: { start: { column: 6, line: 1, offset: 5 } },
231
+ },
232
+ {
233
+ type: 'attribute',
234
+ kind: 'quoted',
235
+ name: 'b',
236
+ value: 'c',
237
+ position: { start: { column: 8, line: 1, offset: 7 } },
238
+ },
239
+ {
240
+ type: 'attribute',
241
+ kind: 'quoted',
242
+ name: 'd',
243
+ value: 'e',
244
+ position: { start: { column: 12, line: 1, offset: 11 } },
245
+ },
246
+ {
247
+ type: 'attribute',
248
+ kind: 'template-literal',
249
+ name: 'f',
250
+ value: 'g',
251
+ position: { start: { column: 18, line: 1, offset: 17 } },
252
+ },
253
+ {
254
+ type: 'attribute',
255
+ kind: 'empty',
256
+ name: 'x:y',
257
+ value: '',
258
+ position: { start: { column: 24, line: 1, offset: 23 } },
259
+ },
260
+ {
261
+ type: 'attribute',
262
+ kind: 'expression',
263
+ name: 'prop',
264
+ value: ' prop ',
265
+ position: { start: { column: 28, line: 1, offset: 27 } },
266
+ },
267
+ ]),
268
+ );
269
+ });
270
+
271
+ test('Greater-than sign in attribute value', () => {
272
+ const ast = astroParse('<div attr="a>b"></div>');
273
+ expect(ast.children?.[0].attributes).toStrictEqual(
274
+ expect.objectContaining([
275
+ {
276
+ kind: 'quoted',
277
+ name: 'attr',
278
+ position: { start: { column: 6, line: 1, offset: 5 } },
279
+ type: 'attribute',
280
+ value: 'a>b',
281
+ },
282
+ ]),
283
+ );
284
+ });
285
+
286
+ describe('Issues', () => {
287
+ test('#803', () => {
288
+ const code = `<html lang="en">
289
+ <head>
290
+ <meta charset="utf-8" />
291
+ <title>Title</title>
292
+ <meta name="viewport" content="width=device-width" />
293
+ </head>
294
+ </html>
295
+ `;
296
+ const ast = astroParse(code);
297
+ expect(ast).toStrictEqual(
298
+ expect.objectContaining({
299
+ type: 'root',
300
+ children: [
301
+ {
302
+ type: 'element',
303
+ name: 'html',
304
+ position: { start: { line: 1, column: 2, offset: 0 } },
305
+ attributes: [
306
+ {
307
+ type: 'attribute',
308
+ kind: 'quoted',
309
+ name: 'lang',
310
+ value: 'en',
311
+ position: { start: { line: 1, column: 7, offset: 6 } },
312
+ },
313
+ ],
314
+ children: [
315
+ {
316
+ type: 'text',
317
+ value: '\n\t',
318
+ position: {
319
+ start: { line: 1, column: 17, offset: 16 },
320
+ end: { line: 2, column: 2, offset: 18 },
321
+ },
322
+ },
323
+ {
324
+ type: 'element',
325
+ name: 'head',
326
+ attributes: [],
327
+ position: {
328
+ start: { line: 2, column: 2, offset: 18 },
329
+ end: { line: 6, column: 9, offset: 139 },
330
+ },
331
+ children: [
332
+ {
333
+ type: 'text',
334
+ value: '\n\t\t',
335
+ position: {
336
+ start: { line: 2, column: 8, offset: 24 },
337
+ end: { line: 3, column: 3, offset: 27 },
338
+ },
339
+ },
340
+ {
341
+ type: 'element',
342
+ name: 'meta',
343
+ position: { start: { line: 3, column: 4, offset: 27 } },
344
+ attributes: [
345
+ {
346
+ type: 'attribute',
347
+ kind: 'quoted',
348
+ name: 'charset',
349
+ value: 'utf-8',
350
+ position: { start: { line: 3, column: 9, offset: 33 } },
351
+ },
352
+ ],
353
+ children: [],
354
+ },
355
+ {
356
+ type: 'text',
357
+ value: '\n\t\t',
358
+ position: {
359
+ start: { line: 3, column: 27, offset: 51 },
360
+ end: { line: 4, column: 3, offset: 54 },
361
+ },
362
+ },
363
+ {
364
+ type: 'element',
365
+ name: 'title',
366
+ position: {
367
+ start: { line: 4, column: 3, offset: 54 },
368
+ end: { line: 4, column: 23, offset: 74 },
369
+ },
370
+ attributes: [],
371
+ children: [
372
+ {
373
+ type: 'text',
374
+ value: 'Title',
375
+ position: {
376
+ start: { line: 4, column: 10, offset: 61 },
377
+ end: { line: 4, column: 15, offset: 66 },
378
+ },
379
+ },
380
+ ],
381
+ },
382
+ {
383
+ type: 'text',
384
+ value: '\n\t\t',
385
+ position: {
386
+ start: { line: 4, column: 23, offset: 74 },
387
+ end: { line: 5, column: 3, offset: 77 },
388
+ },
389
+ },
390
+ {
391
+ type: 'element',
392
+ name: 'meta',
393
+ attributes: [
394
+ {
395
+ type: 'attribute',
396
+ kind: 'quoted',
397
+ name: 'name',
398
+ value: 'viewport',
399
+ position: { start: { line: 5, column: 9, offset: 83 } },
400
+ },
401
+ {
402
+ type: 'attribute',
403
+ kind: 'quoted',
404
+ name: 'content',
405
+ value: 'width=device-width',
406
+ position: { start: { line: 5, column: 25, offset: 99 } },
407
+ },
408
+ ],
409
+ position: { start: { line: 5, column: 4, offset: 77 } },
410
+ children: [],
411
+ },
412
+ {
413
+ type: 'text',
414
+ value: '\n\t',
415
+ position: {
416
+ start: { line: 5, column: 56, offset: 130 },
417
+ end: { line: 6, column: 2, offset: 132 },
418
+ },
419
+ },
420
+ ],
421
+ },
422
+ {
423
+ type: 'text',
424
+ value: '\n',
425
+ position: {
426
+ start: { line: 6, column: 9, offset: 139 },
427
+ end: { line: 7, column: 1, offset: 140 },
428
+ },
429
+ },
430
+ {
431
+ type: 'text',
432
+ value: '',
433
+ position: {
434
+ start: { line: 7, column: 8, offset: 140 },
435
+ end: { line: 8, column: 1, offset: 140 },
436
+ },
437
+ },
438
+ ],
439
+ },
440
+ ],
441
+ }),
442
+ );
443
+ });
444
+ });
@@ -0,0 +1,483 @@
1
+ const { nodeListToDebugMaps } = require('@markuplint/parser-utils');
2
+
3
+ const { parse } = require('../lib/parse');
4
+
5
+ it('Basic', () => {
6
+ const ast = parse(`---
7
+ const name = "World";
8
+ ---
9
+ <!-- Comment -->
10
+ <style>
11
+ div {
12
+ color: red;
13
+ }
14
+ </style>
15
+ <div data-attr="value" data-dynamic={value}>Hello {name}!</div>
16
+ <ul>
17
+ {list.map(item => <li>{item}</li>)}
18
+ </ul>
19
+ `);
20
+ const map = nodeListToDebugMaps(ast.nodeList, true);
21
+ expect(map).toEqual([
22
+ '[1:1]>[4:1](0,30)#text: ␣␣␣⏎␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣⏎␣␣␣⏎',
23
+ '[4:1]>[4:17](30,46)#comment: <!--␣Comment␣-->',
24
+ '[4:17]>[5:1](46,47)#text: ⏎',
25
+ '[5:1]>[5:8](47,54)style: <style>',
26
+ '[9:1]>[9:9](79,87)style: </style>',
27
+ '[9:9]>[10:1](87,88)#text: ⏎',
28
+ '[10:1]>[10:45](88,132)div: <div␣data-attr="value"␣data-dynamic={value}>',
29
+ '[10:6]>[10:23](93,110)data-attr: data-attr="value"',
30
+ ' [10:6]>[10:6](93,93)bN: ',
31
+ ' [10:6]>[10:15](93,102)name: data-attr',
32
+ ' [10:15]>[10:15](102,102)bE: ',
33
+ ' [10:15]>[10:16](102,103)equal: =',
34
+ ' [10:16]>[10:16](103,103)aE: ',
35
+ ' [10:16]>[10:17](103,104)sQ: "',
36
+ ' [10:17]>[10:22](104,109)value: value',
37
+ ' [10:22]>[10:23](109,110)eQ: "',
38
+ ' isDirective: false',
39
+ ' isDynamicValue: false',
40
+ '[10:24]>[10:44](111,131)data-dynamic: data-dynamic={value}',
41
+ ' [10:24]>[10:24](111,111)bN: ',
42
+ ' [10:24]>[10:36](111,123)name: data-dynamic',
43
+ ' [10:36]>[10:36](123,123)bE: ',
44
+ ' [10:36]>[10:37](123,124)equal: =',
45
+ ' [10:37]>[10:37](124,124)aE: ',
46
+ ' [10:37]>[10:38](124,125)sQ: {',
47
+ ' [10:38]>[10:43](125,130)value: value',
48
+ ' [10:43]>[10:44](130,131)eQ: }',
49
+ ' isDirective: false',
50
+ ' isDynamicValue: true',
51
+ '[10:45]>[10:51](132,138)#text: Hello␣',
52
+ '[10:51]>[10:57](138,144)MustacheTag: {name}',
53
+ '[10:57]>[10:58](144,145)#text: !',
54
+ '[10:58]>[10:64](145,151)div: </div>',
55
+ '[10:64]>[11:1](151,152)#text: ⏎',
56
+ '[11:1]>[11:5](152,156)ul: <ul>',
57
+ '[11:5]>[12:1](156,157)#text: ⏎',
58
+ '[12:1]>[12:19](157,175)MustacheTag: {list.map(item␣=>␣',
59
+ '[12:19]>[12:23](175,179)li: <li>',
60
+ '[12:23]>[12:29](179,185)MustacheTag: {item}',
61
+ '[12:29]>[12:34](185,190)li: </li>',
62
+ '[12:34]>[12:36](190,192)MustacheTag: )}',
63
+ '[12:36]>[13:1](192,193)#text: ⏎',
64
+ '[13:1]>[13:6](193,198)ul: </ul>',
65
+ '[13:6]>[14:1](198,199)#text: ⏎',
66
+ ]);
67
+ });
68
+
69
+ it('HTML', () => {
70
+ const ast = parse(`<html>
71
+ <head>
72
+ <style>
73
+ ...
74
+ </style>
75
+ </head>
76
+ <body>...</body>
77
+ </html>
78
+ `);
79
+ const map = nodeListToDebugMaps(ast.nodeList, true);
80
+ expect(map).toEqual([
81
+ '[1:1]>[1:7](0,6)html: <html>',
82
+ '[1:7]>[2:3](6,9)#text: ⏎␣␣',
83
+ '[2:3]>[2:9](9,15)head: <head>',
84
+ '[2:9]>[3:5](15,20)#text: ⏎␣␣␣␣',
85
+ '[3:5]>[3:12](20,27)style: <style>',
86
+ '[5:5]>[5:13](42,50)style: </style>',
87
+ '[5:13]>[6:3](50,53)#text: ⏎␣␣',
88
+ '[6:3]>[6:10](53,60)head: </head>',
89
+ '[6:10]>[7:3](60,63)#text: ⏎␣␣',
90
+ '[7:3]>[7:9](63,69)body: <body>',
91
+ '[7:9]>[7:12](69,72)#text: ...',
92
+ '[7:12]>[7:19](72,79)body: </body>',
93
+ '[7:19]>[8:1](79,80)#text: ⏎',
94
+ '[8:1]>[8:8](80,87)html: </html>',
95
+ '[8:8]>[9:1](87,88)#text: ⏎',
96
+ ]);
97
+ });
98
+
99
+ it('Attributes', () => {
100
+ const ast = parse('<CustomComponent prop1 prop2="value2" prop3={value3}></CustomComponent>');
101
+ const map = nodeListToDebugMaps(ast.nodeList, true);
102
+ expect(map).toEqual([
103
+ '[1:1]>[1:54](0,53)CustomComponent: <CustomComponent␣prop1␣prop2="value2"␣prop3={value3}>',
104
+ '[1:18]>[1:23](17,22)prop1: prop1',
105
+ ' [1:18]>[1:18](17,17)bN: ',
106
+ ' [1:18]>[1:23](17,22)name: prop1',
107
+ ' [1:23]>[1:23](22,22)bE: ',
108
+ ' [1:23]>[1:23](22,22)equal: ',
109
+ ' [1:23]>[1:23](22,22)aE: ',
110
+ ' [1:23]>[1:23](22,22)sQ: ',
111
+ ' [1:23]>[1:23](22,22)value: ',
112
+ ' [1:23]>[1:23](22,22)eQ: ',
113
+ ' isDirective: false',
114
+ ' isDynamicValue: false',
115
+ '[1:24]>[1:38](23,37)prop2: prop2="value2"',
116
+ ' [1:24]>[1:24](23,23)bN: ',
117
+ ' [1:24]>[1:29](23,28)name: prop2',
118
+ ' [1:29]>[1:29](28,28)bE: ',
119
+ ' [1:29]>[1:30](28,29)equal: =',
120
+ ' [1:30]>[1:30](29,29)aE: ',
121
+ ' [1:30]>[1:31](29,30)sQ: "',
122
+ ' [1:31]>[1:37](30,36)value: value2',
123
+ ' [1:37]>[1:38](36,37)eQ: "',
124
+ ' isDirective: false',
125
+ ' isDynamicValue: false',
126
+ '[1:39]>[1:53](38,52)prop3: prop3={value3}',
127
+ ' [1:39]>[1:39](38,38)bN: ',
128
+ ' [1:39]>[1:44](38,43)name: prop3',
129
+ ' [1:44]>[1:44](43,43)bE: ',
130
+ ' [1:44]>[1:45](43,44)equal: =',
131
+ ' [1:45]>[1:45](44,44)aE: ',
132
+ ' [1:45]>[1:46](44,45)sQ: {',
133
+ ' [1:46]>[1:52](45,51)value: value3',
134
+ ' [1:52]>[1:53](51,52)eQ: }',
135
+ ' isDirective: false',
136
+ ' isDynamicValue: true',
137
+ '[1:54]>[1:72](53,71)CustomComponent: </CustomComponent>',
138
+ ]);
139
+ });
140
+
141
+ it('CustomComponent', () => {
142
+ const ast = parse('<CustomComponent />');
143
+ const map = nodeListToDebugMaps(ast.nodeList);
144
+ expect(map).toEqual(['[1:1]>[1:20](0,19)CustomComponent: <CustomComponent␣/>']);
145
+ });
146
+
147
+ it('Siblings', () => {
148
+ const ast = parse('<tag1 /><tag2 /><tag3 />');
149
+ const map = nodeListToDebugMaps(ast.nodeList);
150
+ expect(map).toEqual([
151
+ '[1:1]>[1:9](0,8)tag1: <tag1␣/>',
152
+ '[1:9]>[1:17](8,16)tag2: <tag2␣/>',
153
+ '[1:17]>[1:25](16,24)tag3: <tag3␣/>',
154
+ ]);
155
+ });
156
+
157
+ it('Siblings2', () => {
158
+ const ast = parse('<tag1></tag1><tag2 attr></tag2><tag3 attr2></tag3>');
159
+ const map = nodeListToDebugMaps(ast.nodeList);
160
+ expect(map).toEqual([
161
+ '[1:1]>[1:7](0,6)tag1: <tag1>',
162
+ '[1:7]>[1:14](6,13)tag1: </tag1>',
163
+ '[1:14]>[1:25](13,24)tag2: <tag2␣attr>',
164
+ '[1:25]>[1:32](24,31)tag2: </tag2>',
165
+ '[1:32]>[1:44](31,43)tag3: <tag3␣attr2>',
166
+ '[1:44]>[1:51](43,50)tag3: </tag3>',
167
+ ]);
168
+ });
169
+
170
+ it('Pear', () => {
171
+ expect(parse('<tag1></tag1>').nodeList[0].pearNode?.raw).toBe('</tag1>');
172
+ expect(parse('<tag1><tag2 /></tag1>').nodeList[1].pearNode?.raw).toBeUndefined();
173
+ expect(parse('<tag1><tag2></tag2></tag1>').nodeList[1].pearNode?.raw).toBe('</tag2>');
174
+ });
175
+
176
+ it('Missing end tag', () => {
177
+ const ast = parse('<div><span><span /></div>');
178
+ const map = nodeListToDebugMaps(ast.nodeList);
179
+ expect(map).toEqual([
180
+ '[1:1]>[1:6](0,5)div: <div>',
181
+ '[1:6]>[1:12](5,11)span: <span>',
182
+ '[1:12]>[1:20](11,19)span: <span␣/>',
183
+ '[1:20]>[1:26](19,25)#text: </div>',
184
+ ]);
185
+ });
186
+
187
+ it('Doctype', () => {
188
+ const ast = parse('<!doctype html>\n<html></html>');
189
+ const map = nodeListToDebugMaps(ast.nodeList);
190
+ expect(map).toEqual([
191
+ '[1:1]>[1:16](0,15)#doctype: <!doctype␣html>',
192
+ '[1:16]>[2:1](15,16)#text: ⏎',
193
+ '[2:1]>[2:7](16,22)html: <html>',
194
+ '[2:7]>[2:14](22,29)html: </html>',
195
+ ]);
196
+ });
197
+
198
+ it('namespace', () => {
199
+ const doc = parse('<div><svg><text /></svg></div>');
200
+ expect(doc.nodeList[0].nodeName).toBe('div');
201
+ expect(doc.nodeList[0].namespace).toBe('http://www.w3.org/1999/xhtml');
202
+ expect(doc.nodeList[1].nodeName).toBe('svg');
203
+ expect(doc.nodeList[1].namespace).toBe('http://www.w3.org/2000/svg');
204
+ expect(doc.nodeList[2].nodeName).toBe('text');
205
+ expect(doc.nodeList[2].namespace).toBe('http://www.w3.org/2000/svg');
206
+
207
+ const doc2 = parse('<svg><foreignObject><div></div></foreignObject></svg>');
208
+ expect(doc2.nodeList[0].nodeName).toBe('svg');
209
+ expect(doc2.nodeList[0].namespace).toBe('http://www.w3.org/2000/svg');
210
+ expect(doc2.nodeList[1].nodeName).toBe('foreignObject');
211
+ expect(doc2.nodeList[1].namespace).toBe('http://www.w3.org/2000/svg');
212
+ expect(doc2.nodeList[2].nodeName).toBe('div');
213
+ expect(doc2.nodeList[2].namespace).toBe('http://www.w3.org/1999/xhtml');
214
+ });
215
+
216
+ describe('Issue', () => {
217
+ test('#549', () => {
218
+ const ast = parse(`<ul>{
219
+ list.map(() => <li></li>)
220
+ }</ul>`);
221
+ const map = nodeListToDebugMaps(ast.nodeList);
222
+ expect(map).toEqual([
223
+ '[1:1]>[1:5](0,4)ul: <ul>',
224
+ '[1:5]>[2:17](4,22)MustacheTag: {⏎→list.map(()␣=>␣',
225
+ '[2:17]>[2:21](22,26)li: <li>',
226
+ '[2:21]>[2:26](26,31)li: </li>',
227
+ '[2:26]>[3:2](31,34)MustacheTag: )⏎}',
228
+ '[3:2]>[3:7](34,39)ul: </ul>',
229
+ ]);
230
+ });
231
+
232
+ test('#575', () => {
233
+ const ast = parse('<div class:list={["class-name"]}></div>');
234
+ const map = nodeListToDebugMaps(ast.nodeList, true);
235
+ expect(map).toEqual([
236
+ '[1:1]>[1:34](0,33)div: <div␣class:list={["class-name"]}>',
237
+ '[1:6]>[1:33](5,32)class: class:list={["class-name"]}',
238
+ ' [1:6]>[1:6](5,5)bN: ',
239
+ ' [1:6]>[1:16](5,15)name: class:list',
240
+ ' [1:16]>[1:16](15,15)bE: ',
241
+ ' [1:16]>[1:17](15,16)equal: =',
242
+ ' [1:17]>[1:17](16,16)aE: ',
243
+ ' [1:17]>[1:18](16,17)sQ: {',
244
+ ' [1:18]>[1:32](17,31)value: ["class-name"]',
245
+ ' [1:32]>[1:33](31,32)eQ: }',
246
+ ' isDirective: false',
247
+ ' isDynamicValue: true',
248
+ ' potentialName: class',
249
+ '[1:34]>[1:40](33,39)div: </div>',
250
+ ]);
251
+ });
252
+
253
+ test('#739', () => {
254
+ const ast = parse(`<div>
255
+ {
256
+ type === 'checkbox' ? (
257
+ <fieldset>
258
+ <legend>{label}</legend>
259
+ <div>
260
+ {values.map((value) => (
261
+ <label>
262
+ <input type="checkbox" value={value} />
263
+ <span>{value}</span>
264
+ </label>
265
+ ))}
266
+ </div>
267
+ </fieldset>
268
+ ) : (
269
+ <label>
270
+ <span>{label}</span>
271
+ {type === 'textarea' ? <textarea /> : <input type={type} />}
272
+ </label>
273
+ )
274
+ }
275
+ </div>
276
+ `);
277
+ const map = nodeListToDebugMaps(ast.nodeList, true);
278
+ expect(map).toEqual([
279
+ '[1:1]>[1:6](0,5)div: <div>',
280
+ '[1:6]>[2:2](5,7)#text: ⏎→',
281
+ "[2:2]>[4:4](7,38)MustacheTag: {⏎→→type␣===␣'checkbox'␣?␣(⏎→→→",
282
+ '[4:4]>[4:14](38,48)fieldset: <fieldset>',
283
+ '[4:14]>[5:5](48,53)#text: ⏎→→→→',
284
+ '[5:5]>[5:13](53,61)legend: <legend>',
285
+ '[5:13]>[5:20](61,68)MustacheTag: {label}',
286
+ '[5:20]>[5:29](68,77)legend: </legend>',
287
+ '[5:29]>[6:5](77,82)#text: ⏎→→→→',
288
+ '[6:5]>[6:10](82,87)div: <div>',
289
+ '[6:10]>[7:6](87,93)#text: ⏎→→→→→',
290
+ '[7:6]>[8:7](93,124)MustacheTag: {values.map((value)␣=>␣(⏎→→→→→→',
291
+ '[8:7]>[8:14](124,131)label: <label>',
292
+ '[8:14]>[9:8](131,139)#text: ⏎→→→→→→→',
293
+ '[9:8]>[9:47](139,178)input: <input␣type="checkbox"␣value={value}␣/>',
294
+ '[9:15]>[9:30](146,161)type: type="checkbox"',
295
+ ' [9:15]>[9:15](146,146)bN: ',
296
+ ' [9:15]>[9:19](146,150)name: type',
297
+ ' [9:19]>[9:19](150,150)bE: ',
298
+ ' [9:19]>[9:20](150,151)equal: =',
299
+ ' [9:20]>[9:20](151,151)aE: ',
300
+ ' [9:20]>[9:21](151,152)sQ: "',
301
+ ' [9:21]>[9:29](152,160)value: checkbox',
302
+ ' [9:29]>[9:30](160,161)eQ: "',
303
+ ' isDirective: false',
304
+ ' isDynamicValue: false',
305
+ '[9:31]>[9:45](162,176)value: value={value}␣',
306
+ ' [9:31]>[9:31](162,162)bN: ',
307
+ ' [9:31]>[9:36](162,167)name: value',
308
+ ' [9:36]>[9:36](167,167)bE: ',
309
+ ' [9:36]>[9:37](167,168)equal: =',
310
+ ' [9:37]>[9:37](168,168)aE: ',
311
+ ' [9:37]>[9:38](168,169)sQ: {',
312
+ ' [9:38]>[9:43](169,174)value: value',
313
+ ' [9:43]>[9:44](174,175)eQ: }',
314
+ ' isDirective: false',
315
+ ' isDynamicValue: true',
316
+ '[9:47]>[10:8](178,186)#text: ⏎→→→→→→→',
317
+ '[10:8]>[10:14](186,192)span: <span>',
318
+ '[10:14]>[10:21](192,199)MustacheTag: {value}',
319
+ '[10:21]>[10:28](199,206)span: </span>',
320
+ '[10:28]>[11:7](206,213)#text: ⏎→→→→→→',
321
+ '[11:7]>[11:15](213,221)label: </label>',
322
+ '[11:15]>[12:9](221,230)MustacheTag: ⏎→→→→→))}',
323
+ '[12:9]>[13:5](230,235)#text: ⏎→→→→',
324
+ '[13:5]>[13:11](235,241)div: </div>',
325
+ '[13:11]>[14:4](241,245)#text: ⏎→→→',
326
+ '[14:4]>[14:15](245,256)fieldset: </fieldset>',
327
+ '[16:4]>[16:11](268,275)label: <label>',
328
+ '[16:11]>[17:5](275,280)#text: ⏎→→→→',
329
+ '[17:5]>[17:11](280,286)span: <span>',
330
+ '[17:11]>[17:18](286,293)MustacheTag: {label}',
331
+ '[17:18]>[17:25](293,300)span: </span>',
332
+ '[17:25]>[18:5](300,305)#text: ⏎→→→→',
333
+ "[18:5]>[18:28](305,328)MustacheTag: {type␣===␣'textarea'␣?␣",
334
+ '[18:28]>[18:40](328,340)textarea: <textarea␣/>',
335
+ '[18:43]>[18:64](343,364)input: <input␣type={type}␣/>',
336
+ '[18:50]>[18:62](350,362)type: type={type}␣',
337
+ ' [18:50]>[18:50](350,350)bN: ',
338
+ ' [18:50]>[18:54](350,354)name: type',
339
+ ' [18:54]>[18:54](354,354)bE: ',
340
+ ' [18:54]>[18:55](354,355)equal: =',
341
+ ' [18:55]>[18:55](355,355)aE: ',
342
+ ' [18:55]>[18:56](355,356)sQ: {',
343
+ ' [18:56]>[18:60](356,360)value: type',
344
+ ' [18:60]>[18:61](360,361)eQ: }',
345
+ ' isDirective: false',
346
+ ' isDynamicValue: true',
347
+ '[18:43]>[18:65](343,365)MustacheTag: <input␣type={type}␣/>}',
348
+ '[18:65]>[19:4](365,369)#text: ⏎→→→',
349
+ '[19:4]>[19:12](369,377)label: </label>',
350
+ '[19:12]>[21:3](377,384)MustacheTag: ⏎→→)⏎→}',
351
+ '[21:3]>[22:1](384,385)#text: ⏎',
352
+ '[22:1]>[22:7](385,391)div: </div>',
353
+ '[22:7]>[23:1](391,392)#text: ⏎',
354
+ ]);
355
+ });
356
+
357
+ test('#803', () => {
358
+ const ast = parse(`<html lang="en">
359
+ <head>
360
+ <meta charset="utf-8" />
361
+ <title>Title</title>
362
+ <meta name="viewport" content="width=device-width" />
363
+ </head>
364
+ </html>`);
365
+ const map = nodeListToDebugMaps(ast.nodeList, true);
366
+ expect(map).toEqual([
367
+ '[1:1]>[1:17](0,16)html: <html␣lang="en">',
368
+ '[1:7]>[1:16](6,15)lang: lang="en"',
369
+ ' [1:7]>[1:7](6,6)bN: ',
370
+ ' [1:7]>[1:11](6,10)name: lang',
371
+ ' [1:11]>[1:11](10,10)bE: ',
372
+ ' [1:11]>[1:12](10,11)equal: =',
373
+ ' [1:12]>[1:12](11,11)aE: ',
374
+ ' [1:12]>[1:13](11,12)sQ: "',
375
+ ' [1:13]>[1:15](12,14)value: en',
376
+ ' [1:15]>[1:16](14,15)eQ: "',
377
+ ' isDirective: false',
378
+ ' isDynamicValue: false',
379
+ '[1:17]>[2:2](16,18)#text: ⏎→',
380
+ '[2:2]>[2:8](18,24)head: <head>',
381
+ '[2:8]>[3:3](24,27)#text: ⏎→→',
382
+ '[3:3]>[3:27](27,51)meta: <meta␣charset="utf-8"␣/>',
383
+ '[3:9]>[3:25](33,49)charset: charset="utf-8"␣',
384
+ ' [3:9]>[3:9](33,33)bN: ',
385
+ ' [3:9]>[3:16](33,40)name: charset',
386
+ ' [3:16]>[3:16](40,40)bE: ',
387
+ ' [3:16]>[3:17](40,41)equal: =',
388
+ ' [3:17]>[3:17](41,41)aE: ',
389
+ ' [3:17]>[3:18](41,42)sQ: "',
390
+ ' [3:18]>[3:23](42,47)value: utf-8',
391
+ ' [3:23]>[3:24](47,48)eQ: "',
392
+ ' isDirective: false',
393
+ ' isDynamicValue: false',
394
+ '[3:27]>[4:3](51,54)#text: ⏎→→',
395
+ '[4:3]>[4:10](54,61)title: <title>',
396
+ '[4:10]>[4:15](61,66)#text: Title',
397
+ '[4:15]>[4:23](66,74)title: </title>',
398
+ '[4:23]>[5:3](74,77)#text: ⏎→→',
399
+ '[5:3]>[5:56](77,130)meta: <meta␣name="viewport"␣content="width=device-width"␣/>',
400
+ '[5:9]>[5:24](83,98)name: name="viewport"',
401
+ ' [5:9]>[5:9](83,83)bN: ',
402
+ ' [5:9]>[5:13](83,87)name: name',
403
+ ' [5:13]>[5:13](87,87)bE: ',
404
+ ' [5:13]>[5:14](87,88)equal: =',
405
+ ' [5:14]>[5:14](88,88)aE: ',
406
+ ' [5:14]>[5:15](88,89)sQ: "',
407
+ ' [5:15]>[5:23](89,97)value: viewport',
408
+ ' [5:23]>[5:24](97,98)eQ: "',
409
+ ' isDirective: false',
410
+ ' isDynamicValue: false',
411
+ '[5:25]>[5:54](99,128)content: content="width=device-width"␣',
412
+ ' [5:25]>[5:25](99,99)bN: ',
413
+ ' [5:25]>[5:32](99,106)name: content',
414
+ ' [5:32]>[5:32](106,106)bE: ',
415
+ ' [5:32]>[5:33](106,107)equal: =',
416
+ ' [5:33]>[5:33](107,107)aE: ',
417
+ ' [5:33]>[5:34](107,108)sQ: "',
418
+ ' [5:34]>[5:52](108,126)value: width=device-width',
419
+ ' [5:52]>[5:53](126,127)eQ: "',
420
+ ' isDirective: false',
421
+ ' isDynamicValue: false',
422
+ '[5:56]>[6:2](130,132)#text: ⏎→',
423
+ '[6:2]>[6:9](132,139)head: </head>',
424
+ '[6:9]>[7:1](139,140)#text: ⏎',
425
+ ]);
426
+
427
+ const ast2 = parse(`<html>
428
+ <head>
429
+ <meta attr=">" />
430
+ <meta attr={a>b} />
431
+ <meta attr={<tag>text</tag>} />
432
+ </head>
433
+ </html>`);
434
+ const map2 = nodeListToDebugMaps(ast2.nodeList, true);
435
+ expect(map2).toEqual([
436
+ '[1:1]>[1:7](0,6)html: <html>',
437
+ '[1:7]>[2:2](6,8)#text: ⏎→',
438
+ '[2:2]>[2:8](8,14)head: <head>',
439
+ '[2:8]>[3:3](14,17)#text: ⏎→→',
440
+ '[3:3]>[3:20](17,34)meta: <meta␣attr=">"␣/>',
441
+ '[3:9]>[3:18](23,32)attr: attr=">"␣',
442
+ ' [3:9]>[3:9](23,23)bN: ',
443
+ ' [3:9]>[3:13](23,27)name: attr',
444
+ ' [3:13]>[3:13](27,27)bE: ',
445
+ ' [3:13]>[3:14](27,28)equal: =',
446
+ ' [3:14]>[3:14](28,28)aE: ',
447
+ ' [3:14]>[3:15](28,29)sQ: "',
448
+ ' [3:15]>[3:16](29,30)value: >',
449
+ ' [3:16]>[3:17](30,31)eQ: "',
450
+ ' isDirective: false',
451
+ ' isDynamicValue: false',
452
+ '[3:20]>[4:3](34,37)#text: ⏎→→',
453
+ '[4:3]>[4:22](37,56)meta: <meta␣attr={a>b}␣/>',
454
+ '[4:9]>[4:20](43,54)attr: attr={a>b}␣',
455
+ ' [4:9]>[4:9](43,43)bN: ',
456
+ ' [4:9]>[4:13](43,47)name: attr',
457
+ ' [4:13]>[4:13](47,47)bE: ',
458
+ ' [4:13]>[4:14](47,48)equal: =',
459
+ ' [4:14]>[4:14](48,48)aE: ',
460
+ ' [4:14]>[4:15](48,49)sQ: {',
461
+ ' [4:15]>[4:18](49,52)value: a>b',
462
+ ' [4:18]>[4:19](52,53)eQ: }',
463
+ ' isDirective: false',
464
+ ' isDynamicValue: true',
465
+ '[4:22]>[5:3](56,59)#text: ⏎→→',
466
+ '[5:3]>[5:34](59,90)meta: <meta␣attr={<tag>text</tag>}␣/>',
467
+ '[5:9]>[5:32](65,88)attr: attr={<tag>text</tag>}␣',
468
+ ' [5:9]>[5:9](65,65)bN: ',
469
+ ' [5:9]>[5:13](65,69)name: attr',
470
+ ' [5:13]>[5:13](69,69)bE: ',
471
+ ' [5:13]>[5:14](69,70)equal: =',
472
+ ' [5:14]>[5:14](70,70)aE: ',
473
+ ' [5:14]>[5:15](70,71)sQ: {',
474
+ ' [5:15]>[5:30](71,86)value: <tag>text</tag>',
475
+ ' [5:30]>[5:31](86,87)eQ: }',
476
+ ' isDirective: false',
477
+ ' isDynamicValue: true',
478
+ '[5:34]>[6:2](90,92)#text: ⏎→',
479
+ '[6:2]>[6:9](92,99)head: </head>',
480
+ '[6:9]>[7:1](99,100)#text: ⏎',
481
+ ]);
482
+ });
483
+ });