@lowlighter/xml 6.0.1 → 8.0.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.
package/parse_test.ts DELETED
@@ -1,1303 +0,0 @@
1
- import { parse } from "./parse.ts"
2
- import { expect, test, type testing } from "@libs/testing"
3
- import { fromFileUrl } from "@std/path/from-file-url"
4
- import { exists } from "@std/fs/exists"
5
-
6
- //Huge xml file generator
7
- export async function write(size: number) {
8
- const path = fromFileUrl(import.meta.resolve(`./bench/assets/x-${size}x-large.xml`))
9
- if (await exists(path)) {
10
- return
11
- }
12
- using file = await Deno.open(path, { write: true, create: true })
13
- const encoder = new TextEncoder()
14
- await file.write(encoder.encode("<root>"))
15
- for (let i = 0; i < (2 ** size) * 15500; i++) {
16
- await file.write(encoder.encode(`<child>${Math.random()}</child>`))
17
- }
18
- await file.write(encoder.encode("</root>"))
19
- }
20
-
21
- test("all")("`parse()` xml syntax tag", () =>
22
- expect(
23
- parse(`
24
- <root>hello world</root>
25
- `),
26
- ).toEqual(
27
- {
28
- root: "hello world",
29
- },
30
- ))
31
-
32
- test("all")("`parse()` xml syntax tag with attributes", () =>
33
- expect(
34
- parse(`
35
- <root lang="en" type="greeting">hello world</root>
36
- `),
37
- ).toEqual(
38
- {
39
- root: {
40
- "@lang": "en",
41
- "@type": "greeting",
42
- "#text": "hello world",
43
- },
44
- },
45
- ))
46
-
47
- test("all")("`parse()` xml syntax self-closing tag", () =>
48
- expect(
49
- parse(`
50
- <root/>
51
- `),
52
- ).toEqual(
53
- {
54
- root: null,
55
- },
56
- ))
57
-
58
- test("all")("`parse()` xml syntax self-closing with attributes", () =>
59
- expect(
60
- parse(`
61
- <root lang="en" type="greeting" text="hello world"></root>
62
- `),
63
- ).toEqual(
64
- {
65
- root: {
66
- "@lang": "en",
67
- "@type": "greeting",
68
- "@text": "hello world",
69
- },
70
- },
71
- ))
72
-
73
- test("all")("`parse()` xml syntax empty tag", () =>
74
- expect(
75
- parse(`
76
- <root></root>
77
- `),
78
- ).toEqual(
79
- {
80
- root: null,
81
- },
82
- ))
83
-
84
- test("all")("`parse()` xml syntax empty tag with attributes", () =>
85
- expect(
86
- parse(`
87
- <root type="test"></root>
88
- `),
89
- ).toEqual(
90
- {
91
- root: {
92
- "@type": "test",
93
- },
94
- },
95
- ))
96
-
97
- test("all")("`parse()` xml syntax simple tree", () =>
98
- expect(
99
- parse(`
100
- <root>
101
- <child>
102
- <subchild>.....</subchild>
103
- </child>
104
- </root>
105
- `),
106
- ).toEqual(
107
- {
108
- root: {
109
- child: {
110
- subchild: ".....",
111
- },
112
- },
113
- },
114
- ))
115
-
116
- test("all")("`parse()` xml syntax simple tree with same tags", () =>
117
- expect(
118
- parse(`
119
- <root>
120
- <child>world</child>
121
- <child>monde</child>
122
- <child>世界</child>
123
- <child>🌏</child>
124
- </root>
125
- `),
126
- ).toEqual(
127
- {
128
- root: {
129
- child: ["world", "monde", "世界", "🌏"],
130
- },
131
- },
132
- ))
133
-
134
- test("all")("`parse()` xml syntax simple tree with same tags and attributes", () =>
135
- expect(
136
- parse(`
137
- <root>
138
- <child lang="en">world</child>
139
- <child lang="fr">monde</child>
140
- <child lang="zh">世界</child>
141
- <child lang="🦕">🌏</child>
142
- </root>
143
- `),
144
- ).toEqual(
145
- {
146
- root: {
147
- child: [
148
- { "@lang": "en", "#text": "world" },
149
- { "@lang": "fr", "#text": "monde" },
150
- { "@lang": "zh", "#text": "世界" },
151
- { "@lang": "🦕", "#text": "🌏" },
152
- ],
153
- },
154
- },
155
- ))
156
-
157
- test("all")("`parse()` xml syntax simple tree with nested tags of same name", () =>
158
- expect(
159
- parse(`
160
- <root>
161
- <child>
162
- <child>
163
- <child>
164
- <child/>
165
- </child>
166
- </child>
167
- </child>
168
- </root>
169
- `),
170
- ).toEqual(
171
- {
172
- root: {
173
- child: { child: { child: { child: null } } },
174
- },
175
- },
176
- ))
177
-
178
- test("all")("`parse()` xml syntax mixed content", () =>
179
- expect(
180
- parse(`
181
- <root>some <b>bold</b> text</root>
182
- `),
183
- ).toEqual(
184
- {
185
- root: {
186
- "#text": "some bold text",
187
- b: "bold",
188
- },
189
- },
190
- ))
191
-
192
- test("all")("`parse()` xml syntax nested mixed content", () =>
193
- expect(
194
- parse(`
195
- <root>some <b>bold <i>italic</i> </b> text</root>
196
- `),
197
- ).toEqual(
198
- {
199
- root: {
200
- "#text": "some bold italic text",
201
- b: {
202
- "#text": "bold italic",
203
- i: "italic",
204
- },
205
- },
206
- },
207
- ))
208
-
209
- test("all")("`parse()` xml syntax xml prolog", () =>
210
- expect(
211
- parse(
212
- `
213
- <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
214
- <root></root>
215
- `,
216
- ),
217
- ).toEqual(
218
- {
219
- "@version": "1.0",
220
- "@encoding": "UTF-8",
221
- "@standalone": "yes",
222
- root: null,
223
- },
224
- ))
225
-
226
- test("all")("`parse()` xml syntax xml stylesheet", () =>
227
- expect(
228
- parse(
229
- `
230
- <?xml version="1.0" encoding="UTF-8"?>
231
- <?xml-stylesheet href="styles1.xsl" type="text/xsl"?>
232
- <?xml-stylesheet href="styles2.xsl" type="text/xsl"?>
233
- <?xml-stylesheet href="styles3.xsl" type="text/xsl"?>
234
- <root></root>
235
- `,
236
- ),
237
- ).toEqual(
238
- {
239
- "@version": "1.0",
240
- "@encoding": "UTF-8",
241
- "#instructions": {
242
- "xml-stylesheet": [{
243
- "@href": "styles1.xsl",
244
- "@type": "text/xsl",
245
- }, {
246
- "@href": "styles2.xsl",
247
- "@type": "text/xsl",
248
- }, {
249
- "@href": "styles3.xsl",
250
- "@type": "text/xsl",
251
- }],
252
- },
253
- root: null,
254
- },
255
- ))
256
-
257
- test("all")("`parse()` xml syntax doctype", () =>
258
- expect(
259
- parse(
260
- `
261
- <!DOCTYPE type "quoted attribute">
262
- <root></root>
263
- `,
264
- ),
265
- ).toEqual(
266
- {
267
- "#doctype": {
268
- "@type": "",
269
- "@quoted attribute": "",
270
- },
271
- root: null,
272
- },
273
- ))
274
-
275
- test("all")("`parse()` xml syntax doctype with element", () =>
276
- expect(
277
- parse(
278
- `
279
- <!DOCTYPE type "quoted attribute"
280
- [
281
- <!ELEMENT note (to,from,heading,body)>
282
- <!ELEMENT to (#PCDATA)>
283
- <!ELEMENT from (#PCDATA)>
284
- <!ELEMENT heading (#PCDATA)>
285
- <!ELEMENT body (#PCDATA)>
286
- ]
287
- >
288
- <root></root>
289
- `,
290
- ),
291
- ).toEqual(
292
- {
293
- "#doctype": {
294
- "@type": "",
295
- "@quoted attribute": "",
296
- note: "to,from,heading,body",
297
- to: "#PCDATA",
298
- from: "#PCDATA",
299
- heading: "#PCDATA",
300
- body: "#PCDATA",
301
- },
302
- root: null,
303
- },
304
- ))
305
-
306
- test("all")("`parse()` xml syntax case sensitive", () =>
307
- expect(
308
- parse(`
309
- <root>
310
- <child>
311
- <subchild>1</subchild>
312
- <subchild>2</subchild>
313
- </child>
314
- <Child>
315
- <subchild></subchild>
316
- <SubChild></SubChild>
317
- </Child>
318
- <CHILD></CHILD>
319
- </root>
320
- `),
321
- ).toEqual(
322
- {
323
- root: {
324
- child: {
325
- subchild: ["1", "2"],
326
- },
327
- Child: {
328
- subchild: null,
329
- SubChild: null,
330
- },
331
- CHILD: null,
332
- },
333
- },
334
- ))
335
-
336
- test("all")("`parse()` xml syntax defined entities", () =>
337
- expect(
338
- parse(`
339
- <root>
340
- &lt; &gt; &amp; &apos; &quot;
341
- </root>
342
- `),
343
- ).toEqual(
344
- {
345
- root: `< > & ' "`,
346
- },
347
- ))
348
-
349
- test("all")("`parse()` xml syntax decimal entity reference", () =>
350
- expect(
351
- parse(`
352
- <root>
353
- &#38;
354
- </root>
355
- `),
356
- ).toEqual(
357
- {
358
- root: "&",
359
- },
360
- ))
361
-
362
- test("all")("`parse()` xml syntax hexadecimal entity reference", () =>
363
- expect(
364
- parse(`
365
- <root>
366
- &#x26;
367
- </root>
368
- `),
369
- ).toEqual(
370
- {
371
- root: "&",
372
- },
373
- ))
374
-
375
- test("all")("`parse()` xml syntax comments", () =>
376
- expect(
377
- parse(`
378
- <root>
379
- <!-- COMMENT 1 -->
380
- <child type="test" />
381
- <!-- COMMENT 2 -->
382
- <!--+++++++++++++++++++++-->
383
- </root>
384
- `),
385
- ).toEqual(
386
- {
387
- root: {
388
- "#comments": ["COMMENT 1", "COMMENT 2", "+++++++++++++++++++++"],
389
- child: {
390
- "@type": "test",
391
- },
392
- },
393
- },
394
- ))
395
-
396
- test("all")("`parse()` xml syntax comments in-between text nodes", () =>
397
- expect(
398
- parse(`
399
- <root>
400
- Hello
401
- <!-- COMMENT -->
402
- world
403
- </root>
404
- `),
405
- ).toEqual(
406
- {
407
- root: {
408
- "#comments": ["COMMENT"],
409
- "#text": "Hello world",
410
- },
411
- },
412
- ))
413
-
414
- test("all")("`parse()` xml syntax white spaces preserved", () =>
415
- expect(
416
- parse(`
417
- <root>
418
- Hello world how
419
- are you?
420
- </root>
421
- `),
422
- ).toEqual(
423
- {
424
- root: `Hello world how
425
- are you?`,
426
- },
427
- ))
428
-
429
- test("all")("`parse()` xml syntax CDATA", () =>
430
- expect(
431
- parse(`
432
- <root>
433
- <script type="text/javascript"><![CDATA[function match(a,b) {
434
- if (a < b && a < 0) { return 1; }
435
- else { return 0; }
436
- }]]></script>
437
- </root>
438
- `),
439
- ).toEqual(
440
- {
441
- root: {
442
- script: {
443
- "@type": "text/javascript",
444
- "#text": `function match(a,b) {
445
- if (a < b && a < 0) { return 1; }
446
- else { return 0; }
447
- }`,
448
- },
449
- },
450
- },
451
- ))
452
-
453
- test("all")("`parse()` xml syntax mixed content with CDATA", () =>
454
- expect(
455
- parse(`
456
- <root>
457
- <script type="text/javascript">this is a <b>test</b> <![CDATA[function match(a,b) {
458
- if (a < b && a < 0) { return 1; }
459
- else { return 0; }
460
- }]]></script>
461
- </root>
462
- `),
463
- ).toEqual(
464
- {
465
- root: {
466
- script: {
467
- "@type": "text/javascript",
468
- "#text": `this is a test function match(a,b) {
469
- if (a < b && a < 0) { return 1; }
470
- else { return 0; }
471
- }`,
472
- b: "test",
473
- },
474
- },
475
- },
476
- ))
477
-
478
- test("all")("`parse()` xml syntax with multiple CDATA's", () =>
479
- expect(
480
- parse(`
481
- <root>
482
- <text><![CDATA[ a ]]></text>
483
- <text><![CDATA[ b ]]></text>
484
- </root>`),
485
- ).toEqual(
486
- {
487
- root: {
488
- text: [
489
- "a",
490
- "b",
491
- ],
492
- },
493
- },
494
- ))
495
-
496
- test("all")("`parse()` xml space preserve", () =>
497
- expect(
498
- parse(`
499
- <root>
500
- <text xml:space="preserve"> hello<b> the</b> world </text>
501
- </root>`),
502
- ).toEqual(
503
- {
504
- root: {
505
- text: {
506
- "#text": " hello the world ",
507
- "@xml:space": "preserve",
508
- b: "the",
509
- },
510
- },
511
- },
512
- ))
513
-
514
- //Errors checks
515
-
516
- test("all")("`parse()` xml syntax unique root", () =>
517
- expect(() =>
518
- parse(`
519
- <root>
520
- <child>
521
- <subchild>.....</subchild>
522
- </child>
523
- </root>
524
- <root>
525
- <child>
526
- <subchild>.....</subchild>
527
- </child>
528
- </root>
529
- `)
530
- ).toThrow(SyntaxError))
531
-
532
- test("all")("`parse()` xml syntax closing tag", () =>
533
- expect(() =>
534
- parse(`
535
- <root>
536
- <child>
537
- </root>
538
- `)
539
- ).toThrow(SyntaxError))
540
-
541
- test("all")("`parse()` xml syntax closing properly nested", () =>
542
- expect(() =>
543
- parse(`
544
- <root>
545
- <child><subchild></child></subchild>
546
- </root>
547
- `)
548
- ).toThrow(SyntaxError))
549
-
550
- test("all")("`parse()` xml syntax attributes quoted", () =>
551
- expect(() =>
552
- parse(`
553
- <root>
554
- <child test=hey></child>
555
- </root>
556
- `)
557
- ).toThrow(SyntaxError))
558
-
559
- test("all")("`parse()` xml syntax attributes properly quoted", () =>
560
- expect(() =>
561
- parse(`
562
- <root>
563
- <child test="hey></child>
564
- </root>
565
- `)
566
- ).toThrow(SyntaxError))
567
-
568
- test("all")("`parse()` xml syntax first character", () => {
569
- expect(() => parse(`a>1</a>`)).toThrow(SyntaxError)
570
- expect(() => parse(`xml`)).toThrow(SyntaxError)
571
- expect(() => parse(`""`)).toThrow(SyntaxError)
572
- expect(() => parse(`{a: 1}`)).toThrow(SyntaxError)
573
- })
574
-
575
- test("all")("`parse()` wasm crashed", () => {
576
- expect(() => parse(Symbol("Expected error") as testing)).toThrow(EvalError)
577
- })
578
-
579
- //Example below were taken from https://www.w3schools.com/xml/default.asp
580
-
581
- test("all")("`parse()` xml example w3schools.com#1", () =>
582
- expect(
583
- parse(`
584
- <note>
585
- <to>Tove</to>
586
- <from>Jani</from>
587
- <heading>Reminder</heading>
588
- <body>Don't forget me this weekend!</body>
589
- </note>
590
- `),
591
- ).toEqual(
592
- {
593
- note: {
594
- to: "Tove",
595
- from: "Jani",
596
- heading: "Reminder",
597
- body: "Don't forget me this weekend!",
598
- },
599
- },
600
- ))
601
-
602
- test("all")("`parse()` xml example w3schools.com#2", () =>
603
- expect(
604
- parse(`
605
- <note>
606
- <date>2015-09-01</date>
607
- <hour>08:30</hour>
608
- <to>Tove</to>
609
- <from>Jani</from>
610
- <body>Don't forget me this weekend!</body>
611
- </note>
612
- `),
613
- ).toEqual(
614
- {
615
- note: {
616
- date: "2015-09-01",
617
- hour: "08:30",
618
- to: "Tove",
619
- from: "Jani",
620
- body: "Don't forget me this weekend!",
621
- },
622
- },
623
- ))
624
-
625
- test("all")("`parse()` xml example w3schools.com#3", () =>
626
- expect(
627
- parse(`
628
- <bookstore>
629
-
630
- <book category="cooking">
631
- <title lang="en">Everyday Italian</title>
632
- <author>Giada De Laurentiis</author>
633
- <year>2005</year>
634
- <price>30.00</price>
635
- </book>
636
-
637
- <book category="children">
638
- <title lang="en">Harry Potter</title>
639
- <author>J K. Rowling</author>
640
- <year>2005</year>
641
- <price>29.99</price>
642
- </book>
643
-
644
- <book category="web">
645
- <title lang="en">XQuery Kick Start</title>
646
- <author>James McGovern</author>
647
- <author>Per Bothner</author>
648
- <author>Kurt Cagle</author>
649
- <author>James Linn</author>
650
- <author>Vaidyanathan Nagarajan</author>
651
- <year>2003</year>
652
- <price>49.99</price>
653
- </book>
654
-
655
- <book category="web" cover="paperback">
656
- <title lang="en">Learning XML</title>
657
- <author>Erik T. Ray</author>
658
- <year>2003</year>
659
- <price>39.95</price>
660
- </book>
661
-
662
- </bookstore>
663
- `),
664
- ).toEqual(
665
- {
666
- bookstore: {
667
- book: [
668
- {
669
- "@category": "cooking",
670
- title: { "@lang": "en", "#text": "Everyday Italian" },
671
- author: "Giada De Laurentiis",
672
- year: "2005",
673
- price: "30.00",
674
- },
675
- {
676
- "@category": "children",
677
- title: { "@lang": "en", "#text": "Harry Potter" },
678
- author: "J K. Rowling",
679
- year: "2005",
680
- price: "29.99",
681
- },
682
- {
683
- "@category": "web",
684
- title: { "@lang": "en", "#text": "XQuery Kick Start" },
685
- author: [
686
- "James McGovern",
687
- "Per Bothner",
688
- "Kurt Cagle",
689
- "James Linn",
690
- "Vaidyanathan Nagarajan",
691
- ],
692
- year: "2003",
693
- price: "49.99",
694
- },
695
- {
696
- "@category": "web",
697
- "@cover": "paperback",
698
- title: { "@lang": "en", "#text": "Learning XML" },
699
- author: "Erik T. Ray",
700
- year: "2003",
701
- price: "39.95",
702
- },
703
- ],
704
- },
705
- },
706
- ))
707
-
708
- test("all")("`parse()` xml example w3schools.com#4", () =>
709
- expect(
710
- parse(`
711
- <nitf>
712
- <head>
713
- <title>Colombia Earthquake</title>
714
- </head>
715
- <body>
716
- <headline>
717
- <hl1>143 Dead in Colombia Earthquake</hl1>
718
- </headline>
719
- <byline>
720
- <bytag>By Jared Kotler, Associated Press Writer</bytag>
721
- </byline>
722
- <dateline>
723
- <location>Bogota, Colombia</location>
724
- <date>Monday January 25 1999 7:28 ET</date>
725
- </dateline>
726
- </body>
727
- </nitf>
728
- `),
729
- ).toEqual(
730
- {
731
- nitf: {
732
- head: {
733
- title: "Colombia Earthquake",
734
- },
735
- body: {
736
- headline: {
737
- hl1: "143 Dead in Colombia Earthquake",
738
- },
739
- byline: {
740
- bytag: "By Jared Kotler, Associated Press Writer",
741
- },
742
- dateline: {
743
- location: "Bogota, Colombia",
744
- date: "Monday January 25 1999 7:28 ET",
745
- },
746
- },
747
- },
748
- },
749
- ))
750
-
751
- test("all")("`parse()` xml example w3schools.com#5", () =>
752
- expect(
753
- parse(
754
- `
755
- <current_observation>
756
-
757
- <credit>NOAA's National Weather Service</credit>
758
- <credit_URL>http://weather.gov/</credit_URL>
759
-
760
- <image>
761
- <url>http://weather.gov/images/xml_logo.gif</url>
762
- <title>NOAA's National Weather Service</title>
763
- <link>http://weather.gov</link>
764
- </image>
765
-
766
- <location>New York/John F. Kennedy Intl Airport, NY</location>
767
- <station_id>KJFK</station_id>
768
- <latitude>40.66</latitude>
769
- <longitude>-73.78</longitude>
770
- <observation_time_rfc822>Mon, 11 Feb 2008 06:51:00 -0500 EST
771
- </observation_time_rfc822>
772
-
773
- <weather>A Few Clouds</weather>
774
- <temp_f>11</temp_f>
775
- <temp_c>-12</temp_c>
776
- <relative_humidity>36</relative_humidity>
777
- <wind_dir>West</wind_dir>
778
- <wind_degrees>280</wind_degrees>
779
- <wind_mph>18.4</wind_mph>
780
- <wind_gust_mph>29</wind_gust_mph>
781
- <pressure_mb>1023.6</pressure_mb>
782
- <pressure_in>30.23</pressure_in>
783
- <dewpoint_f>-11</dewpoint_f>
784
- <dewpoint_c>-24</dewpoint_c>
785
- <windchill_f>-7</windchill_f>
786
- <windchill_c>-22</windchill_c>
787
- <visibility_mi>10.00</visibility_mi>
788
-
789
- <icon_url_base>http://weather.gov/weather/images/fcicons/</icon_url_base>
790
- <icon_url_name>nfew.jpg</icon_url_name>
791
- <disclaimer_url>http://weather.gov/disclaimer.html</disclaimer_url>
792
- <copyright_url>http://weather.gov/disclaimer.html</copyright_url>
793
-
794
- </current_observation>
795
- `,
796
- { revive: { numbers: true } },
797
- ),
798
- ).toEqual(
799
- {
800
- current_observation: {
801
- credit: "NOAA's National Weather Service",
802
- credit_URL: "http://weather.gov/",
803
- image: {
804
- url: "http://weather.gov/images/xml_logo.gif",
805
- title: "NOAA's National Weather Service",
806
- link: "http://weather.gov",
807
- },
808
- location: "New York/John F. Kennedy Intl Airport, NY",
809
- station_id: "KJFK",
810
- latitude: 40.66,
811
- longitude: -73.78,
812
- observation_time_rfc822: "Mon, 11 Feb 2008 06:51:00 -0500 EST",
813
- weather: "A Few Clouds",
814
- temp_f: 11,
815
- temp_c: -12,
816
- relative_humidity: 36,
817
- wind_dir: "West",
818
- wind_degrees: 280,
819
- wind_mph: 18.4,
820
- wind_gust_mph: 29,
821
- pressure_mb: 1023.6,
822
- pressure_in: 30.23,
823
- dewpoint_f: -11,
824
- dewpoint_c: -24,
825
- windchill_f: -7,
826
- windchill_c: -22,
827
- visibility_mi: 10.00,
828
- icon_url_base: "http://weather.gov/weather/images/fcicons/",
829
- icon_url_name: "nfew.jpg",
830
- disclaimer_url: "http://weather.gov/disclaimer.html",
831
- copyright_url: "http://weather.gov/disclaimer.html",
832
- },
833
- },
834
- ))
835
-
836
- test("all")("`parse()` xml example w3schools.com#6", () =>
837
- expect(
838
- parse(`
839
- <breakfast_menu>
840
- <food>
841
- <name>Belgian Waffles</name>
842
- <price>$5.95</price>
843
- <description>
844
- Two of our famous Belgian Waffles with plenty of real maple syrup
845
- </description>
846
- <calories>650</calories>
847
- </food>
848
- <food>
849
- <name>Strawberry Belgian Waffles</name>
850
- <price>$7.95</price>
851
- <description>
852
- Light Belgian waffles covered with strawberries and whipped cream
853
- </description>
854
- <calories>900</calories>
855
- </food>
856
- <food>
857
- <name>Berry-Berry Belgian Waffles</name>
858
- <price>$8.95</price>
859
- <description>
860
- Belgian waffles covered with assorted fresh berries and whipped cream
861
- </description>
862
- <calories>900</calories>
863
- </food>
864
- <food>
865
- <name>French Toast</name>
866
- <price>$4.50</price>
867
- <description>
868
- Thick slices made from our homemade sourdough bread
869
- </description>
870
- <calories>600</calories>
871
- </food>
872
- <food>
873
- <name>Homestyle Breakfast</name>
874
- <price>$6.95</price>
875
- <description>
876
- Two eggs, bacon or sausage, toast, and our ever-popular hash browns
877
- </description>
878
- <calories>950</calories>
879
- </food>
880
- </breakfast_menu>
881
- `),
882
- ).toEqual(
883
- {
884
- breakfast_menu: {
885
- food: [
886
- {
887
- name: "Belgian Waffles",
888
- price: "$5.95",
889
- description: "Two of our famous Belgian Waffles with plenty of real maple syrup",
890
- calories: "650",
891
- },
892
- {
893
- name: "Strawberry Belgian Waffles",
894
- price: "$7.95",
895
- description: "Light Belgian waffles covered with strawberries and whipped cream",
896
- calories: "900",
897
- },
898
- {
899
- name: "Berry-Berry Belgian Waffles",
900
- price: "$8.95",
901
- description: "Belgian waffles covered with assorted fresh berries and whipped cream",
902
- calories: "900",
903
- },
904
- {
905
- name: "French Toast",
906
- price: "$4.50",
907
- description: "Thick slices made from our homemade sourdough bread",
908
- calories: "600",
909
- },
910
- {
911
- name: "Homestyle Breakfast",
912
- price: "$6.95",
913
- description: "Two eggs, bacon or sausage, toast, and our ever-popular hash browns",
914
- calories: "950",
915
- },
916
- ],
917
- },
918
- },
919
- ))
920
-
921
- // Parser options
922
-
923
- test("all")("`parse()` xml parser option no flatten text", () =>
924
- expect(
925
- parse(
926
- `
927
- <root>
928
- <child>
929
- <grand-child>family</grand-child>
930
- </child>
931
- </root>
932
- `,
933
- { flatten: { text: false } },
934
- ),
935
- ).toEqual(
936
- {
937
- root: {
938
- child: {
939
- "grand-child": {
940
- "#text": "family",
941
- },
942
- },
943
- },
944
- },
945
- ))
946
-
947
- test("all")("`parse()` xml parser option revive", () =>
948
- expect(
949
- parse(
950
- `
951
- <?xml version="1.0"?>
952
- <root>
953
- <empty></empty>
954
- <number>1</number>
955
- <number_negative>-1</number_negative>
956
- <number_hex>0xAC</number_hex>
957
- <number_octal>0o667</number_octal>
958
- <boolean>true</boolean>
959
- </root>
960
- `,
961
- { revive: { booleans: true, numbers: true } },
962
- ),
963
- ).toEqual(
964
- {
965
- "@version": "1.0",
966
- root: {
967
- empty: null,
968
- number: 1,
969
- number_negative: -1,
970
- number_hex: 0xac,
971
- number_octal: 0o667,
972
- boolean: true,
973
- },
974
- },
975
- ))
976
-
977
- test("all")("`parse()` xml parser option no-revive", () =>
978
- expect(
979
- parse(
980
- `
981
- <?xml version="1.0"?>
982
- <root>
983
- <empty></empty>
984
- <number>1</number>
985
- <number_negative>-1</number_negative>
986
- <number_hex>0xac</number_hex>
987
- <number_octal>0o667</number_octal>
988
- <boolean>true</boolean>
989
- </root>
990
- `,
991
- { flatten: { empty: false }, revive: { booleans: false, numbers: false } },
992
- ),
993
- ).toEqual(
994
- {
995
- "@version": "1.0",
996
- root: {
997
- empty: "",
998
- number: "1",
999
- number_negative: "-1",
1000
- number_hex: "0xac",
1001
- number_octal: "0o667",
1002
- boolean: "true",
1003
- },
1004
- },
1005
- ))
1006
-
1007
- test("all")("`parse()` xml parser reviver", () =>
1008
- expect(
1009
- parse(
1010
- `
1011
- <root>
1012
- <not>true</not>
1013
- <attribute delete="true"/>
1014
- <delete/>
1015
- </root>
1016
- `,
1017
- {
1018
- revive: {
1019
- custom({ name, key, value }) {
1020
- if (name === "not") {
1021
- return !value
1022
- }
1023
- if (name === "delete") {
1024
- return undefined
1025
- }
1026
- if ((name === "attribute") && (key === "@delete")) {
1027
- return undefined
1028
- }
1029
- return value
1030
- },
1031
- },
1032
- },
1033
- ),
1034
- ).toEqual(
1035
- {
1036
- root: {
1037
- not: false,
1038
- attribute: null,
1039
- },
1040
- },
1041
- ))
1042
-
1043
- test("all")("`parse()` xml parser option clean", () =>
1044
- expect(
1045
- parse(
1046
- `
1047
- <?xml version="1.0" encoding="UTF-8"?>
1048
- <?xml-stylesheet href="styles.xsl" type="text/xsl"?>
1049
- <!DOCTYPE type "quoted attribute">
1050
- <root>
1051
- <a attr="test">foo</a>
1052
- </root>
1053
- `,
1054
- { clean: { attributes: true, comments: true, doctype: true, instructions: true } },
1055
- ),
1056
- ).toEqual(
1057
- {
1058
- root: {
1059
- a: "foo",
1060
- },
1061
- },
1062
- ))
1063
-
1064
- test("all")("`parse()` xml parser option clean (no matching elements)", () =>
1065
- expect(
1066
- parse(
1067
- `
1068
- <?xml version="1.0" encoding="UTF-8"?>
1069
- <root>
1070
- <a attr="test">foo</a>
1071
- </root>
1072
- `,
1073
- { clean: { attributes: true, comments: true, doctype: true, instructions: true } },
1074
- ),
1075
- ).toEqual(
1076
- {
1077
- root: {
1078
- a: "foo",
1079
- },
1080
- },
1081
- ))
1082
-
1083
- test("all")("`parse()` xml parser option no clean", () =>
1084
- expect(
1085
- parse(
1086
- `
1087
- <?xml version="1.0" encoding="UTF-8"?>
1088
- <?xml-stylesheet href="styles.xsl" type="text/xsl"?>
1089
- <!DOCTYPE type "quoted attribute">
1090
- <root>
1091
- <a attr="test">foo</a>
1092
- </root>
1093
- `,
1094
- { clean: { attributes: false, comments: false, doctype: false, instructions: false } },
1095
- ),
1096
- ).toEqual(
1097
- {
1098
- "@version": "1.0",
1099
- "@encoding": "UTF-8",
1100
- "#instructions": {
1101
- "xml-stylesheet": {
1102
- "@href": "styles.xsl",
1103
- "@type": "text/xsl",
1104
- },
1105
- },
1106
- "#doctype": {
1107
- "@type": "",
1108
- "@quoted attribute": "",
1109
- },
1110
- root: {
1111
- a: {
1112
- "@attr": "test",
1113
- "#text": "foo",
1114
- },
1115
- },
1116
- },
1117
- ))
1118
-
1119
- test("all")("`parse()` xml parser option flatten", () =>
1120
- expect(
1121
- parse(
1122
- `
1123
- <root>
1124
- <attributes foo="1" bar="2"></attributes>
1125
- <text>foo</text>
1126
- <empty></empty>
1127
- </root>
1128
- `,
1129
- { flatten: { attributes: true, text: true, empty: true } },
1130
- ),
1131
- ).toEqual(
1132
- {
1133
- root: {
1134
- attributes: { foo: "1", bar: "2" },
1135
- text: "foo",
1136
- empty: null,
1137
- },
1138
- },
1139
- ))
1140
-
1141
- test("all")("`parse()` xml parser option no flatten", () =>
1142
- expect(
1143
- parse(
1144
- `
1145
- <root>
1146
- <attributes foo="1" bar="2"></attributes>
1147
- <text>foo</text>
1148
- <empty></empty>
1149
- </root>
1150
- `,
1151
- { flatten: { attributes: false, text: false, empty: false } },
1152
- ),
1153
- ).toEqual(
1154
- {
1155
- root: {
1156
- attributes: { "@foo": "1", "@bar": "2" },
1157
- text: { "#text": "foo" },
1158
- empty: { "#text": "" },
1159
- },
1160
- },
1161
- ))
1162
-
1163
- test("all")("`parse()` xml parser option revive", () =>
1164
- expect(
1165
- parse(
1166
- `
1167
- <root>
1168
- <trim> hello </trim>
1169
- <preserve xml:space="preserve"> world </preserve>
1170
- <entities>&lt; &gt; &amp; &apos; &quot;</entities>
1171
- <boolean>true</boolean>
1172
- <boolean>false</boolean>
1173
- <integer>1</integer>
1174
- <float>3.14</float>
1175
- </root>
1176
- `,
1177
- { revive: { trim: true, entities: true, booleans: true, numbers: true } },
1178
- ),
1179
- ).toEqual(
1180
- {
1181
- root: {
1182
- trim: "hello",
1183
- preserve: { "@xml:space": "preserve", "#text": " world " },
1184
- entities: `< > & ' "`,
1185
- boolean: [true, false],
1186
- integer: 1,
1187
- float: 3.14,
1188
- },
1189
- },
1190
- ))
1191
-
1192
- test("all")("`parse()` xml parser option no revive", () =>
1193
- expect(
1194
- parse(
1195
- `
1196
- <root>
1197
- <trim> hello </trim>
1198
- <preserve xml:space="preserve"> world </preserve>
1199
- <entities>&lt; &gt; &amp; &apos; &quot;</entities>
1200
- <boolean>true</boolean>
1201
- <boolean>false</boolean>
1202
- <integer>1</integer>
1203
- <float>3.14</float>
1204
- </root>
1205
- `,
1206
- { revive: { trim: false, entities: false, booleans: false, numbers: false } },
1207
- ),
1208
- ).toEqual(
1209
- {
1210
- root: {
1211
- trim: " hello ",
1212
- preserve: { "@xml:space": "preserve", "#text": " world " },
1213
- entities: `&lt; &gt; &amp; &apos; &quot;`,
1214
- boolean: ["true", "false"],
1215
- integer: "1",
1216
- float: "3.14",
1217
- },
1218
- },
1219
- ))
1220
-
1221
- test("all")("`parse()` xml parser option mode 'xml'", () =>
1222
- expect(() =>
1223
- parse(
1224
- `
1225
- <root foo=bar></root>
1226
- `,
1227
- { mode: "xml" },
1228
- )
1229
- ).toThrow(SyntaxError))
1230
-
1231
- test("all")("`parse()` xml parser option mode 'html'", () =>
1232
- expect(
1233
- parse(
1234
- `
1235
- <root foo=bar></root>
1236
- `,
1237
- { mode: "html" },
1238
- ),
1239
- ).toEqual({
1240
- root: {
1241
- "@foo": "bar",
1242
- },
1243
- }))
1244
-
1245
- // Metadata
1246
-
1247
- test("all")("`parse()` xml parser option metadata", () => {
1248
- const xml = parse(
1249
- `
1250
- <root>
1251
- <child>
1252
- <grand-child></grand-child>
1253
- </child>
1254
- <sibling>A</sibling>
1255
- <sibling>B</sibling>
1256
- <sibling>C</sibling>
1257
- <sibling>D</sibling>
1258
- </root>
1259
- `,
1260
- { flatten: { text: false, empty: false } },
1261
- ) as testing
1262
-
1263
- expect(xml.root?.child?.["grand-child"]?.["~parent"]).toEqual(xml.root.child)
1264
- expect(xml.root?.child?.["grand-child"]?.["~name"]).toBe("grand-child")
1265
- expect(xml.root?.child?.["~parent"]).toEqual(xml.root)
1266
- expect(xml.root?.child?.["~name"]).toBe("child")
1267
- expect(xml.root?.["~parent"]).toBe(xml)
1268
- expect(xml.root?.["~name"]).toBe("root")
1269
- expect(xml["~parent"]).toBeNull()
1270
- expect(xml.root?.sibling?.["~parent"]).toEqual(xml.root)
1271
- expect(xml.root?.sibling?.["~name"]).toBe("sibling")
1272
- })
1273
-
1274
- // Other inputs
1275
-
1276
- test("deno")("`parse()` using a reader", async () => {
1277
- using file = await Deno.open("bench/assets/small.xml")
1278
- expect(
1279
- parse(file),
1280
- ).toEqual(
1281
- {
1282
- "#comments": [
1283
- "From https://www.w3schools.com/xml/note.xml",
1284
- ],
1285
- note: {
1286
- body: "Don't forget me this weekend!",
1287
- from: "Jani",
1288
- heading: "Reminder",
1289
- to: "Tove",
1290
- },
1291
- },
1292
- )
1293
- }, { permissions: { read: ["bench"] } })
1294
-
1295
- // Size tests
1296
-
1297
- for (let i = 0; i <= 5; i++) {
1298
- const ignore = false && (i > 2) && (!Deno.env.get("CI"))
1299
- test("all")(`\`parse()\` parse large files ~${(2 ** i)}Mb`, async () => {
1300
- await write(i)
1301
- expect(parse(await Deno.readTextFile(`bench/assets/x-${i}x-large.xml`))).not.toThrow()
1302
- }, { permissions: { read: ["bench"], write: ["bench"] }, ignore } as testing)
1303
- }