@markuplint/html-parser 3.6.1 → 3.8.0

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.
@@ -0,0 +1,1246 @@
1
+ const { attributesToDebugMaps, nodeListToDebugMaps } = require('@markuplint/parser-utils');
2
+
3
+ const { isDocumentFragment, parse } = require('../lib/');
4
+
5
+ describe('isDocumentFragment', () => {
6
+ it('<!doctype>', () => {
7
+ expect(isDocumentFragment('<!DOCTYPE html>')).toBe(false);
8
+ });
9
+
10
+ it('<!doctype> - 2', () => {
11
+ expect(
12
+ isDocumentFragment(`
13
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
14
+ `),
15
+ ).toBe(false);
16
+ });
17
+
18
+ it('<!doctype> + <html>', () => {
19
+ expect(
20
+ isDocumentFragment(`
21
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
22
+ <html>
23
+ `),
24
+ ).toBe(false);
25
+ });
26
+
27
+ it('<!doctype> + <html></html>', () => {
28
+ expect(
29
+ isDocumentFragment(`
30
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
31
+ <html></html>
32
+ `),
33
+ ).toBe(false);
34
+ });
35
+
36
+ it('<!doctype> + <html> - 2', () => {
37
+ expect(
38
+ isDocumentFragment(`
39
+ <html lang="ja">
40
+ `),
41
+ ).toBe(false);
42
+ });
43
+
44
+ it('<!doctype> + <html></html> - 2', () => {
45
+ expect(
46
+ isDocumentFragment(`
47
+ <html lang="ja"></html>
48
+ `),
49
+ ).toBe(false);
50
+ });
51
+
52
+ it('<html></html>', () => {
53
+ expect(isDocumentFragment('<html lang="ja"></html>')).toBe(false);
54
+ });
55
+
56
+ it('<html></html> - 2', () => {
57
+ expect(isDocumentFragment('<html></html>')).toBe(false);
58
+ });
59
+
60
+ it('<body>', () => {
61
+ expect(
62
+ isDocumentFragment(`
63
+ <body>
64
+ `),
65
+ ).toBe(true);
66
+ });
67
+
68
+ it('<body></body>', () => {
69
+ expect(isDocumentFragment('<body></body>')).toBe(true);
70
+ });
71
+
72
+ it('<div></div>', () => {
73
+ expect(isDocumentFragment('<div></div>')).toBe(true);
74
+ });
75
+
76
+ it('<template></template>', () => {
77
+ expect(isDocumentFragment('<template></template>')).toBe(true);
78
+ });
79
+
80
+ it('<head></head>', () => {
81
+ expect(isDocumentFragment('<head></head>')).toBe(true);
82
+ });
83
+ });
84
+
85
+ describe('parser', () => {
86
+ it('<!DOCTYPE html>', () => {
87
+ const doc = parse('<!DOCTYPE html>');
88
+ expect(doc.nodeList[0].type).toBe('doctype');
89
+ expect(doc.nodeList[1].nodeName).toBe('html');
90
+ expect(doc.nodeList[2].nodeName).toBe('head');
91
+ expect(doc.nodeList[3].nodeName).toBe('body');
92
+ expect(doc.nodeList.length).toBe(4);
93
+ });
94
+
95
+ it('<!DOCTYPE html> ', () => {
96
+ const doc = parse('<!DOCTYPE html> ');
97
+ expect(doc.nodeList[0].type).toBe('doctype');
98
+ expect(doc.nodeList[1].nodeName).toBe('html');
99
+ expect(doc.nodeList[2].nodeName).toBe('head');
100
+ expect(doc.nodeList[3].nodeName).toBe('body');
101
+ expect(doc.nodeList[4].nodeName).toBe('#text');
102
+ expect(doc.nodeList[4].raw).toBe(' ');
103
+ expect(doc.nodeList.length).toBe(5);
104
+ });
105
+
106
+ it('<!DOCTYPE html>\\n', () => {
107
+ const doc = parse('<!DOCTYPE html>\n');
108
+ expect(doc.nodeList[0].type).toBe('doctype');
109
+ expect(doc.nodeList[1].nodeName).toBe('html');
110
+ expect(doc.nodeList[2].nodeName).toBe('head');
111
+ expect(doc.nodeList[3].nodeName).toBe('body');
112
+ expect(doc.nodeList[4].nodeName).toBe('#text');
113
+ expect(doc.nodeList[4].raw).toBe('\n');
114
+ expect(doc.nodeList.length).toBe(5);
115
+ });
116
+
117
+ it('<!DOCTYPE html>text', () => {
118
+ const doc = parse('<!DOCTYPE html>text');
119
+ expect(doc.nodeList[0].type).toBe('doctype');
120
+ expect(doc.nodeList[1].nodeName).toBe('html');
121
+ expect(doc.nodeList[2].nodeName).toBe('head');
122
+ expect(doc.nodeList[3].nodeName).toBe('body');
123
+ expect(doc.nodeList[4].type).toBe('text');
124
+ expect(doc.nodeList[4].startCol).toBe(16);
125
+ expect(doc.nodeList.length).toBe(5);
126
+ });
127
+
128
+ it('<!DOCTYPE html> text', () => {
129
+ const doc = parse('<!DOCTYPE html> text');
130
+ expect(doc.nodeList[0].type).toBe('doctype');
131
+ expect(doc.nodeList[1].nodeName).toBe('html');
132
+ expect(doc.nodeList[2].nodeName).toBe('head');
133
+ expect(doc.nodeList[3].nodeName).toBe('body');
134
+ expect(doc.nodeList[4].type).toBe('text');
135
+ expect(doc.nodeList[4].raw).toBe(' text');
136
+ expect(doc.nodeList[4].startCol).toBe(16);
137
+ expect(doc.nodeList.length).toBe(5);
138
+ });
139
+
140
+ it('<!DOCTYPE html>\\ntext', () => {
141
+ const doc = parse('<!DOCTYPE html>\ntext');
142
+ expect(doc.nodeList[0].type).toBe('doctype');
143
+ expect(doc.nodeList[1].nodeName).toBe('html');
144
+ expect(doc.nodeList[2].nodeName).toBe('head');
145
+ expect(doc.nodeList[3].nodeName).toBe('body');
146
+ expect(doc.nodeList[4].type).toBe('text');
147
+ expect(doc.nodeList[4].raw).toBe('\ntext');
148
+ expect(doc.nodeList[4].startCol).toBe(16);
149
+ expect(doc.nodeList.length).toBe(5);
150
+ });
151
+
152
+ it('<!DOCTYPE html>\\n<p>text', () => {
153
+ const doc = parse('<!DOCTYPE html>\n<p>text');
154
+ expect(doc.nodeList[0].type).toBe('doctype');
155
+ expect(doc.nodeList[1].nodeName).toBe('html');
156
+ expect(doc.nodeList[2].nodeName).toBe('head');
157
+ expect(doc.nodeList[3].nodeName).toBe('body');
158
+ expect(doc.nodeList[4].nodeName).toBe('#text');
159
+ expect(doc.nodeList[5].nodeName).toBe('p');
160
+ expect(doc.nodeList[6].type).toBe('text');
161
+ expect(doc.nodeList[6].raw).toBe('text');
162
+ expect(doc.nodeList[6].startCol).toBe(4);
163
+ expect(doc.nodeList.length).toBe(7);
164
+ });
165
+
166
+ it('<!DOCTYPE html><p>\\ntext', () => {
167
+ const doc = parse('<!DOCTYPE html><p>\ntext');
168
+ expect(doc.nodeList[0].type).toBe('doctype');
169
+ expect(doc.nodeList[1].nodeName).toBe('html');
170
+ expect(doc.nodeList[2].nodeName).toBe('head');
171
+ expect(doc.nodeList[3].nodeName).toBe('body');
172
+ expect(doc.nodeList[4].nodeName).toBe('p');
173
+ expect(doc.nodeList[5].type).toBe('text');
174
+ expect(doc.nodeList[5].raw).toBe('\ntext');
175
+ expect(doc.nodeList[5].startCol).toBe(19);
176
+ expect(doc.nodeList.length).toBe(6);
177
+ });
178
+
179
+ it('<!DOCTYPE html>\\n<html>text', () => {
180
+ const doc = parse('<!DOCTYPE html>\n<html>text');
181
+ expect(doc.nodeList[0].type).toBe('doctype');
182
+ expect(doc.nodeList[1].nodeName).toBe('#text');
183
+ expect(doc.nodeList[2].nodeName).toBe('html');
184
+ expect(doc.nodeList[3].nodeName).toBe('head');
185
+ expect(doc.nodeList[4].nodeName).toBe('body');
186
+ expect(doc.nodeList[5].type).toBe('text');
187
+ expect(doc.nodeList[5].raw).toBe('text');
188
+ expect(doc.nodeList[5].startCol).toBe(7);
189
+ expect(doc.nodeList.length).toBe(6);
190
+ });
191
+
192
+ it('<!DOCTYPE html><html>\\ntext', () => {
193
+ const doc = parse('<!DOCTYPE html><html>\ntext');
194
+ expect(doc.nodeList[0].type).toBe('doctype');
195
+ expect(doc.nodeList[1].nodeName).toBe('html');
196
+ expect(doc.nodeList[2].nodeName).toBe('head');
197
+ expect(doc.nodeList[3].nodeName).toBe('body');
198
+ expect(doc.nodeList[4].type).toBe('text');
199
+ expect(doc.nodeList[4].raw).toBe('\ntext');
200
+ expect(doc.nodeList[4].startCol).toBe(22);
201
+ expect(doc.nodeList.length).toBe(5);
202
+ });
203
+
204
+ it('empty code', () => {
205
+ const doc = parse('');
206
+ expect(doc.nodeList).toStrictEqual([]);
207
+ expect(doc.nodeList.length).toBe(0);
208
+ });
209
+
210
+ it('<html>', () => {
211
+ const doc = parse('<html>');
212
+ expect(doc.nodeList[0].nodeName).toBe('html');
213
+ expect(doc.nodeList[1].nodeName).toBe('head');
214
+ expect(doc.nodeList[2].nodeName).toBe('body');
215
+ expect(doc.nodeList.length).toBe(3);
216
+ });
217
+
218
+ it('<html></body>', () => {
219
+ const doc = parse('<html></body>');
220
+ expect(doc.nodeList[0].nodeName).toBe('html');
221
+ expect(doc.nodeList[1].nodeName).toBe('head');
222
+ expect(doc.nodeList[2].nodeName).toBe('body');
223
+ expect(doc.nodeList[3].nodeName).toBe('#text');
224
+ expect(doc.nodeList[3].raw).toBe('</body>');
225
+ expect(doc.nodeList.length).toBe(4);
226
+ });
227
+
228
+ it('text only', () => {
229
+ const doc = parse('text');
230
+ expect(doc.nodeList[0].nodeName).toBe('#text');
231
+ expect(doc.nodeList[0].raw).toBe('text');
232
+ expect(doc.nodeList.length).toBe(1);
233
+ });
234
+
235
+ it('<html>invalid-before-text<body>text</body>invalid-after-text</html>', () => {
236
+ const doc = parse('<html>invalid-before-text<body>text</body>invalid-after-text</html>');
237
+ expect(doc.nodeList[0].nodeName).toBe('html');
238
+ expect(doc.nodeList[1].nodeName).toBe('head');
239
+ expect(doc.nodeList[2].nodeName).toBe('body');
240
+ expect(doc.nodeList[3].nodeName).toBe('#text');
241
+ expect(doc.nodeList[4].nodeName).toBe('html');
242
+ expect(doc.nodeList.length).toBe(5);
243
+ });
244
+
245
+ test('a element', () => {
246
+ const r = parse('<div>text</div>');
247
+ const map = nodeListToDebugMaps(r.nodeList);
248
+ expect(map).toStrictEqual([
249
+ '[1:1]>[1:6](0,5)div: <div>',
250
+ '[1:6]>[1:10](5,9)#text: text',
251
+ '[1:10]>[1:16](9,15)div: </div>',
252
+ ]);
253
+ });
254
+
255
+ it('<head><title>TITLE</title></head>', () => {
256
+ const doc = parse('<head><title>TITLE</title></head>');
257
+ expect(nodeListToDebugMaps(doc.nodeList)).toStrictEqual([
258
+ '[1:1]>[1:7](0,6)head: <head>',
259
+ '[1:7]>[1:14](6,13)title: <title>',
260
+ '[1:14]>[1:19](13,18)#text: TITLE',
261
+ '[1:19]>[1:27](18,26)title: </title>',
262
+ '[1:27]>[1:34](26,33)head: </head>',
263
+ ]);
264
+ });
265
+
266
+ it('<body><p>TEXT</p></body>', () => {
267
+ const doc = parse('<body><p>TEXT</p></body>');
268
+ expect(nodeListToDebugMaps(doc.nodeList)).toStrictEqual([
269
+ '[1:1]>[1:7](0,6)body: <body>',
270
+ '[1:7]>[1:10](6,9)p: <p>',
271
+ '[1:10]>[1:14](9,13)#text: TEXT',
272
+ '[1:14]>[1:18](13,17)p: </p>',
273
+ '[1:18]>[1:25](17,24)body: </body>',
274
+ ]);
275
+ });
276
+
277
+ it('<head><title>TITLE</title></head><body><p>TEXT</p></body>', () => {
278
+ const doc = parse('<head><title>TITLE</title></head><body><p>TEXT</p></body>');
279
+ expect(nodeListToDebugMaps(doc.nodeList)).toStrictEqual([
280
+ '[1:1]>[1:7](0,6)head: <head>',
281
+ '[1:7]>[1:14](6,13)title: <title>',
282
+ '[1:14]>[1:19](13,18)#text: TITLE',
283
+ '[1:19]>[1:27](18,26)title: </title>',
284
+ '[1:27]>[1:34](26,33)head: </head>',
285
+ '[1:34]>[1:40](33,39)body: <body>',
286
+ '[1:40]>[1:43](39,42)p: <p>',
287
+ '[1:43]>[1:47](42,46)#text: TEXT',
288
+ '[1:47]>[1:51](46,50)p: </p>',
289
+ '[1:51]>[1:58](50,57)body: </body>',
290
+ ]);
291
+ });
292
+
293
+ it('<head><title>TITLE</title>', () => {
294
+ const doc = parse('<head><title>TITLE</title>');
295
+ expect(nodeListToDebugMaps(doc.nodeList)).toStrictEqual([
296
+ '[1:1]>[1:7](0,6)head: <head>',
297
+ '[1:7]>[1:14](6,13)title: <title>',
298
+ '[1:14]>[1:19](13,18)#text: TITLE',
299
+ '[1:19]>[1:27](18,26)title: </title>',
300
+ ]);
301
+ });
302
+
303
+ it('<body><p>TEXT</p>', () => {
304
+ const doc = parse('<body><p>TEXT</p>');
305
+ expect(nodeListToDebugMaps(doc.nodeList)).toStrictEqual([
306
+ '[1:1]>[1:7](0,6)body: <body>',
307
+ '[1:7]>[1:10](6,9)p: <p>',
308
+ '[1:10]>[1:14](9,13)#text: TEXT',
309
+ '[1:14]>[1:18](13,17)p: </p>',
310
+ ]);
311
+ });
312
+
313
+ it('<head><title>TITLE</title><body><p>TEXT</p>', () => {
314
+ const doc = parse('<head><title>TITLE</title><body><p>TEXT</p>');
315
+ expect(nodeListToDebugMaps(doc.nodeList)).toStrictEqual([
316
+ '[1:1]>[1:7](0,6)head: <head>',
317
+ '[1:7]>[1:14](6,13)title: <title>',
318
+ '[1:14]>[1:19](13,18)#text: TITLE',
319
+ '[1:19]>[1:27](18,26)title: </title>',
320
+ '[1:27]>[1:33](26,32)body: <body>',
321
+ '[1:33]>[1:36](32,35)p: <p>',
322
+ '[1:36]>[1:40](35,39)#text: TEXT',
323
+ '[1:40]>[1:44](39,43)p: </p>',
324
+ ]);
325
+ });
326
+
327
+ it('standard code', () => {
328
+ const doc = parse(`
329
+ <!DOCTYPE html>
330
+ <html lang="en">
331
+ <head>
332
+ <meta charset="UTF-8">
333
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
334
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
335
+ <title>Document</title>
336
+ </head>
337
+ <body>
338
+ <script>
339
+ const i = 0;
340
+ </script>
341
+ <!comment-node>
342
+ <!-- html-comment -->
343
+ <div>
344
+ text&amp;div
345
+ </div>
346
+ <table>
347
+ <tr>
348
+ <th>header</th>
349
+ <td>cell</td>
350
+ </tr>
351
+ </table>
352
+ <table>
353
+ <tbody>
354
+ <tr>
355
+ <th>header</th>
356
+ <td>cell</td>
357
+ </tr>
358
+ </tbody>
359
+ </table>
360
+ <img src="path/to" />
361
+ invalid-indent
362
+
363
+ <?template engine;
364
+ $var = '<html attr="value">text</html>'
365
+ ?>
366
+
367
+ <%template engine;
368
+ $var = '<html attr="value">text</html>'
369
+ %>
370
+
371
+ </expected>
372
+ <div>
373
+ text-node
374
+ </body>
375
+ </html>
376
+ `);
377
+ const map = nodeListToDebugMaps(doc.nodeList);
378
+ expect(map).toStrictEqual([
379
+ '[1:1]>[2:2](0,2)#text: ⏎→',
380
+ '[2:2]>[2:17](2,17)#doctype: <!DOCTYPE␣html>',
381
+ '[2:17]>[3:2](17,19)#text: ⏎→',
382
+ '[3:2]>[3:18](19,35)html: <html␣lang="en">',
383
+ '[3:18]>[4:2](35,37)#text: ⏎→',
384
+ '[4:2]>[4:8](37,43)head: <head>',
385
+ '[4:8]>[5:3](43,46)#text: ⏎→→',
386
+ '[5:3]>[5:25](46,68)meta: <meta␣charset="UTF-8">',
387
+ '[5:25]>[6:3](68,71)#text: ⏎→→',
388
+ '[6:3]>[6:73](71,141)meta: <meta␣name="viewport"␣content="width=device-width,␣initial-scale=1.0">',
389
+ '[6:73]>[7:3](141,144)#text: ⏎→→',
390
+ '[7:3]>[7:56](144,197)meta: <meta␣http-equiv="X-UA-Compatible"␣content="ie=edge">',
391
+ '[7:56]>[8:3](197,200)#text: ⏎→→',
392
+ '[8:3]>[8:10](200,207)title: <title>',
393
+ '[8:10]>[8:18](207,215)#text: Document',
394
+ '[8:18]>[8:26](215,223)title: </title>',
395
+ '[8:26]>[9:2](223,225)#text: ⏎→',
396
+ '[9:2]>[9:9](225,232)head: </head>',
397
+ '[9:9]>[10:2](232,234)#text: ⏎→',
398
+ '[10:2]>[10:8](234,240)body: <body>',
399
+ '[10:8]>[11:3](240,243)#text: ⏎→→',
400
+ '[11:3]>[11:11](243,251)script: <script>',
401
+ '[11:11]>[13:3](251,270)#text: ⏎→→→const␣i␣=␣0;⏎→→',
402
+ '[13:3]>[13:12](270,279)script: </script>',
403
+ '[13:12]>[14:3](279,282)#text: ⏎→→',
404
+ '[14:3]>[14:18](282,297)#comment: <!comment-node>',
405
+ '[14:18]>[15:3](297,300)#text: ⏎→→',
406
+ '[15:3]>[15:24](300,321)#comment: <!--␣html-comment␣-->',
407
+ '[15:24]>[16:3](321,324)#text: ⏎→→',
408
+ '[16:3]>[16:8](324,329)div: <div>',
409
+ '[16:8]>[18:3](329,348)#text: ⏎→→→text&amp;div⏎→→',
410
+ '[18:3]>[18:9](348,354)div: </div>',
411
+ '[18:9]>[19:3](354,357)#text: ⏎→→',
412
+ '[19:3]>[19:10](357,364)table: <table>',
413
+ '[19:10]>[20:4](364,368)#text: ⏎→→→',
414
+ '[N/A]>[N/A](N/A)tbody: ',
415
+ '[20:4]>[20:8](368,372)tr: <tr>',
416
+ '[20:8]>[21:5](372,377)#text: ⏎→→→→',
417
+ '[21:5]>[21:9](377,381)th: <th>',
418
+ '[21:9]>[21:15](381,387)#text: header',
419
+ '[21:15]>[21:20](387,392)th: </th>',
420
+ '[21:20]>[22:5](392,397)#text: ⏎→→→→',
421
+ '[22:5]>[22:9](397,401)td: <td>',
422
+ '[22:9]>[22:13](401,405)#text: cell',
423
+ '[22:13]>[22:18](405,410)td: </td>',
424
+ '[22:18]>[23:4](410,414)#text: ⏎→→→',
425
+ '[23:4]>[23:9](414,419)tr: </tr>',
426
+ '[23:9]>[24:3](419,422)#text: ⏎→→',
427
+ '[24:3]>[24:11](422,430)table: </table>',
428
+ '[24:11]>[25:3](430,433)#text: ⏎→→',
429
+ '[25:3]>[25:10](433,440)table: <table>',
430
+ '[25:10]>[26:4](440,444)#text: ⏎→→→',
431
+ '[26:4]>[26:11](444,451)tbody: <tbody>',
432
+ '[26:11]>[27:5](451,456)#text: ⏎→→→→',
433
+ '[27:5]>[27:9](456,460)tr: <tr>',
434
+ '[27:9]>[28:6](460,466)#text: ⏎→→→→→',
435
+ '[28:6]>[28:10](466,470)th: <th>',
436
+ '[28:10]>[28:16](470,476)#text: header',
437
+ '[28:16]>[28:21](476,481)th: </th>',
438
+ '[28:21]>[29:6](481,487)#text: ⏎→→→→→',
439
+ '[29:6]>[29:10](487,491)td: <td>',
440
+ '[29:10]>[29:14](491,495)#text: cell',
441
+ '[29:14]>[29:19](495,500)td: </td>',
442
+ '[29:19]>[30:5](500,505)#text: ⏎→→→→',
443
+ '[30:5]>[30:10](505,510)tr: </tr>',
444
+ '[30:10]>[31:4](510,514)#text: ⏎→→→',
445
+ '[31:4]>[31:12](514,522)tbody: </tbody>',
446
+ '[31:12]>[32:3](522,525)#text: ⏎→→',
447
+ '[32:3]>[32:11](525,533)table: </table>',
448
+ '[32:11]>[33:3](533,536)#text: ⏎→→',
449
+ '[33:3]>[33:24](536,557)img: <img␣src="path/to"␣/>',
450
+ '[33:24]>[36:3](557,580)#text: ⏎→→→→invalid-indent⏎⏎→→',
451
+ '[36:3]>[37:31](580,629)#comment: <?template␣engine;⏎→→→$var␣=␣\'<html␣attr="value">',
452
+ "[37:31]>[45:3](629,734)#text: text</html>'⏎→→?>⏎⏎→→<%template␣engine;⏎→→→$var␣=␣'<html␣attr=\"value\">text</html>'⏎→→%>⏎⏎→→</expected>⏎→→",
453
+ '[45:3]>[45:8](734,739)div: <div>',
454
+ '[45:8]>[47:2](739,752)#text: ⏎→text-node⏎→',
455
+ '[47:2]>[47:9](752,759)body: </body>',
456
+ '[47:9]>[48:2](759,761)#text: ⏎→',
457
+ '[48:2]>[48:9](761,768)html: </html>',
458
+ '[48:9]>[49:2](768,770)#text: ⏎→',
459
+ ]);
460
+ });
461
+
462
+ it('<template>', () => {
463
+ const doc = parse(`
464
+ <template>
465
+ <script>
466
+ const i = 0;
467
+ </script>
468
+ <!comment-node>
469
+ <!-- html-comment -->
470
+ <div>
471
+ text&amp;div
472
+ </div>
473
+ <table>
474
+ <tr>
475
+ <th>header</th>
476
+ <td>cell</td>
477
+ </tr>
478
+ </table>
479
+ <table>
480
+ <tbody>
481
+ <tr>
482
+ <th>header</th>
483
+ <td>cell</td>
484
+ </tr>
485
+ </tbody>
486
+ </table>
487
+ <img src="path/to" />
488
+ invalid-indent
489
+
490
+ <?template engine;
491
+ $var = '<html attr="value">text</html>'
492
+ ?>
493
+
494
+ <%template engine;
495
+ $var = '<html attr="value">text</html>'
496
+ %>
497
+
498
+ </expected>
499
+ <div>
500
+ text-node
501
+ </template>
502
+ `);
503
+ const map = nodeListToDebugMaps(doc.nodeList);
504
+ expect(map).toStrictEqual([
505
+ '[1:1]>[2:2](0,2)#text: ⏎→',
506
+ '[2:2]>[2:12](2,12)template: <template>',
507
+ '[2:12]>[3:3](12,15)#text: ⏎→→',
508
+ '[3:3]>[3:11](15,23)script: <script>',
509
+ '[3:11]>[5:3](23,42)#text: ⏎→→→const␣i␣=␣0;⏎→→',
510
+ '[5:3]>[5:12](42,51)script: </script>',
511
+ '[5:12]>[6:3](51,54)#text: ⏎→→',
512
+ '[6:3]>[6:18](54,69)#comment: <!comment-node>',
513
+ '[6:18]>[7:3](69,72)#text: ⏎→→',
514
+ '[7:3]>[7:24](72,93)#comment: <!--␣html-comment␣-->',
515
+ '[7:24]>[8:3](93,96)#text: ⏎→→',
516
+ '[8:3]>[8:8](96,101)div: <div>',
517
+ '[8:8]>[10:3](101,120)#text: ⏎→→→text&amp;div⏎→→',
518
+ '[10:3]>[10:9](120,126)div: </div>',
519
+ '[10:9]>[11:3](126,129)#text: ⏎→→',
520
+ '[11:3]>[11:10](129,136)table: <table>',
521
+ '[11:10]>[12:4](136,140)#text: ⏎→→→',
522
+ '[N/A]>[N/A](N/A)tbody: ',
523
+ '[12:4]>[12:8](140,144)tr: <tr>',
524
+ '[12:8]>[13:5](144,149)#text: ⏎→→→→',
525
+ '[13:5]>[13:9](149,153)th: <th>',
526
+ '[13:9]>[13:15](153,159)#text: header',
527
+ '[13:15]>[13:20](159,164)th: </th>',
528
+ '[13:20]>[14:5](164,169)#text: ⏎→→→→',
529
+ '[14:5]>[14:9](169,173)td: <td>',
530
+ '[14:9]>[14:13](173,177)#text: cell',
531
+ '[14:13]>[14:18](177,182)td: </td>',
532
+ '[14:18]>[15:4](182,186)#text: ⏎→→→',
533
+ '[15:4]>[15:9](186,191)tr: </tr>',
534
+ '[15:9]>[16:3](191,194)#text: ⏎→→',
535
+ '[16:3]>[16:11](194,202)table: </table>',
536
+ '[16:11]>[17:3](202,205)#text: ⏎→→',
537
+ '[17:3]>[17:10](205,212)table: <table>',
538
+ '[17:10]>[18:4](212,216)#text: ⏎→→→',
539
+ '[18:4]>[18:11](216,223)tbody: <tbody>',
540
+ '[18:11]>[19:5](223,228)#text: ⏎→→→→',
541
+ '[19:5]>[19:9](228,232)tr: <tr>',
542
+ '[19:9]>[20:6](232,238)#text: ⏎→→→→→',
543
+ '[20:6]>[20:10](238,242)th: <th>',
544
+ '[20:10]>[20:16](242,248)#text: header',
545
+ '[20:16]>[20:21](248,253)th: </th>',
546
+ '[20:21]>[21:6](253,259)#text: ⏎→→→→→',
547
+ '[21:6]>[21:10](259,263)td: <td>',
548
+ '[21:10]>[21:14](263,267)#text: cell',
549
+ '[21:14]>[21:19](267,272)td: </td>',
550
+ '[21:19]>[22:5](272,277)#text: ⏎→→→→',
551
+ '[22:5]>[22:10](277,282)tr: </tr>',
552
+ '[22:10]>[23:4](282,286)#text: ⏎→→→',
553
+ '[23:4]>[23:12](286,294)tbody: </tbody>',
554
+ '[23:12]>[24:3](294,297)#text: ⏎→→',
555
+ '[24:3]>[24:11](297,305)table: </table>',
556
+ '[24:11]>[25:3](305,308)#text: ⏎→→',
557
+ '[25:3]>[25:24](308,329)img: <img␣src="path/to"␣/>',
558
+ '[25:24]>[28:3](329,352)#text: ⏎→→→→invalid-indent⏎⏎→→',
559
+ '[28:3]>[29:31](352,401)#comment: <?template␣engine;⏎→→→$var␣=␣\'<html␣attr="value">',
560
+ "[29:31]>[37:3](401,506)#text: text</html>'⏎→→?>⏎⏎→→<%template␣engine;⏎→→→$var␣=␣'<html␣attr=\"value\">text</html>'⏎→→%>⏎⏎→→</expected>⏎→→",
561
+ '[37:3]>[37:8](506,511)div: <div>',
562
+ '[37:8]>[39:2](511,524)#text: ⏎→text-node⏎→',
563
+ '[39:2]>[39:13](524,535)template: </template>',
564
+ '[39:13]>[40:2](535,537)#text: ⏎→',
565
+ ]);
566
+ });
567
+
568
+ it('<noscript>', () => {
569
+ const doc = parse(`
570
+ <noscript>
571
+ <div>test</div>
572
+ <expected>
573
+ </expected2>
574
+ </noscript>
575
+ `);
576
+ const map = nodeListToDebugMaps(doc.nodeList);
577
+ expect(map).toStrictEqual([
578
+ '[1:1]>[2:2](0,2)#text: ⏎→',
579
+ '[2:2]>[2:12](2,12)noscript: <noscript>',
580
+ '[2:12]>[3:3](12,15)#text: ⏎→→',
581
+ '[3:3]>[3:8](15,20)div: <div>',
582
+ '[3:8]>[3:12](20,24)#text: test',
583
+ '[3:12]>[3:18](24,30)div: </div>',
584
+ '[3:18]>[4:3](30,33)#text: ⏎→→',
585
+ '[4:3]>[4:13](33,43)expected: <expected>',
586
+ '[4:13]>[6:2](43,60)#text: ⏎→→</expected2>⏎→',
587
+ '[6:2]>[6:13](60,71)noscript: </noscript>',
588
+ '[6:13]>[7:2](71,73)#text: ⏎→',
589
+ ]);
590
+ });
591
+
592
+ /**
593
+ * https://github.com/markuplint/markuplint/issues/219
594
+ */
595
+ it('<noscript> (Issue: #219)', () => {
596
+ const doc = parse('<html><body><body><noscript data-xxx><iframe ></iframe></noscript></body></html>');
597
+ const map = nodeListToDebugMaps(doc.nodeList);
598
+ expect(map).toStrictEqual([
599
+ '[1:1]>[1:7](0,6)html: <html>',
600
+ '[N/A]>[N/A](N/A)head: ',
601
+ '[1:7]>[1:13](6,12)body: <body>',
602
+ '[1:19]>[1:38](18,37)noscript: <noscript␣data-xxx>',
603
+ '[1:38]>[1:47](37,46)iframe: <iframe␣>',
604
+ '[1:47]>[1:56](46,55)iframe: </iframe>',
605
+ '[1:56]>[1:67](55,66)noscript: </noscript>',
606
+ '[1:67]>[1:74](66,73)body: </body>',
607
+ '[1:74]>[1:81](73,80)html: </html>',
608
+ ]);
609
+ });
610
+
611
+ /**
612
+ * https://github.com/markuplint/markuplint/issues/737
613
+ */
614
+ it('<noscript> (Issue: #737)', () => {
615
+ const doc = parse('<html><body><noscript>\r\n<div>text</div>\r\n</noscript></body></html>');
616
+ const map = nodeListToDebugMaps(doc.nodeList);
617
+ expect(map).toStrictEqual([
618
+ '[1:1]>[1:7](0,6)html: <html>',
619
+ '[N/A]>[N/A](N/A)head: ',
620
+ '[1:7]>[1:13](6,12)body: <body>',
621
+ '[1:13]>[1:23](12,22)noscript: <noscript>',
622
+ '[1:23]>[2:1](22,24)#text: ␣⏎',
623
+ '[2:1]>[2:6](24,29)div: <div>',
624
+ '[2:6]>[2:10](29,33)#text: text',
625
+ '[2:10]>[2:16](33,39)div: </div>',
626
+ '[2:16]>[3:1](39,41)#text: ␣⏎',
627
+ '[3:1]>[3:12](41,52)noscript: </noscript>',
628
+ '[3:12]>[3:19](52,59)body: </body>',
629
+ '[3:19]>[3:26](59,66)html: </html>',
630
+ ]);
631
+ });
632
+
633
+ it('<form>', () => {
634
+ const doc = parse(`
635
+ <div>
636
+ <form novalidate>
637
+ <input type="text" name="foo">
638
+ <input type="checkbox" name="bar">
639
+ </form>
640
+ </div>
641
+ `);
642
+ const map = nodeListToDebugMaps(doc.nodeList);
643
+ expect(map).toStrictEqual([
644
+ '[1:1]>[2:2](0,2)#text: ⏎→',
645
+ '[2:2]>[2:7](2,7)div: <div>',
646
+ '[2:7]>[3:3](7,10)#text: ⏎→→',
647
+ '[3:3]>[3:20](10,27)form: <form␣novalidate>',
648
+ '[3:20]>[4:4](27,31)#text: ⏎→→→',
649
+ '[4:4]>[4:34](31,61)input: <input␣type="text"␣name="foo">',
650
+ '[4:34]>[5:4](61,65)#text: ⏎→→→',
651
+ '[5:4]>[5:38](65,99)input: <input␣type="checkbox"␣name="bar">',
652
+ '[5:38]>[6:3](99,102)#text: ⏎→→',
653
+ '[6:3]>[6:10](102,109)form: </form>',
654
+ '[6:10]>[7:2](109,111)#text: ⏎→',
655
+ '[7:2]>[7:8](111,117)div: </div>',
656
+ '[7:8]>[8:2](117,119)#text: ⏎→',
657
+ ]);
658
+ });
659
+
660
+ it('<form> in <form>', () => {
661
+ const doc = parse(`
662
+ <form>
663
+ <form novalidate>
664
+ <input type="text" name="foo">
665
+ <input type="checkbox" name="bar">
666
+ </form>
667
+ </form>
668
+ `);
669
+ const map = nodeListToDebugMaps(doc.nodeList);
670
+ expect(map).toStrictEqual([
671
+ '[1:1]>[2:2](0,2)#text: ⏎→',
672
+ '[2:2]>[2:8](2,8)form: <form>',
673
+ '[2:8]>[4:4](8,32)#text: ⏎→→<form␣novalidate>⏎→→→',
674
+ '[4:4]>[4:34](32,62)input: <input␣type="text"␣name="foo">',
675
+ '[4:34]>[5:4](62,66)#text: ⏎→→→',
676
+ '[5:4]>[5:38](66,100)input: <input␣type="checkbox"␣name="bar">',
677
+ '[5:38]>[6:3](100,103)#text: ⏎→→',
678
+ '[6:3]>[6:10](103,110)form: </form>',
679
+ '[6:10]>[8:2](110,121)#text: ⏎→</form>⏎→',
680
+ ]);
681
+ });
682
+
683
+ it('UUID', () => {
684
+ const doc = parse('<html><head><title>title</title></head><body><div>test</div></body></html>');
685
+ // const map = nodeListToDebugMaps(doc.nodeList);
686
+ // console.log(map);
687
+ // console.log(doc.nodeList.map((n, i) => `${i}: ${n.uuid} ${n.raw.trim()}`));
688
+
689
+ // <html>
690
+ expect(doc.nodeList[0].parentNode).toEqual(null);
691
+ expect(doc.nodeList[0].prevNode).toEqual(null);
692
+ expect(doc.nodeList[0].nextNode).toEqual(null);
693
+ // @ts-ignore
694
+ expect(doc.nodeList[0].pearNode.uuid).toEqual(doc.nodeList[11].uuid);
695
+
696
+ // </html>
697
+ expect(doc.nodeList[11].parentNode).toEqual(null);
698
+ // @ts-ignore
699
+ expect(doc.nodeList[11].pearNode.uuid).toEqual(doc.nodeList[0].uuid);
700
+
701
+ // <head>
702
+ // @ts-ignore
703
+ expect(doc.nodeList[1].parentNode.uuid).toEqual(doc.nodeList[0].uuid);
704
+ // @ts-ignore
705
+ expect(doc.nodeList[1].prevNode).toEqual(null);
706
+ // @ts-ignore
707
+ expect(doc.nodeList[1].nextNode.uuid).toEqual(doc.nodeList[6].uuid);
708
+ // @ts-ignore
709
+ expect(doc.nodeList[1].pearNode.uuid).toEqual(doc.nodeList[5].uuid);
710
+
711
+ // </head>
712
+ // @ts-ignore
713
+ expect(doc.nodeList[5].parentNode.uuid).toEqual(doc.nodeList[0].uuid);
714
+ // @ts-ignore
715
+ expect(doc.nodeList[5].pearNode.uuid).toEqual(doc.nodeList[1].uuid);
716
+
717
+ // <body>
718
+ // @ts-ignore
719
+ expect(doc.nodeList[6].parentNode.uuid).toEqual(doc.nodeList[0].uuid);
720
+ // @ts-ignore
721
+ expect(doc.nodeList[6].prevNode.uuid).toEqual(doc.nodeList[1].uuid);
722
+ // @ts-ignore
723
+ expect(doc.nodeList[6].nextNode).toEqual(null);
724
+ // @ts-ignore
725
+ expect(doc.nodeList[6].pearNode.uuid).toEqual(doc.nodeList[10].uuid);
726
+
727
+ // </body>
728
+ // @ts-ignore
729
+ expect(doc.nodeList[10].parentNode.uuid).toEqual(doc.nodeList[0].uuid);
730
+ // @ts-ignore
731
+ expect(doc.nodeList[10].pearNode.uuid).toEqual(doc.nodeList[6].uuid);
732
+ });
733
+
734
+ it('UUID', () => {
735
+ const doc = parse(`
736
+ <!DOCTYPE html>
737
+ <html lang="en">
738
+ <head>
739
+ <meta charset="UTF-8">
740
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
741
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
742
+ <title>Document</title>
743
+ </head>
744
+ <body>
745
+ <h1>Title</h1>
746
+ </body>
747
+ </html>
748
+ `);
749
+ // const map = nodeListToDebugMaps(doc.nodeList);
750
+ // console.log(map);
751
+ // console.log(doc.nodeList.map((n, i) => `${i}: ${n.uuid} ${n.raw.trim()}`));
752
+
753
+ // #text ⏎
754
+ expect(doc.nodeList[0].parentNode).toEqual(null);
755
+ expect(doc.nodeList[0].prevNode).toEqual(null);
756
+ // @ts-ignore
757
+ expect(doc.nodeList[0].nextNode.uuid).toEqual(doc.nodeList[1].uuid);
758
+
759
+ // Doctype <!DOCTYPE␣html>
760
+ expect(doc.nodeList[1].parentNode).toEqual(null);
761
+ // @ts-ignore
762
+ expect(doc.nodeList[1].prevNode.uuid).toEqual(doc.nodeList[0].uuid);
763
+ // @ts-ignore
764
+ expect(doc.nodeList[1].nextNode.uuid).toEqual(doc.nodeList[2].uuid);
765
+
766
+ // #text ⏎
767
+ expect(doc.nodeList[2].parentNode).toEqual(null);
768
+ // @ts-ignore
769
+ expect(doc.nodeList[2].prevNode.uuid).toEqual(doc.nodeList[1].uuid);
770
+ // @ts-ignore
771
+ expect(doc.nodeList[2].nextNode.uuid).toEqual(doc.nodeList[3].uuid);
772
+
773
+ // html <html␣lang="en">
774
+ expect(doc.nodeList[3].parentNode).toEqual(null);
775
+ // @ts-ignore
776
+ expect(doc.nodeList[3].prevNode.uuid).toEqual(doc.nodeList[2].uuid);
777
+ // @ts-ignore
778
+ expect(doc.nodeList[3].nextNode.uuid).toEqual(doc.nodeList[28].uuid);
779
+ // @ts-ignore
780
+ expect(doc.nodeList[3].pearNode.uuid).toEqual(doc.nodeList[27].uuid);
781
+
782
+ {
783
+ // @ts-ignore
784
+ expect(doc.nodeList[3].childNodes[0].uuid).toEqual(doc.nodeList[4].uuid);
785
+ // @ts-ignore
786
+ expect(doc.nodeList[3].childNodes[1].uuid).toEqual(doc.nodeList[5].uuid);
787
+ // @ts-ignore
788
+ expect(doc.nodeList[3].childNodes[2].uuid).toEqual(doc.nodeList[18].uuid);
789
+ // @ts-ignore
790
+ expect(doc.nodeList[3].childNodes[3].uuid).toEqual(doc.nodeList[19].uuid);
791
+ // @ts-ignore
792
+ expect(doc.nodeList[3].childNodes[4].uuid).toEqual(doc.nodeList[26].uuid);
793
+ }
794
+
795
+ // #text ⏎
796
+ // @ts-ignore
797
+ expect(doc.nodeList[4].parentNode.uuid).toEqual(doc.nodeList[3].uuid);
798
+ // @ts-ignore
799
+ expect(doc.nodeList[4].prevNode).toEqual(null);
800
+ // @ts-ignore
801
+ expect(doc.nodeList[4].nextNode.uuid).toEqual(doc.nodeList[5].uuid);
802
+
803
+ // head <head>
804
+ // @ts-ignore
805
+ expect(doc.nodeList[5].parentNode.uuid).toEqual(doc.nodeList[3].uuid);
806
+ // @ts-ignore
807
+ expect(doc.nodeList[5].prevNode.uuid).toEqual(doc.nodeList[4].uuid);
808
+ // @ts-ignore
809
+ expect(doc.nodeList[5].nextNode.uuid).toEqual(doc.nodeList[18].uuid);
810
+ // @ts-ignore
811
+ expect(doc.nodeList[5].pearNode.uuid).toEqual(doc.nodeList[17].uuid);
812
+
813
+ {
814
+ // @ts-ignore
815
+ expect(doc.nodeList[5].childNodes[0].uuid).toEqual(doc.nodeList[6].uuid);
816
+ // @ts-ignore
817
+ expect(doc.nodeList[5].childNodes[1].uuid).toEqual(doc.nodeList[7].uuid);
818
+ // @ts-ignore
819
+ expect(doc.nodeList[5].childNodes[2].uuid).toEqual(doc.nodeList[8].uuid);
820
+ // @ts-ignore
821
+ expect(doc.nodeList[5].childNodes[3].uuid).toEqual(doc.nodeList[9].uuid);
822
+ // @ts-ignore
823
+ expect(doc.nodeList[5].childNodes[4].uuid).toEqual(doc.nodeList[10].uuid);
824
+ // @ts-ignore
825
+ expect(doc.nodeList[5].childNodes[5].uuid).toEqual(doc.nodeList[11].uuid);
826
+ // @ts-ignore
827
+ expect(doc.nodeList[5].childNodes[6].uuid).toEqual(doc.nodeList[12].uuid);
828
+ // @ts-ignore
829
+ expect(doc.nodeList[5].childNodes[7].uuid).toEqual(doc.nodeList[13].uuid);
830
+ // @ts-ignore
831
+ expect(doc.nodeList[5].childNodes[8].uuid).toEqual(doc.nodeList[16].uuid);
832
+ }
833
+
834
+ // #text ⏎→
835
+ // @ts-ignore
836
+ expect(doc.nodeList[6].parentNode.uuid).toEqual(doc.nodeList[5].uuid);
837
+ // @ts-ignore
838
+ expect(doc.nodeList[6].prevNode).toEqual(null);
839
+ // @ts-ignore
840
+ expect(doc.nodeList[6].nextNode.uuid).toEqual(doc.nodeList[7].uuid);
841
+
842
+ // meta <meta␣charset="UTF-8">
843
+ // @ts-ignore
844
+ expect(doc.nodeList[7].parentNode.uuid).toEqual(doc.nodeList[5].uuid);
845
+ // @ts-ignore
846
+ expect(doc.nodeList[7].prevNode.uuid).toEqual(doc.nodeList[6].uuid);
847
+ // @ts-ignore
848
+ expect(doc.nodeList[7].nextNode.uuid).toEqual(doc.nodeList[8].uuid);
849
+ // @ts-ignore
850
+ expect(doc.nodeList[7].pearNode).toEqual(null);
851
+
852
+ // #text ⏎→
853
+ // @ts-ignore
854
+ expect(doc.nodeList[8].parentNode.uuid).toEqual(doc.nodeList[5].uuid);
855
+ // @ts-ignore
856
+ expect(doc.nodeList[8].prevNode.uuid).toEqual(doc.nodeList[7].uuid);
857
+ // @ts-ignore
858
+ expect(doc.nodeList[8].nextNode.uuid).toEqual(doc.nodeList[9].uuid);
859
+
860
+ // meta <meta␣name="viewport"␣content="width=device-width,␣initial-scale=1.0">
861
+ // @ts-ignore
862
+ expect(doc.nodeList[9].parentNode.uuid).toEqual(doc.nodeList[5].uuid);
863
+ // @ts-ignore
864
+ expect(doc.nodeList[9].prevNode.uuid).toEqual(doc.nodeList[8].uuid);
865
+ // @ts-ignore
866
+ expect(doc.nodeList[9].nextNode.uuid).toEqual(doc.nodeList[10].uuid);
867
+ // @ts-ignore
868
+ expect(doc.nodeList[9].pearNode).toEqual(null);
869
+
870
+ // #text ⏎→
871
+ // @ts-ignore
872
+ expect(doc.nodeList[10].parentNode.uuid).toEqual(doc.nodeList[5].uuid);
873
+ // @ts-ignore
874
+ expect(doc.nodeList[10].prevNode.uuid).toEqual(doc.nodeList[9].uuid);
875
+ // @ts-ignore
876
+ expect(doc.nodeList[10].nextNode.uuid).toEqual(doc.nodeList[11].uuid);
877
+
878
+ // meta <meta␣http-equiv="X-UA-Compatible"␣content="ie=edge">
879
+ // @ts-ignore
880
+ expect(doc.nodeList[11].parentNode.uuid).toEqual(doc.nodeList[5].uuid);
881
+ // @ts-ignore
882
+ expect(doc.nodeList[11].prevNode.uuid).toEqual(doc.nodeList[10].uuid);
883
+ // @ts-ignore
884
+ expect(doc.nodeList[11].nextNode.uuid).toEqual(doc.nodeList[12].uuid);
885
+ // @ts-ignore
886
+ expect(doc.nodeList[11].pearNode).toEqual(null);
887
+
888
+ // #text ⏎→
889
+ // @ts-ignore
890
+ expect(doc.nodeList[12].parentNode.uuid).toEqual(doc.nodeList[5].uuid);
891
+ // @ts-ignore
892
+ expect(doc.nodeList[12].prevNode.uuid).toEqual(doc.nodeList[11].uuid);
893
+ // @ts-ignore
894
+ expect(doc.nodeList[12].nextNode.uuid).toEqual(doc.nodeList[13].uuid);
895
+
896
+ // meta <title>
897
+ // @ts-ignore
898
+ expect(doc.nodeList[13].parentNode.uuid).toEqual(doc.nodeList[5].uuid);
899
+ // @ts-ignore
900
+ expect(doc.nodeList[13].prevNode.uuid).toEqual(doc.nodeList[12].uuid);
901
+ // @ts-ignore
902
+ expect(doc.nodeList[13].nextNode.uuid).toEqual(doc.nodeList[16].uuid);
903
+ // @ts-ignore
904
+ expect(doc.nodeList[13].pearNode.uuid).toEqual(doc.nodeList[15].uuid);
905
+
906
+ {
907
+ // @ts-ignore
908
+ expect(doc.nodeList[13].childNodes[0].uuid).toEqual(doc.nodeList[14].uuid);
909
+ }
910
+
911
+ // #text Document
912
+ // @ts-ignore
913
+ expect(doc.nodeList[14].parentNode.uuid).toEqual(doc.nodeList[13].uuid);
914
+ // @ts-ignore
915
+ expect(doc.nodeList[14].prevNode).toEqual(null);
916
+ // @ts-ignore
917
+ expect(doc.nodeList[14].nextNode).toEqual(null);
918
+
919
+ // meta </title>
920
+ // @ts-ignore
921
+ expect(doc.nodeList[15].parentNode.uuid).toEqual(doc.nodeList[5].uuid);
922
+ // @ts-ignore
923
+ expect(doc.nodeList[15].prevNode.uuid).toEqual(doc.nodeList[12].uuid);
924
+ // @ts-ignore
925
+ expect(doc.nodeList[15].nextNode.uuid).toEqual(doc.nodeList[16].uuid);
926
+ // @ts-ignore
927
+ expect(doc.nodeList[15].pearNode.uuid).toEqual(doc.nodeList[13].uuid);
928
+
929
+ // #text ⏎
930
+ // @ts-ignore
931
+ expect(doc.nodeList[16].parentNode.uuid).toEqual(doc.nodeList[5].uuid);
932
+ // @ts-ignore
933
+ expect(doc.nodeList[16].prevNode.uuid).toEqual(doc.nodeList[13].uuid);
934
+ // @ts-ignore
935
+ expect(doc.nodeList[16].nextNode).toEqual(null);
936
+
937
+ // meta </head>
938
+ // @ts-ignore
939
+ expect(doc.nodeList[17].parentNode.uuid).toEqual(doc.nodeList[3].uuid);
940
+ // @ts-ignore
941
+ expect(doc.nodeList[17].prevNode.uuid).toEqual(doc.nodeList[4].uuid);
942
+ // @ts-ignore
943
+ expect(doc.nodeList[17].nextNode.uuid).toEqual(doc.nodeList[18].uuid);
944
+ // @ts-ignore
945
+ expect(doc.nodeList[17].pearNode.uuid).toEqual(doc.nodeList[5].uuid);
946
+
947
+ // #text ⏎
948
+ // @ts-ignore
949
+ expect(doc.nodeList[18].parentNode.uuid).toEqual(doc.nodeList[3].uuid);
950
+ // @ts-ignore
951
+ expect(doc.nodeList[18].prevNode.uuid).toEqual(doc.nodeList[5].uuid);
952
+ // @ts-ignore
953
+ expect(doc.nodeList[18].nextNode.uuid).toEqual(doc.nodeList[19].uuid);
954
+
955
+ // head <body>
956
+ // @ts-ignore
957
+ expect(doc.nodeList[19].parentNode.uuid).toEqual(doc.nodeList[3].uuid);
958
+ // @ts-ignore
959
+ expect(doc.nodeList[19].prevNode.uuid).toEqual(doc.nodeList[18].uuid);
960
+ // @ts-ignore
961
+ expect(doc.nodeList[19].nextNode.uuid).toEqual(doc.nodeList[26].uuid);
962
+ // @ts-ignore
963
+ expect(doc.nodeList[19].pearNode.uuid).toEqual(doc.nodeList[25].uuid);
964
+
965
+ {
966
+ // @ts-ignore
967
+ expect(doc.nodeList[19].childNodes[0].uuid).toEqual(doc.nodeList[20].uuid);
968
+ // @ts-ignore
969
+ expect(doc.nodeList[19].childNodes[1].uuid).toEqual(doc.nodeList[21].uuid);
970
+ // @ts-ignore
971
+ expect(doc.nodeList[19].childNodes[2].uuid).toEqual(doc.nodeList[24].uuid);
972
+ }
973
+
974
+ // #text ⏎→
975
+ // @ts-ignore
976
+ expect(doc.nodeList[20].parentNode.uuid).toEqual(doc.nodeList[19].uuid);
977
+ // @ts-ignore
978
+ expect(doc.nodeList[20].prevNode).toEqual(null);
979
+ // @ts-ignore
980
+ expect(doc.nodeList[20].nextNode.uuid).toEqual(doc.nodeList[21].uuid);
981
+
982
+ // head <h1>
983
+ // @ts-ignore
984
+ expect(doc.nodeList[21].parentNode.uuid).toEqual(doc.nodeList[19].uuid);
985
+ // @ts-ignore
986
+ expect(doc.nodeList[21].prevNode.uuid).toEqual(doc.nodeList[20].uuid);
987
+ // @ts-ignore
988
+ expect(doc.nodeList[21].nextNode.uuid).toEqual(doc.nodeList[24].uuid);
989
+ // @ts-ignore
990
+ expect(doc.nodeList[21].pearNode.uuid).toEqual(doc.nodeList[23].uuid);
991
+
992
+ {
993
+ // @ts-ignore
994
+ expect(doc.nodeList[21].childNodes[0].uuid).toEqual(doc.nodeList[22].uuid);
995
+ }
996
+
997
+ // #text Title
998
+ // @ts-ignore
999
+ expect(doc.nodeList[22].parentNode.uuid).toEqual(doc.nodeList[21].uuid);
1000
+ // @ts-ignore
1001
+ expect(doc.nodeList[22].prevNode).toEqual(null);
1002
+ // @ts-ignore
1003
+ expect(doc.nodeList[22].nextNode).toEqual(null);
1004
+
1005
+ // head </h1>
1006
+ // @ts-ignore
1007
+ expect(doc.nodeList[23].parentNode.uuid).toEqual(doc.nodeList[19].uuid);
1008
+ // @ts-ignore
1009
+ expect(doc.nodeList[23].prevNode.uuid).toEqual(doc.nodeList[20].uuid);
1010
+ // @ts-ignore
1011
+ expect(doc.nodeList[23].nextNode.uuid).toEqual(doc.nodeList[24].uuid);
1012
+ // @ts-ignore
1013
+ expect(doc.nodeList[23].pearNode.uuid).toEqual(doc.nodeList[21].uuid);
1014
+
1015
+ // #text ⏎
1016
+ // @ts-ignore
1017
+ expect(doc.nodeList[24].parentNode.uuid).toEqual(doc.nodeList[19].uuid);
1018
+ // @ts-ignore
1019
+ expect(doc.nodeList[24].prevNode.uuid).toEqual(doc.nodeList[21].uuid);
1020
+ // @ts-ignore
1021
+ expect(doc.nodeList[24].nextNode).toEqual(null);
1022
+
1023
+ // </body>
1024
+ // @ts-ignore
1025
+ expect(doc.nodeList[25].parentNode.uuid).toEqual(doc.nodeList[3].uuid);
1026
+ // @ts-ignore
1027
+ expect(doc.nodeList[25].prevNode.uuid).toEqual(doc.nodeList[18].uuid);
1028
+ // @ts-ignore
1029
+ expect(doc.nodeList[25].nextNode.uuid).toEqual(doc.nodeList[26].uuid);
1030
+ // @ts-ignore
1031
+ expect(doc.nodeList[25].pearNode.uuid).toEqual(doc.nodeList[19].uuid);
1032
+
1033
+ // #text ⏎
1034
+ // @ts-ignore
1035
+ expect(doc.nodeList[26].parentNode.uuid).toEqual(doc.nodeList[3].uuid);
1036
+ // @ts-ignore
1037
+ expect(doc.nodeList[26].prevNode.uuid).toEqual(doc.nodeList[25].uuid);
1038
+ // @ts-ignore
1039
+ expect(doc.nodeList[26].nextNode).toEqual(null);
1040
+
1041
+ // </html>
1042
+ expect(doc.nodeList[27].parentNode).toEqual(null);
1043
+ // @ts-ignore
1044
+ expect(doc.nodeList[27].prevNode.uuid).toEqual(doc.nodeList[2].uuid);
1045
+ // @ts-ignore
1046
+ expect(doc.nodeList[27].nextNode.uuid).toEqual(doc.nodeList[28].uuid);
1047
+ // @ts-ignore
1048
+ expect(doc.nodeList[27].pearNode.uuid).toEqual(doc.nodeList[3].uuid);
1049
+
1050
+ // #text ⏎
1051
+ // @ts-ignore
1052
+ expect(doc.nodeList[28].parentNode).toEqual(null);
1053
+ // @ts-ignore
1054
+ expect(doc.nodeList[28].prevNode.uuid).toEqual(doc.nodeList[27].uuid);
1055
+ // @ts-ignore
1056
+ expect(doc.nodeList[28].nextNode).toEqual(null);
1057
+ });
1058
+
1059
+ it('UUID', () => {
1060
+ const doc = parse(`<html>
1061
+ <body></body>
1062
+ </html>`);
1063
+ // const map = nodeListToDebugMaps(doc.nodeList);
1064
+ // console.log(map);
1065
+
1066
+ // @ts-ignore
1067
+ expect(doc.nodeList[3].nextNode.uuid).toEqual(doc.nodeList[5].uuid);
1068
+ // @ts-ignore
1069
+ expect(doc.nodeList[4].nextNode.uuid).toEqual(doc.nodeList[5].uuid);
1070
+ });
1071
+
1072
+ it('Offset', () => {
1073
+ const doc = parse(
1074
+ `<span>
1075
+ <img src="path/to">
1076
+ </span>
1077
+ `,
1078
+ {
1079
+ offsetOffset: 15,
1080
+ offsetLine: 2,
1081
+ offsetColumn: 2,
1082
+ },
1083
+ );
1084
+ const map = nodeListToDebugMaps(doc.nodeList);
1085
+ expect(map).toStrictEqual([
1086
+ '[3:3]>[3:9](15,21)span: <span>',
1087
+ '[3:9]>[4:4](21,25)#text: ⏎→→→',
1088
+ '[4:4]>[4:25](25,44)img: <img␣src="path/to">',
1089
+ '[4:23]>[5:3](44,47)#text: ⏎→→',
1090
+ '[5:3]>[5:10](47,54)span: </span>',
1091
+ '[5:10]>[6:4](54,58)#text: ⏎→→→',
1092
+ ]);
1093
+
1094
+ // @ts-ignore
1095
+ expect(doc.nodeList[2].attributes[0].startOffset).toBe(30);
1096
+ // @ts-ignore
1097
+ expect(doc.nodeList[2].attributes[0].endOffset).toBe(43);
1098
+ // @ts-ignore
1099
+ expect(doc.nodeList[2].attributes[0].startLine).toBe(4);
1100
+ // @ts-ignore
1101
+ expect(doc.nodeList[2].attributes[0].endLine).toBe(4);
1102
+ // @ts-ignore
1103
+ expect(doc.nodeList[2].attributes[0].startCol).toBe(9);
1104
+ // @ts-ignore
1105
+ expect(doc.nodeList[2].attributes[0].endCol).toBe(22);
1106
+ });
1107
+
1108
+ it('The fragment tree', () => {
1109
+ const doc = parse('<audio><source media="print"></audio>');
1110
+ // const map = nodeListToDebugMaps(doc.nodeList);
1111
+ // console.log(map);
1112
+
1113
+ expect(doc.nodeList[0].parentNode).toEqual(null);
1114
+ expect(doc.nodeList[1].parentNode.parentNode).toEqual(null);
1115
+ });
1116
+
1117
+ it('code in script', () => {
1118
+ const doc = parse("<script>const $span = '<span>text</span>';</script>");
1119
+ const map = nodeListToDebugMaps(doc.nodeList);
1120
+ expect(doc.unknownParseError).toBeUndefined();
1121
+ expect(map).toStrictEqual([
1122
+ '[1:1]>[1:9](0,8)script: <script>',
1123
+ "[1:9]>[1:43](8,42)#text: const␣$span␣=␣'<span>text</span>';",
1124
+ '[1:43]>[1:52](42,51)script: </script>',
1125
+ ]);
1126
+ });
1127
+
1128
+ it('With frontmatter', () => {
1129
+ const doc = parse('===\np: v\n===\n<html></html>', { ignoreFrontMatter: true });
1130
+ expect(doc.nodeList[0].nodeName).toBe('html');
1131
+
1132
+ const doc2 = parse('===\np: v\n===\n<html></html>', { ignoreFrontMatter: false });
1133
+ expect(doc2.nodeList[0].nodeName).toBe('html');
1134
+ expect(doc2.nodeList[0].isGhost).toBe(true);
1135
+
1136
+ const doc3 = parse('===\np: v\n===\n<div></div>', { ignoreFrontMatter: true });
1137
+ expect(doc3.nodeList[0].nodeName).toBe('#text');
1138
+ expect(doc3.nodeList[1].nodeName).toBe('div');
1139
+
1140
+ const doc4 = parse('===\np: v\n===\n<div></div>', { ignoreFrontMatter: false });
1141
+ expect(doc4.nodeList[0].nodeName).toBe('#text');
1142
+ expect(doc4.nodeList[1].nodeName).toBe('div');
1143
+ });
1144
+
1145
+ it('Static attribute', () => {
1146
+ const ast = parse('<a href=""/>');
1147
+ // @ts-ignore
1148
+ const attrMaps = attributesToDebugMaps(ast.nodeList[0].attributes);
1149
+ expect(attrMaps).toStrictEqual([
1150
+ [
1151
+ '[1:4]>[1:11](3,10)href: href=""',
1152
+ ' [1:3]>[1:4](2,3)bN: ␣',
1153
+ ' [1:4]>[1:8](3,7)name: href',
1154
+ ' [1:8]>[1:8](7,7)bE: ',
1155
+ ' [1:8]>[1:9](7,8)equal: =',
1156
+ ' [1:9]>[1:9](8,8)aE: ',
1157
+ ' [1:9]>[1:10](8,9)sQ: "',
1158
+ ' [1:10]>[1:10](9,9)value: ',
1159
+ ' [1:10]>[1:11](9,10)eQ: "',
1160
+ ' isDirective: false',
1161
+ ' isDynamicValue: false',
1162
+ ],
1163
+ ]);
1164
+ });
1165
+
1166
+ it('svg', () => {
1167
+ const doc = parse(`<div>
1168
+ <svg>
1169
+ <a></a>
1170
+ <switch>
1171
+ <g>
1172
+ <rect />
1173
+ </g>
1174
+ <foreignObject>
1175
+ <div></div>
1176
+ </foreignObject>
1177
+ </switch>
1178
+ </svg>
1179
+ </div>
1180
+ `);
1181
+ const map = nodeListToDebugMaps(doc.nodeList);
1182
+ expect(map).toStrictEqual([
1183
+ '[1:1]>[1:6](0,5)div: <div>',
1184
+ '[1:6]>[2:2](5,7)#text: ⏎→',
1185
+ '[2:2]>[2:7](7,12)svg: <svg>',
1186
+ '[2:7]>[3:3](12,15)#text: ⏎→→',
1187
+ '[3:3]>[3:6](15,18)a: <a>',
1188
+ '[3:6]>[3:10](18,22)a: </a>',
1189
+ '[3:10]>[4:3](22,25)#text: ⏎→→',
1190
+ '[4:3]>[4:11](25,33)switch: <switch>',
1191
+ '[4:11]>[5:4](33,37)#text: ⏎→→→',
1192
+ '[5:4]>[5:7](37,40)g: <g>',
1193
+ '[5:7]>[6:5](40,45)#text: ⏎→→→→',
1194
+ '[6:5]>[6:13](45,53)rect: <rect␣/>',
1195
+ '[6:13]>[7:4](53,57)#text: ⏎→→→',
1196
+ '[7:4]>[7:8](57,61)g: </g>',
1197
+ '[7:8]>[8:4](61,65)#text: ⏎→→→',
1198
+ '[8:4]>[8:19](65,80)foreignObject: <foreignObject>',
1199
+ '[8:19]>[9:5](80,85)#text: ⏎→→→→',
1200
+ '[9:5]>[9:10](85,90)div: <div>',
1201
+ '[9:10]>[9:16](90,96)div: </div>',
1202
+ '[9:16]>[10:4](96,100)#text: ⏎→→→',
1203
+ '[10:4]>[10:20](100,116)foreignObject: </foreignObject>',
1204
+ '[10:20]>[11:3](116,119)#text: ⏎→→',
1205
+ '[11:3]>[11:12](119,128)switch: </switch>',
1206
+ '[11:12]>[12:2](128,130)#text: ⏎→',
1207
+ '[12:2]>[12:8](130,136)svg: </svg>',
1208
+ '[12:8]>[13:1](136,137)#text: ⏎',
1209
+ '[13:1]>[13:7](137,143)div: </div>',
1210
+ '[13:7]>[14:1](143,144)#text: ⏎',
1211
+ ]);
1212
+ });
1213
+ });
1214
+
1215
+ describe('Issues', () => {
1216
+ test('#775', () => {
1217
+ expect(nodeListToDebugMaps(parse('<pre>text</pre>').nodeList)).toStrictEqual([
1218
+ '[1:1]>[1:6](0,5)pre: <pre>',
1219
+ '[1:6]>[1:10](5,9)#text: text',
1220
+ '[1:10]>[1:16](9,15)pre: </pre>',
1221
+ ]);
1222
+
1223
+ const nodes = parse('<pre>\ntext</pre>').nodeList;
1224
+
1225
+ expect(nodeListToDebugMaps(nodes)).toStrictEqual([
1226
+ '[1:1]>[1:6](0,5)pre: <pre>',
1227
+ '[1:6]>[2:5](5,10)#text: ⏎text',
1228
+ '[2:5]>[2:11](10,16)pre: </pre>',
1229
+ ]);
1230
+
1231
+ expect(nodes[0].childNodes?.[0]?.raw).toBe('\ntext');
1232
+
1233
+ /**
1234
+ * Test for `<textarea>`
1235
+ *
1236
+ * @see https://html.spec.whatwg.org/multipage/syntax.html#element-restrictions
1237
+ */
1238
+ const textarea = parse('<textarea>\ntext</textarea>').nodeList;
1239
+ expect(nodeListToDebugMaps(textarea)).toStrictEqual([
1240
+ '[1:1]>[1:11](0,10)textarea: <textarea>',
1241
+ '[1:11]>[2:5](10,15)#text: ⏎text',
1242
+ '[2:5]>[2:16](15,26)textarea: </textarea>',
1243
+ ]);
1244
+ expect(textarea[0].childNodes?.[0]?.raw).toBe('\ntext');
1245
+ });
1246
+ });