bbcode-compiler 0.1.9 → 0.1.11
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/dist/index.d.ts +1 -16
- package/dist/index.js +866 -1038
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +914 -1063
- package/dist/index.umd.cjs.map +1 -1
- package/dist/src/generateHtml.d.ts +2 -0
- package/dist/src/generateHtml.d.ts.map +1 -0
- package/dist/{generator → src/generator}/Generator.d.ts +2 -3
- package/dist/src/generator/Generator.d.ts.map +1 -0
- package/dist/{generator → src/generator}/transforms/Transform.d.ts +1 -2
- package/dist/src/generator/transforms/Transform.d.ts.map +1 -0
- package/dist/src/generator/transforms/htmlTransforms.d.ts +3 -0
- package/dist/src/generator/transforms/htmlTransforms.d.ts.map +1 -0
- package/dist/{generator → src/generator}/utils/getTagImmediateAttrVal.d.ts +1 -2
- package/dist/src/generator/utils/getTagImmediateAttrVal.d.ts.map +1 -0
- package/dist/{generator → src/generator}/utils/getTagImmediateText.d.ts +1 -2
- package/dist/src/generator/utils/getTagImmediateText.d.ts.map +1 -0
- package/dist/{generator → src/generator}/utils/getWidthHeightAttr.d.ts +1 -2
- package/dist/src/generator/utils/getWidthHeightAttr.d.ts.map +1 -0
- package/dist/src/generator/utils/isDangerousUrl.d.ts.map +1 -0
- package/dist/{generator → src/generator}/utils/isOrderedList.d.ts +1 -2
- package/dist/src/generator/utils/isOrderedList.d.ts.map +1 -0
- package/dist/src/index.d.ts +16 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/{lexer → src/lexer}/Lexer.d.ts +1 -2
- package/dist/src/lexer/Lexer.d.ts.map +1 -0
- package/dist/{lexer → src/lexer}/Token.d.ts +1 -2
- package/dist/src/lexer/Token.d.ts.map +1 -0
- package/dist/src/lexer/TokenType.d.ts +5 -0
- package/dist/src/lexer/TokenType.d.ts.map +1 -0
- package/dist/{parser → src/parser}/AstNode.d.ts +10 -18
- package/dist/src/parser/AstNode.d.ts.map +1 -0
- package/dist/{parser → src/parser}/Parser.d.ts +3 -4
- package/dist/src/parser/Parser.d.ts.map +1 -0
- package/dist/src/parser/nodeIsType.d.ts +13 -0
- package/dist/src/parser/nodeIsType.d.ts.map +1 -0
- package/package.json +81 -82
- package/src/generateHtml.ts +4 -4
- package/src/generator/Generator.ts +7 -7
- package/src/generator/transforms/Transform.ts +1 -1
- package/src/generator/transforms/htmlTransforms.ts +6 -6
- package/src/generator/utils/getTagImmediateAttrVal.ts +1 -1
- package/src/generator/utils/getTagImmediateText.ts +4 -4
- package/src/generator/utils/getWidthHeightAttr.ts +1 -1
- package/src/generator/utils/isOrderedList.ts +1 -1
- package/src/index.ts +15 -15
- package/src/lexer/Lexer.ts +9 -9
- package/src/lexer/Token.ts +12 -12
- package/src/lexer/TokenType.ts +39 -40
- package/src/parser/AstNode.ts +30 -29
- package/src/parser/Parser.ts +28 -28
- package/src/parser/nodeIsType.ts +8 -8
- package/dist/generateHtml.d.ts +0 -2
- package/dist/generateHtml.d.ts.map +0 -1
- package/dist/generator/Generator.d.ts.map +0 -1
- package/dist/generator/transforms/Transform.d.ts.map +0 -1
- package/dist/generator/transforms/htmlTransforms.d.ts +0 -4
- package/dist/generator/transforms/htmlTransforms.d.ts.map +0 -1
- package/dist/generator/utils/getTagImmediateAttrVal.d.ts.map +0 -1
- package/dist/generator/utils/getTagImmediateText.d.ts.map +0 -1
- package/dist/generator/utils/getWidthHeightAttr.d.ts.map +0 -1
- package/dist/generator/utils/isDangerousUrl.d.ts.map +0 -1
- package/dist/generator/utils/isOrderedList.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/lexer/Lexer.d.ts.map +0 -1
- package/dist/lexer/Token.d.ts.map +0 -1
- package/dist/lexer/TokenType.d.ts +0 -17
- package/dist/lexer/TokenType.d.ts.map +0 -1
- package/dist/parser/AstNode.d.ts.map +0 -1
- package/dist/parser/Parser.d.ts.map +0 -1
- package/dist/parser/nodeIsType.d.ts +0 -14
- package/dist/parser/nodeIsType.d.ts.map +0 -1
- /package/dist/{generator → src/generator}/utils/isDangerousUrl.d.ts +0 -0
package/dist/index.umd.cjs
CHANGED
|
@@ -1,1065 +1,916 @@
|
|
|
1
1
|
(function(global, factory) {
|
|
2
|
-
|
|
3
|
-
})(this, function(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
break;
|
|
915
|
-
}
|
|
916
|
-
attrNodes.push(attrNode);
|
|
917
|
-
}
|
|
918
|
-
if (tokens[idx].type !== TokenType.R_BRACKET) {
|
|
919
|
-
return null;
|
|
920
|
-
}
|
|
921
|
-
idx += 1;
|
|
922
|
-
const slice = tokens.slice(startIdx, idx);
|
|
923
|
-
const ogTag = stringifyTokens(ogText, slice);
|
|
924
|
-
const startTagNode = new StartTagNode(labelText, ogTag, attrNodes);
|
|
925
|
-
return startTagNode;
|
|
926
|
-
}
|
|
927
|
-
if (tokens[idx + 1].type === TokenType.BACKSLASH) {
|
|
928
|
-
const startIdx = idx;
|
|
929
|
-
idx += 1;
|
|
930
|
-
idx += 1;
|
|
931
|
-
const labelText = parseLabel();
|
|
932
|
-
if (!this.tags.has(labelText)) {
|
|
933
|
-
return null;
|
|
934
|
-
}
|
|
935
|
-
if (tokens[idx].type !== TokenType.R_BRACKET) {
|
|
936
|
-
return null;
|
|
937
|
-
}
|
|
938
|
-
idx += 1;
|
|
939
|
-
const slice = tokens.slice(startIdx, idx);
|
|
940
|
-
const ogTag = stringifyTokens(ogText, slice);
|
|
941
|
-
const endTagNode = new EndTagNode(labelText, ogTag);
|
|
942
|
-
return endTagNode;
|
|
943
|
-
}
|
|
944
|
-
return null;
|
|
945
|
-
};
|
|
946
|
-
const parseRoot = () => {
|
|
947
|
-
const root2 = new RootNode();
|
|
948
|
-
while (idx < tokens.length) {
|
|
949
|
-
if (tokens[idx].type === TokenType.L_BRACKET) {
|
|
950
|
-
const startIdx = idx;
|
|
951
|
-
const tagNode = parseTag();
|
|
952
|
-
if (tagNode !== null) {
|
|
953
|
-
root2.addChild(tagNode);
|
|
954
|
-
} else {
|
|
955
|
-
const invalidTokens = tokens.slice(startIdx, idx);
|
|
956
|
-
const str = stringifyTokens(ogText, invalidTokens);
|
|
957
|
-
const textNode = new TextNode(str);
|
|
958
|
-
root2.addChild(textNode);
|
|
959
|
-
}
|
|
960
|
-
} else if (tokens[idx].type === TokenType.LINEBREAK) {
|
|
961
|
-
idx += 1;
|
|
962
|
-
root2.addChild(new LinebreakNode());
|
|
963
|
-
} else {
|
|
964
|
-
const startIdx = idx;
|
|
965
|
-
while (idx < tokens.length && tokens[idx].type !== TokenType.L_BRACKET && tokens[idx].type !== TokenType.LINEBREAK) {
|
|
966
|
-
idx += 1;
|
|
967
|
-
}
|
|
968
|
-
const slice = tokens.slice(startIdx, idx);
|
|
969
|
-
const str = stringifyTokens(ogText, slice);
|
|
970
|
-
root2.addChild(new TextNode(str));
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
return root2;
|
|
974
|
-
};
|
|
975
|
-
let root = parseRoot();
|
|
976
|
-
root = this.matchTagNodes(root);
|
|
977
|
-
return root;
|
|
978
|
-
}
|
|
979
|
-
// ------------------------------------------------------------------------
|
|
980
|
-
// Post Parsing Transforms
|
|
981
|
-
// ------------------------------------------------------------------------
|
|
982
|
-
matchTagNodes(rootNode) {
|
|
983
|
-
const transformedRoot = new RootNode();
|
|
984
|
-
for (let i = 0; i < rootNode.children.length; i++) {
|
|
985
|
-
const child = rootNode.children[i];
|
|
986
|
-
if (nodeIsType(child, AstNodeType.StartTagNode)) {
|
|
987
|
-
const endTag = this.findMatchingEndTag(rootNode.children, i, child.tagName);
|
|
988
|
-
const isStandalone = this.standaloneTags.has(child.tagName);
|
|
989
|
-
if (endTag || isStandalone) {
|
|
990
|
-
const tagNode = new TagNode(child, endTag == null ? void 0 : endTag.node);
|
|
991
|
-
transformedRoot.addChild(tagNode);
|
|
992
|
-
if (endTag) {
|
|
993
|
-
const subRoot = new RootNode(rootNode.children.slice(i + 1, endTag.idx));
|
|
994
|
-
i = endTag.idx;
|
|
995
|
-
const transformedSubRoot = this.matchTagNodes(subRoot);
|
|
996
|
-
tagNode.addChild(transformedSubRoot);
|
|
997
|
-
}
|
|
998
|
-
} else {
|
|
999
|
-
transformedRoot.addChild(new TextNode(child.ogTag));
|
|
1000
|
-
}
|
|
1001
|
-
} else if (nodeIsType(child, AstNodeType.EndTagNode)) {
|
|
1002
|
-
transformedRoot.addChild(new TextNode(child.ogTag));
|
|
1003
|
-
} else if (nodeIsType(child, AstNodeType.TextNode)) {
|
|
1004
|
-
transformedRoot.addChild(child);
|
|
1005
|
-
} else if (nodeIsType(child, AstNodeType.LinebreakNode)) {
|
|
1006
|
-
transformedRoot.addChild(child);
|
|
1007
|
-
} else {
|
|
1008
|
-
throw new Error("Unexpected child of RootNode");
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
return transformedRoot;
|
|
1012
|
-
}
|
|
1013
|
-
findMatchingEndTag(siblings, startIdx, tagName) {
|
|
1014
|
-
if (this.standaloneTags.has(tagName)) {
|
|
1015
|
-
return null;
|
|
1016
|
-
}
|
|
1017
|
-
for (let i = startIdx; i < siblings.length; i++) {
|
|
1018
|
-
const sibling = siblings[i];
|
|
1019
|
-
const isEndTag = nodeIsType(sibling, AstNodeType.LinebreakNode) && this.linebreakTerminatedTags.has(tagName) || nodeIsType(sibling, AstNodeType.EndTagNode) && sibling.tagName === tagName;
|
|
1020
|
-
if (isEndTag) {
|
|
1021
|
-
return {
|
|
1022
|
-
idx: i,
|
|
1023
|
-
node: sibling
|
|
1024
|
-
};
|
|
1025
|
-
}
|
|
1026
|
-
}
|
|
1027
|
-
return null;
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
function generateHtml(input, transforms = htmlTransforms) {
|
|
1031
|
-
const lexer = new Lexer();
|
|
1032
|
-
const tokens = lexer.tokenize(input);
|
|
1033
|
-
const parser = new Parser(transforms);
|
|
1034
|
-
const root = parser.parse(input, tokens);
|
|
1035
|
-
const generator = new Generator(transforms);
|
|
1036
|
-
return generator.generate(root);
|
|
1037
|
-
}
|
|
1038
|
-
exports2.AstNode = AstNode;
|
|
1039
|
-
exports2.AstNodeType = AstNodeType;
|
|
1040
|
-
exports2.AttrNode = AttrNode;
|
|
1041
|
-
exports2.EndTagNode = EndTagNode;
|
|
1042
|
-
exports2.Generator = Generator;
|
|
1043
|
-
exports2.Lexer = Lexer;
|
|
1044
|
-
exports2.LinebreakNode = LinebreakNode;
|
|
1045
|
-
exports2.Parser = Parser;
|
|
1046
|
-
exports2.RootNode = RootNode;
|
|
1047
|
-
exports2.StartTagNode = StartTagNode;
|
|
1048
|
-
exports2.TagNode = TagNode;
|
|
1049
|
-
exports2.TextNode = TextNode;
|
|
1050
|
-
exports2.TokenType = TokenType;
|
|
1051
|
-
exports2.generateHtml = generateHtml;
|
|
1052
|
-
exports2.getTagImmediateAttrVal = getTagImmediateAttrVal;
|
|
1053
|
-
exports2.getTagImmediateText = getTagImmediateText;
|
|
1054
|
-
exports2.getWidthHeightAttr = getWidthHeightAttr;
|
|
1055
|
-
exports2.htmlTransforms = htmlTransforms;
|
|
1056
|
-
exports2.isDangerousUrl = isDangerousUrl;
|
|
1057
|
-
exports2.isOrderedList = isOrderedList;
|
|
1058
|
-
exports2.isStringToken = isStringToken;
|
|
1059
|
-
exports2.nodeIsType = nodeIsType;
|
|
1060
|
-
exports2.stringifyTokens = stringifyTokens;
|
|
1061
|
-
exports2.symbolTable = symbolTable;
|
|
1062
|
-
exports2.tokenTypeToString = tokenTypeToString;
|
|
1063
|
-
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.BbcodeCompiler = {}));
|
|
3
|
+
})(this, function(exports) {
|
|
4
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
5
|
+
//#region src/parser/nodeIsType.ts
|
|
6
|
+
function nodeIsType(node, nodeType) {
|
|
7
|
+
return node.nodeType === nodeType;
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/parser/AstNode.ts
|
|
11
|
+
/**
|
|
12
|
+
|
|
13
|
+
Haven't formally verified this grammar but it should be LL(2)
|
|
14
|
+
|
|
15
|
+
The root's intermediate state has StartTag/EndTag because it's easier to first parse them as independant nodes
|
|
16
|
+
than to parse a StartTag and find the matching EndTag since we can only lookahead by 1 token
|
|
17
|
+
|
|
18
|
+
Trying to lookahead by 4 tokens after each advancement to determine the end of the sub-root will greatly affect performance
|
|
19
|
+
1 "["
|
|
20
|
+
2 "/"
|
|
21
|
+
3 "LABEL"
|
|
22
|
+
4 "]"
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
Root <- (Text | Linebreak | Tag)*
|
|
27
|
+
|
|
28
|
+
Text <-
|
|
29
|
+
| {XSS Characters}.
|
|
30
|
+
| STR.
|
|
31
|
+
|
|
32
|
+
Linebreak <-
|
|
33
|
+
| LINEBREAK.
|
|
34
|
+
|
|
35
|
+
Tag <- StartTag Root EndTag
|
|
36
|
+
StartTag <- L_BRACKET Text Attr* R_BRACKET
|
|
37
|
+
EndTag <- L_BRACKET BACKSLASH Text R_BRACKET
|
|
38
|
+
|
|
39
|
+
Attr <-
|
|
40
|
+
| STR EQUALS STR
|
|
41
|
+
| EQUALS STR
|
|
42
|
+
| STR
|
|
43
|
+
|
|
44
|
+
*/
|
|
45
|
+
var AstNode = class {
|
|
46
|
+
children;
|
|
47
|
+
constructor(children = new Array()) {
|
|
48
|
+
this.children = children;
|
|
49
|
+
}
|
|
50
|
+
addChild(node) {
|
|
51
|
+
this.children.push(node);
|
|
52
|
+
}
|
|
53
|
+
isValid() {
|
|
54
|
+
for (const child of this.children) if (!child.isValid()) return false;
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
toShortString() {
|
|
58
|
+
return this.nodeType;
|
|
59
|
+
}
|
|
60
|
+
toString(depth = 0) {
|
|
61
|
+
let s = " ".repeat(depth * 2) + this.toShortString();
|
|
62
|
+
for (const child of this.children) s += "\n" + child.toString(depth + 1);
|
|
63
|
+
return s;
|
|
64
|
+
}
|
|
65
|
+
toJSON() {
|
|
66
|
+
const json = { type: this.nodeType };
|
|
67
|
+
if (this.children.length > 0) json.children = this.children.map((child) => child.toJSON());
|
|
68
|
+
return json;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var RootNode = class extends AstNode {
|
|
72
|
+
nodeType = "RootNode";
|
|
73
|
+
isValid() {
|
|
74
|
+
for (const child of this.children) if (child.nodeType !== "TagNode" && child.nodeType !== "TextNode" && child.nodeType !== "LinebreakNode") return false;
|
|
75
|
+
return super.isValid() && this.children.length > 0;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var TextNode = class extends AstNode {
|
|
79
|
+
nodeType = "TextNode";
|
|
80
|
+
str;
|
|
81
|
+
constructor(str) {
|
|
82
|
+
super();
|
|
83
|
+
this.str = str;
|
|
84
|
+
}
|
|
85
|
+
isValid() {
|
|
86
|
+
return super.isValid() && this.children.length === 0;
|
|
87
|
+
}
|
|
88
|
+
toShortString() {
|
|
89
|
+
return `${super.toShortString()} "${this.str}"`;
|
|
90
|
+
}
|
|
91
|
+
toJSON() {
|
|
92
|
+
const json = super.toJSON();
|
|
93
|
+
json.data = { str: this.str };
|
|
94
|
+
return json;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
var LinebreakNode = class extends AstNode {
|
|
98
|
+
nodeType = "LinebreakNode";
|
|
99
|
+
toShortString() {
|
|
100
|
+
return `${super.toShortString()} "\\n"`;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
var AttrNode = class AttrNode extends AstNode {
|
|
104
|
+
nodeType = "AttrNode";
|
|
105
|
+
static DEFAULT_KEY = "default";
|
|
106
|
+
get key() {
|
|
107
|
+
switch (this.children.length) {
|
|
108
|
+
case 1: return AttrNode.DEFAULT_KEY;
|
|
109
|
+
case 2:
|
|
110
|
+
if (!nodeIsType(this.children[0], "TextNode")) throw new Error("Invalid TextNode");
|
|
111
|
+
return this.children[0].str.trim();
|
|
112
|
+
}
|
|
113
|
+
throw new Error("Invalid AttrNode");
|
|
114
|
+
}
|
|
115
|
+
get val() {
|
|
116
|
+
switch (this.children.length) {
|
|
117
|
+
case 1:
|
|
118
|
+
if (!nodeIsType(this.children[0], "TextNode")) throw new Error("Invalid TextNode");
|
|
119
|
+
return this.children[0].str.trim();
|
|
120
|
+
case 2:
|
|
121
|
+
if (!nodeIsType(this.children[1], "TextNode")) throw new Error("Invalid TextNode");
|
|
122
|
+
return this.children[1].str.trim();
|
|
123
|
+
}
|
|
124
|
+
throw new Error("Invalid AttrNode");
|
|
125
|
+
}
|
|
126
|
+
isValid() {
|
|
127
|
+
return super.isValid() && this.children.length >= 1 && this.children.length <= 2;
|
|
128
|
+
}
|
|
129
|
+
toShortString() {
|
|
130
|
+
let s = super.toShortString();
|
|
131
|
+
switch (this.children.length) {
|
|
132
|
+
case 1:
|
|
133
|
+
s += ` VAL="${this.val}"`;
|
|
134
|
+
break;
|
|
135
|
+
case 2:
|
|
136
|
+
s += ` KEY="${this.key}" VAL="${this.val}"`;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
return s;
|
|
140
|
+
}
|
|
141
|
+
toJSON() {
|
|
142
|
+
const json = { type: this.nodeType };
|
|
143
|
+
switch (this.children.length) {
|
|
144
|
+
case 1:
|
|
145
|
+
json.data = { key: this.key };
|
|
146
|
+
break;
|
|
147
|
+
case 2:
|
|
148
|
+
json.data = {
|
|
149
|
+
key: this.key,
|
|
150
|
+
val: this.val
|
|
151
|
+
};
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
return json;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
var StartTagNode = class extends AstNode {
|
|
158
|
+
nodeType = "StartTagNode";
|
|
159
|
+
tagName;
|
|
160
|
+
ogTag;
|
|
161
|
+
constructor(tagName, ogTag, attrNodes = []) {
|
|
162
|
+
super(attrNodes);
|
|
163
|
+
this.tagName = tagName.toLowerCase();
|
|
164
|
+
this.ogTag = ogTag;
|
|
165
|
+
}
|
|
166
|
+
isValid() {
|
|
167
|
+
for (const child of this.children) if (child.nodeType !== "AttrNode") return false;
|
|
168
|
+
return super.isValid();
|
|
169
|
+
}
|
|
170
|
+
toShortString() {
|
|
171
|
+
return `${super.toShortString()} ${this.ogTag}`;
|
|
172
|
+
}
|
|
173
|
+
toJSON() {
|
|
174
|
+
const json = super.toJSON();
|
|
175
|
+
json.data = { tag: this.tagName };
|
|
176
|
+
return json;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
var EndTagNode = class extends AstNode {
|
|
180
|
+
nodeType = "EndTagNode";
|
|
181
|
+
tagName;
|
|
182
|
+
ogTag;
|
|
183
|
+
constructor(tagName, ogTag) {
|
|
184
|
+
super();
|
|
185
|
+
this.tagName = tagName;
|
|
186
|
+
this.ogTag = ogTag;
|
|
187
|
+
}
|
|
188
|
+
isValid() {
|
|
189
|
+
return super.isValid() && this.children.length === 0;
|
|
190
|
+
}
|
|
191
|
+
toShortString() {
|
|
192
|
+
return `${super.toShortString()} ${this.ogTag}`;
|
|
193
|
+
}
|
|
194
|
+
toJSON() {
|
|
195
|
+
const json = super.toJSON();
|
|
196
|
+
json.data = { tag: this.tagName };
|
|
197
|
+
return json;
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
var TagNode = class extends AstNode {
|
|
201
|
+
nodeType = "TagNode";
|
|
202
|
+
_startTag;
|
|
203
|
+
_endTag;
|
|
204
|
+
constructor(startTag, endTag) {
|
|
205
|
+
super();
|
|
206
|
+
this._startTag = startTag;
|
|
207
|
+
this._endTag = endTag;
|
|
208
|
+
}
|
|
209
|
+
get tagName() {
|
|
210
|
+
return this._startTag.tagName;
|
|
211
|
+
}
|
|
212
|
+
get attributes() {
|
|
213
|
+
return this._startTag.children;
|
|
214
|
+
}
|
|
215
|
+
get ogStartTag() {
|
|
216
|
+
return this._startTag.ogTag;
|
|
217
|
+
}
|
|
218
|
+
get ogEndTag() {
|
|
219
|
+
if (!this._endTag) return "";
|
|
220
|
+
if (nodeIsType(this._endTag, "LinebreakNode")) return "\n";
|
|
221
|
+
else return this._endTag.ogTag;
|
|
222
|
+
}
|
|
223
|
+
isValid() {
|
|
224
|
+
if (this._endTag && nodeIsType(this._endTag, "EndTagNode") && this._startTag.tagName !== this._endTag.tagName) return false;
|
|
225
|
+
if (this.children.length === 1 && this.children[0].nodeType !== "RootNode") return false;
|
|
226
|
+
if (this.children.length > 2) return false;
|
|
227
|
+
return super.isValid() && this._startTag.isValid() && (this._endTag?.isValid() ?? true);
|
|
228
|
+
}
|
|
229
|
+
toString(depth = 0) {
|
|
230
|
+
let s = " ".repeat(depth * 2) + this.toShortString() + ` [${this.tagName}]`;
|
|
231
|
+
for (const attrNode of this._startTag.children) s += "\n" + attrNode.toString(depth + 1);
|
|
232
|
+
for (const child of this.children) s += "\n" + child.toString(depth + 1);
|
|
233
|
+
return s;
|
|
234
|
+
}
|
|
235
|
+
toJSON() {
|
|
236
|
+
const json = super.toJSON();
|
|
237
|
+
json.data = { startTag: this._startTag.toJSON() };
|
|
238
|
+
if (this._endTag) json.data.endTag = this._endTag.toJSON();
|
|
239
|
+
return json;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
//#endregion
|
|
243
|
+
//#region src/generator/utils/getTagImmediateAttrVal.ts
|
|
244
|
+
/**
|
|
245
|
+
* Gets the text of the immediate attribute of the current TagNode
|
|
246
|
+
*
|
|
247
|
+
* [url=https://en.wikipedia.org]English Wikipedia[/url]
|
|
248
|
+
*
|
|
249
|
+
* TagNode [url]
|
|
250
|
+
* AttrNode VAL="https://en.wikipedia.org" (returns this string)
|
|
251
|
+
* TextNode "https://en.wikipedia.org"
|
|
252
|
+
* RootNode
|
|
253
|
+
* TextNode "English Wikipedia"
|
|
254
|
+
*/
|
|
255
|
+
function getTagImmediateAttrVal(tagNode) {
|
|
256
|
+
if (tagNode.attributes.length !== 1) return;
|
|
257
|
+
return tagNode.attributes[0].val;
|
|
258
|
+
}
|
|
259
|
+
//#endregion
|
|
260
|
+
//#region src/generator/utils/getTagImmediateText.ts
|
|
261
|
+
/**
|
|
262
|
+
* Gets the text of the immediate descendant of the current TagNode
|
|
263
|
+
*
|
|
264
|
+
* [url]https://en.wikipedia.org[/url]
|
|
265
|
+
*
|
|
266
|
+
* TagNode [url]
|
|
267
|
+
* RootNode
|
|
268
|
+
* TextNode "https://en.wikipedia.org" (returns this string)
|
|
269
|
+
*/
|
|
270
|
+
function getTagImmediateText(tagNode) {
|
|
271
|
+
if (tagNode.children.length !== 1) return;
|
|
272
|
+
const child = tagNode.children[0];
|
|
273
|
+
if (!nodeIsType(child, "RootNode")) return;
|
|
274
|
+
if (child.children.length !== 1) return;
|
|
275
|
+
const textNode = child.children[0];
|
|
276
|
+
if (!nodeIsType(textNode, "TextNode")) return;
|
|
277
|
+
return textNode.str;
|
|
278
|
+
}
|
|
279
|
+
//#endregion
|
|
280
|
+
//#region src/generator/utils/getWidthHeightAttr.ts
|
|
281
|
+
/**
|
|
282
|
+
* Gets the width/height attributes of the TagNode if they exist
|
|
283
|
+
*
|
|
284
|
+
* [img 500x300]https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png[/img]
|
|
285
|
+
*
|
|
286
|
+
* RootNode
|
|
287
|
+
* TagNode [img] (returns width:500, height:300)
|
|
288
|
+
* AttrNode VAL="500x300"
|
|
289
|
+
* TextNode " 500x300"
|
|
290
|
+
* RootNode
|
|
291
|
+
* TextNode "https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png"
|
|
292
|
+
*
|
|
293
|
+
* [img width=500 height=300]https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png[/img]
|
|
294
|
+
*
|
|
295
|
+
* RootNode
|
|
296
|
+
* TagNode [img] (returns width:500, height:300)
|
|
297
|
+
* AttrNode KEY="width" VAL="500"
|
|
298
|
+
* TextNode " width"
|
|
299
|
+
* TextNode "500"
|
|
300
|
+
* AttrNode KEY="height" VAL="300"
|
|
301
|
+
* TextNode " height"
|
|
302
|
+
* TextNode "300"
|
|
303
|
+
* RootNode
|
|
304
|
+
* TextNode "https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png
|
|
305
|
+
*/
|
|
306
|
+
function getWidthHeightAttr(tagNode) {
|
|
307
|
+
let width;
|
|
308
|
+
let height;
|
|
309
|
+
for (const child of tagNode.attributes) {
|
|
310
|
+
if (child.key === "width") width = child.val;
|
|
311
|
+
if (child.key === "height") height = child.val;
|
|
312
|
+
const matches = /(\d+)x(\d+)/.exec(child.val);
|
|
313
|
+
if (matches) {
|
|
314
|
+
width = matches[1];
|
|
315
|
+
height = matches[2];
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return {
|
|
319
|
+
width,
|
|
320
|
+
height
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
//#endregion
|
|
324
|
+
//#region src/generator/utils/isDangerousUrl.ts
|
|
325
|
+
var dangerousUriRe = /^(vbscript|javascript|file|data):/;
|
|
326
|
+
var safeDataUriRe = /^data:image\/(gif|png|jpeg|webp);/;
|
|
327
|
+
function isDangerousUrl(url) {
|
|
328
|
+
const normalizedUrl = url.trim().toLowerCase();
|
|
329
|
+
if (!dangerousUriRe.test(normalizedUrl)) return false;
|
|
330
|
+
if (safeDataUriRe.test(normalizedUrl)) return false;
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
//#endregion
|
|
334
|
+
//#region src/generator/utils/isOrderedList.ts
|
|
335
|
+
/**
|
|
336
|
+
* Determines if the StartTag has an attribute of "1" to indicate that it's an ordered list
|
|
337
|
+
*
|
|
338
|
+
* [list=1]
|
|
339
|
+
*
|
|
340
|
+
* TagNode [list]
|
|
341
|
+
* AttrNode VAL="1"
|
|
342
|
+
* TextNode "1"
|
|
343
|
+
* RootNode
|
|
344
|
+
* TagNode [*]
|
|
345
|
+
* RootNode
|
|
346
|
+
* TextNode "Entry 1"
|
|
347
|
+
* TagNode [*]
|
|
348
|
+
* RootNode
|
|
349
|
+
* TextNode "Entry 2"
|
|
350
|
+
*/
|
|
351
|
+
function isOrderedList(node) {
|
|
352
|
+
for (const child of node.attributes) if (child.val === "1") return true;
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
//#endregion
|
|
356
|
+
//#region src/generator/transforms/htmlTransforms.ts
|
|
357
|
+
var htmlTransforms = [
|
|
358
|
+
{
|
|
359
|
+
name: "b",
|
|
360
|
+
start: () => {
|
|
361
|
+
return "<strong>";
|
|
362
|
+
},
|
|
363
|
+
end: () => {
|
|
364
|
+
return "</strong>";
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
name: "i",
|
|
369
|
+
start: () => {
|
|
370
|
+
return "<em>";
|
|
371
|
+
},
|
|
372
|
+
end: () => {
|
|
373
|
+
return "</em>";
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
name: "u",
|
|
378
|
+
start: () => {
|
|
379
|
+
return "<ins>";
|
|
380
|
+
},
|
|
381
|
+
end: () => {
|
|
382
|
+
return "</ins>";
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
name: "s",
|
|
387
|
+
start: () => {
|
|
388
|
+
return "<del>";
|
|
389
|
+
},
|
|
390
|
+
end: () => {
|
|
391
|
+
return "</del>";
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
name: "style",
|
|
396
|
+
start: (tagNode) => {
|
|
397
|
+
let style = "";
|
|
398
|
+
for (const child of tagNode.attributes) switch (child.key) {
|
|
399
|
+
case "color":
|
|
400
|
+
style += `color:${child.val};`;
|
|
401
|
+
continue;
|
|
402
|
+
case "size":
|
|
403
|
+
if (/^\d+$/.test(child.val)) style += `font-size:${child.val}%;`;
|
|
404
|
+
else style += `font-size:${child.val};`;
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
return `<span style="${style}">`;
|
|
408
|
+
},
|
|
409
|
+
end: () => {
|
|
410
|
+
return "</span>";
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
name: "color",
|
|
415
|
+
start: (tagNode) => {
|
|
416
|
+
return `<span style="color:${getTagImmediateAttrVal(tagNode)};">`;
|
|
417
|
+
},
|
|
418
|
+
end: () => {
|
|
419
|
+
return "</span>";
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
name: "hr",
|
|
424
|
+
isStandalone: true,
|
|
425
|
+
start: () => {
|
|
426
|
+
return "<hr />";
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
name: "br",
|
|
431
|
+
isStandalone: true,
|
|
432
|
+
start: () => {
|
|
433
|
+
return "<br />";
|
|
434
|
+
}
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
name: "list",
|
|
438
|
+
start: (tagNode) => {
|
|
439
|
+
return isOrderedList(tagNode) ? "<ol>" : "<ul>";
|
|
440
|
+
},
|
|
441
|
+
end: (tagNode) => {
|
|
442
|
+
return isOrderedList(tagNode) ? "</ol>" : "</ul>";
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
name: "*",
|
|
447
|
+
isLinebreakTerminated: true,
|
|
448
|
+
start: () => {
|
|
449
|
+
return "<li>";
|
|
450
|
+
},
|
|
451
|
+
end: () => {
|
|
452
|
+
return "</li>";
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
name: "img",
|
|
457
|
+
skipChildren: true,
|
|
458
|
+
start: (tagNode) => {
|
|
459
|
+
const src = getTagImmediateText(tagNode);
|
|
460
|
+
if (!src) return false;
|
|
461
|
+
if (isDangerousUrl(src)) return false;
|
|
462
|
+
const { width, height } = getWidthHeightAttr(tagNode);
|
|
463
|
+
let str = `<img src="${src}"`;
|
|
464
|
+
if (width) str += ` width="${width}"`;
|
|
465
|
+
if (height) str += ` height="${height}"`;
|
|
466
|
+
str += ">";
|
|
467
|
+
return str;
|
|
468
|
+
}
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
name: "url",
|
|
472
|
+
start: (tagNode) => {
|
|
473
|
+
const href = getTagImmediateAttrVal(tagNode) ?? getTagImmediateText(tagNode);
|
|
474
|
+
if (!href) return false;
|
|
475
|
+
if (isDangerousUrl(href)) return false;
|
|
476
|
+
return `<a href="${href}">`;
|
|
477
|
+
},
|
|
478
|
+
end: () => {
|
|
479
|
+
return "</a>";
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
name: "quote",
|
|
484
|
+
start: (tagNode) => {
|
|
485
|
+
const author = getTagImmediateAttrVal(tagNode);
|
|
486
|
+
return author ? `<blockquote><strong>${author}</strong>` : "<blockquote>";
|
|
487
|
+
},
|
|
488
|
+
end: () => {
|
|
489
|
+
return "</blockquote>";
|
|
490
|
+
}
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
name: "table",
|
|
494
|
+
start: () => {
|
|
495
|
+
return "<table>";
|
|
496
|
+
},
|
|
497
|
+
end: () => {
|
|
498
|
+
return "</table>";
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
name: "tr",
|
|
503
|
+
start: () => {
|
|
504
|
+
return "<tr>";
|
|
505
|
+
},
|
|
506
|
+
end: () => {
|
|
507
|
+
return "</tr>";
|
|
508
|
+
}
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
name: "td",
|
|
512
|
+
start: () => {
|
|
513
|
+
return "<td>";
|
|
514
|
+
},
|
|
515
|
+
end: () => {
|
|
516
|
+
return "</td>";
|
|
517
|
+
}
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
name: "code",
|
|
521
|
+
start: () => {
|
|
522
|
+
return "<code>";
|
|
523
|
+
},
|
|
524
|
+
end: () => {
|
|
525
|
+
return "</code>";
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
];
|
|
529
|
+
//#endregion
|
|
530
|
+
//#region src/generator/Generator.ts
|
|
531
|
+
var Generator = class {
|
|
532
|
+
transforms;
|
|
533
|
+
constructor(transforms = htmlTransforms) {
|
|
534
|
+
this.transforms = new Map(transforms.map((transform) => [transform.name, transform]));
|
|
535
|
+
}
|
|
536
|
+
generate(root) {
|
|
537
|
+
const stringify = (node) => {
|
|
538
|
+
let output = "";
|
|
539
|
+
if (nodeIsType(node, "TagNode")) {
|
|
540
|
+
const tagName = node.tagName;
|
|
541
|
+
const transform = this.transforms.get(tagName);
|
|
542
|
+
if (!transform) throw new Error(`Unrecognized bbcode ${node.tagName}`);
|
|
543
|
+
const renderedStartTag = transform.start(node);
|
|
544
|
+
const renderedEndTag = transform.end?.(node) ?? "";
|
|
545
|
+
const isInvalidTag = renderedStartTag === false;
|
|
546
|
+
if (isInvalidTag) output += node.ogStartTag;
|
|
547
|
+
else output += renderedStartTag;
|
|
548
|
+
if (!transform.skipChildren || isInvalidTag) for (const child of node.children) output += stringify(child);
|
|
549
|
+
if (isInvalidTag) output += node.ogEndTag;
|
|
550
|
+
else output += renderedEndTag;
|
|
551
|
+
} else if (nodeIsType(node, "TextNode")) output += node.str;
|
|
552
|
+
else if (nodeIsType(node, "LinebreakNode")) output += "\n";
|
|
553
|
+
else for (const child of node.children) output += stringify(child);
|
|
554
|
+
return output;
|
|
555
|
+
};
|
|
556
|
+
return stringify(root);
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
//#endregion
|
|
560
|
+
//#region src/lexer/TokenType.ts
|
|
561
|
+
function tokenTypeToString(tokenType) {
|
|
562
|
+
switch (tokenType) {
|
|
563
|
+
case "STR": return "STR";
|
|
564
|
+
case "LINEBREAK": return "LINEBREAK";
|
|
565
|
+
case "L_BRACKET": return "L_BRACKET";
|
|
566
|
+
case "R_BRACKET": return "R_BRACKET";
|
|
567
|
+
case "BACKSLASH": return "BACKSLASH";
|
|
568
|
+
case "EQUALS": return "EQUALS";
|
|
569
|
+
case "XSS_AMP": return "XSS_AMP";
|
|
570
|
+
case "XSS_LT": return "XSS_LT";
|
|
571
|
+
case "XSS_GT": return "XSS_GT";
|
|
572
|
+
case "XSS_D_QUOTE": return "XSS_D_QUOTE";
|
|
573
|
+
case "XSS_S_QUOTE": return "XSS_S_QUOTE";
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
function isStringToken(tokenType) {
|
|
577
|
+
switch (tokenType) {
|
|
578
|
+
case "XSS_AMP":
|
|
579
|
+
case "XSS_LT":
|
|
580
|
+
case "XSS_GT":
|
|
581
|
+
case "XSS_D_QUOTE":
|
|
582
|
+
case "XSS_S_QUOTE":
|
|
583
|
+
case "STR": return true;
|
|
584
|
+
}
|
|
585
|
+
return false;
|
|
586
|
+
}
|
|
587
|
+
var symbolTable = {
|
|
588
|
+
"\n": "LINEBREAK",
|
|
589
|
+
"[": "L_BRACKET",
|
|
590
|
+
"]": "R_BRACKET",
|
|
591
|
+
"/": "BACKSLASH",
|
|
592
|
+
"=": "EQUALS",
|
|
593
|
+
"&": "XSS_AMP",
|
|
594
|
+
"<": "XSS_LT",
|
|
595
|
+
">": "XSS_GT",
|
|
596
|
+
"\"": "XSS_D_QUOTE",
|
|
597
|
+
"'": "XSS_S_QUOTE"
|
|
598
|
+
};
|
|
599
|
+
//#endregion
|
|
600
|
+
//#region src/lexer/Lexer.ts
|
|
601
|
+
var Lexer = class {
|
|
602
|
+
tokenize(input) {
|
|
603
|
+
const tokens = new Array();
|
|
604
|
+
const re = /\n|\[\/|\[(\w+|\*)|\]|=|&|<|>|'|"/g;
|
|
605
|
+
let offset = 0;
|
|
606
|
+
while (true) {
|
|
607
|
+
const match = re.exec(input);
|
|
608
|
+
if (!match) break;
|
|
609
|
+
const length = match.index - offset;
|
|
610
|
+
if (length > 0) tokens.push({
|
|
611
|
+
type: "STR",
|
|
612
|
+
offset,
|
|
613
|
+
length
|
|
614
|
+
});
|
|
615
|
+
offset = match.index;
|
|
616
|
+
if (match[0] === "[/") {
|
|
617
|
+
tokens.push({
|
|
618
|
+
type: "L_BRACKET",
|
|
619
|
+
offset,
|
|
620
|
+
length: 1
|
|
621
|
+
});
|
|
622
|
+
offset += 1;
|
|
623
|
+
tokens.push({
|
|
624
|
+
type: "BACKSLASH",
|
|
625
|
+
offset,
|
|
626
|
+
length: 1
|
|
627
|
+
});
|
|
628
|
+
offset += 1;
|
|
629
|
+
} else if (match[0].startsWith("[")) {
|
|
630
|
+
tokens.push({
|
|
631
|
+
type: "L_BRACKET",
|
|
632
|
+
offset,
|
|
633
|
+
length: 1
|
|
634
|
+
});
|
|
635
|
+
offset += 1;
|
|
636
|
+
const length = match[0].length - 1;
|
|
637
|
+
tokens.push({
|
|
638
|
+
type: "STR",
|
|
639
|
+
offset,
|
|
640
|
+
length
|
|
641
|
+
});
|
|
642
|
+
offset += length;
|
|
643
|
+
} else {
|
|
644
|
+
tokens.push({
|
|
645
|
+
type: symbolTable[match[0]] ?? "STR",
|
|
646
|
+
offset,
|
|
647
|
+
length: 1
|
|
648
|
+
});
|
|
649
|
+
offset += 1;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
const length = input.length - offset;
|
|
653
|
+
if (length > 0) tokens.push({
|
|
654
|
+
type: "STR",
|
|
655
|
+
offset,
|
|
656
|
+
length
|
|
657
|
+
});
|
|
658
|
+
return tokens;
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
//#endregion
|
|
662
|
+
//#region src/lexer/Token.ts
|
|
663
|
+
function stringifyTokens(ogText, tokens) {
|
|
664
|
+
let s = "";
|
|
665
|
+
for (const token of tokens) switch (token.type) {
|
|
666
|
+
case "STR":
|
|
667
|
+
s += ogText.substring(token.offset, token.offset + token.length);
|
|
668
|
+
break;
|
|
669
|
+
case "LINEBREAK":
|
|
670
|
+
s += "\n";
|
|
671
|
+
break;
|
|
672
|
+
case "L_BRACKET":
|
|
673
|
+
s += "[";
|
|
674
|
+
break;
|
|
675
|
+
case "R_BRACKET":
|
|
676
|
+
s += "]";
|
|
677
|
+
break;
|
|
678
|
+
case "BACKSLASH":
|
|
679
|
+
s += "/";
|
|
680
|
+
break;
|
|
681
|
+
case "EQUALS":
|
|
682
|
+
s += "=";
|
|
683
|
+
break;
|
|
684
|
+
case "XSS_AMP":
|
|
685
|
+
s += "&";
|
|
686
|
+
break;
|
|
687
|
+
case "XSS_LT":
|
|
688
|
+
s += "<";
|
|
689
|
+
break;
|
|
690
|
+
case "XSS_GT":
|
|
691
|
+
s += ">";
|
|
692
|
+
break;
|
|
693
|
+
case "XSS_D_QUOTE":
|
|
694
|
+
s += """;
|
|
695
|
+
break;
|
|
696
|
+
case "XSS_S_QUOTE":
|
|
697
|
+
s += "'";
|
|
698
|
+
break;
|
|
699
|
+
}
|
|
700
|
+
return s;
|
|
701
|
+
}
|
|
702
|
+
//#endregion
|
|
703
|
+
//#region src/parser/Parser.ts
|
|
704
|
+
var Parser = class {
|
|
705
|
+
tags;
|
|
706
|
+
linebreakTerminatedTags;
|
|
707
|
+
standaloneTags;
|
|
708
|
+
constructor(transforms = htmlTransforms) {
|
|
709
|
+
this.tags = new Set(transforms.map((transform) => transform.name));
|
|
710
|
+
this.linebreakTerminatedTags = new Set(transforms.filter((transform) => transform.isLinebreakTerminated).map((transform) => transform.name.toLowerCase()));
|
|
711
|
+
this.standaloneTags = new Set(transforms.filter((transform) => transform.isStandalone).map((transform) => transform.name.toLowerCase()));
|
|
712
|
+
}
|
|
713
|
+
parse(ogText, tokens) {
|
|
714
|
+
let idx = 0;
|
|
715
|
+
const parseLabel = () => {
|
|
716
|
+
const label = stringifyTokens(ogText, tokens.slice(idx, idx + 1));
|
|
717
|
+
idx += 1;
|
|
718
|
+
return label.toLowerCase();
|
|
719
|
+
};
|
|
720
|
+
const parseText = (endOnQuotes = false, endOnSpace = false) => {
|
|
721
|
+
const startIdx = idx;
|
|
722
|
+
while (idx < tokens.length) {
|
|
723
|
+
if (!isStringToken(tokens[idx].type)) break;
|
|
724
|
+
if (endOnQuotes && (tokens[idx].type === "XSS_S_QUOTE" || tokens[idx].type === "XSS_D_QUOTE")) break;
|
|
725
|
+
/**
|
|
726
|
+
* SPECIAL CASE:
|
|
727
|
+
* If we encounter a space, then we must split the current token into 2 tokens and only consume the first part
|
|
728
|
+
*
|
|
729
|
+
* a b -> a b
|
|
730
|
+
* | | |
|
|
731
|
+
* | | idx (new)
|
|
732
|
+
* | |
|
|
733
|
+
* idx consumed
|
|
734
|
+
*
|
|
735
|
+
* Note: We only handle endOnSpace special case when we don't expect the current text to endOnQuotes
|
|
736
|
+
* If it endOnQuotes, then it implies that it opened with quotes (and thus we need an enclosing/matching quote)
|
|
737
|
+
*/
|
|
738
|
+
if (endOnSpace && !endOnQuotes) {
|
|
739
|
+
const spaceIdx = stringifyTokens(ogText, [tokens[idx]]).indexOf(" ");
|
|
740
|
+
if (spaceIdx >= 0) {
|
|
741
|
+
const oldToken = {
|
|
742
|
+
type: "STR",
|
|
743
|
+
offset: tokens[idx].offset,
|
|
744
|
+
length: spaceIdx
|
|
745
|
+
};
|
|
746
|
+
const newToken = {
|
|
747
|
+
type: "STR",
|
|
748
|
+
offset: tokens[idx].offset + spaceIdx,
|
|
749
|
+
length: tokens[idx].length - spaceIdx
|
|
750
|
+
};
|
|
751
|
+
tokens.splice(idx + 0, 1, oldToken);
|
|
752
|
+
tokens.splice(idx + 1, 0, newToken);
|
|
753
|
+
idx += 1;
|
|
754
|
+
break;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
idx += 1;
|
|
758
|
+
}
|
|
759
|
+
return new TextNode(stringifyTokens(ogText, tokens.slice(startIdx, idx)));
|
|
760
|
+
};
|
|
761
|
+
const parseAttr = () => {
|
|
762
|
+
if (idx + 1 >= tokens.length) return null;
|
|
763
|
+
const attrNode = new AttrNode();
|
|
764
|
+
if (tokens[idx].type === "EQUALS" && isStringToken(tokens[idx + 1].type)) {
|
|
765
|
+
idx += 1;
|
|
766
|
+
const openedWithQuotes = tokens[idx].type === "XSS_S_QUOTE" || tokens[idx].type === "XSS_D_QUOTE";
|
|
767
|
+
if (openedWithQuotes) idx += 1;
|
|
768
|
+
const valNode = parseText(openedWithQuotes, true);
|
|
769
|
+
attrNode.addChild(valNode);
|
|
770
|
+
if (openedWithQuotes) {
|
|
771
|
+
if (tokens[idx].type !== "XSS_S_QUOTE" && tokens[idx].type !== "XSS_D_QUOTE") return null;
|
|
772
|
+
idx += 1;
|
|
773
|
+
}
|
|
774
|
+
} else if (isStringToken(tokens[idx].type) && tokens[idx + 1].type === "EQUALS" && idx + 2 < tokens.length && isStringToken(tokens[idx + 2].type)) {
|
|
775
|
+
const keyNode = parseText();
|
|
776
|
+
attrNode.addChild(keyNode);
|
|
777
|
+
idx += 1;
|
|
778
|
+
const openedWithQuotes = tokens[idx].type === "XSS_S_QUOTE" || tokens[idx].type === "XSS_D_QUOTE";
|
|
779
|
+
if (openedWithQuotes) idx += 1;
|
|
780
|
+
const valNode = parseText(openedWithQuotes, true);
|
|
781
|
+
if (openedWithQuotes) {
|
|
782
|
+
if (tokens[idx].type !== "XSS_S_QUOTE" && tokens[idx].type !== "XSS_D_QUOTE") return null;
|
|
783
|
+
idx += 1;
|
|
784
|
+
}
|
|
785
|
+
attrNode.addChild(valNode);
|
|
786
|
+
} else if (isStringToken(tokens[idx].type) && tokens[idx + 1].type !== "EQUALS") {
|
|
787
|
+
const valNode = parseText();
|
|
788
|
+
attrNode.addChild(valNode);
|
|
789
|
+
} else return null;
|
|
790
|
+
return attrNode;
|
|
791
|
+
};
|
|
792
|
+
const parseTag = () => {
|
|
793
|
+
if (idx + 1 >= tokens.length) return null;
|
|
794
|
+
if (tokens[idx].type !== "L_BRACKET") return null;
|
|
795
|
+
if (isStringToken(tokens[idx + 1].type)) {
|
|
796
|
+
const startIdx = idx;
|
|
797
|
+
idx += 1;
|
|
798
|
+
const labelText = parseLabel();
|
|
799
|
+
if (!this.tags.has(labelText)) return null;
|
|
800
|
+
const attrNodes = new Array();
|
|
801
|
+
while (true) {
|
|
802
|
+
const attrNode = parseAttr();
|
|
803
|
+
if (attrNode === null) break;
|
|
804
|
+
attrNodes.push(attrNode);
|
|
805
|
+
}
|
|
806
|
+
if (tokens[idx].type !== "R_BRACKET") return null;
|
|
807
|
+
idx += 1;
|
|
808
|
+
return new StartTagNode(labelText, stringifyTokens(ogText, tokens.slice(startIdx, idx)), attrNodes);
|
|
809
|
+
}
|
|
810
|
+
if (tokens[idx + 1].type === "BACKSLASH") {
|
|
811
|
+
const startIdx = idx;
|
|
812
|
+
idx += 1;
|
|
813
|
+
idx += 1;
|
|
814
|
+
const labelText = parseLabel();
|
|
815
|
+
if (!this.tags.has(labelText)) return null;
|
|
816
|
+
if (tokens[idx].type !== "R_BRACKET") return null;
|
|
817
|
+
idx += 1;
|
|
818
|
+
return new EndTagNode(labelText, stringifyTokens(ogText, tokens.slice(startIdx, idx)));
|
|
819
|
+
}
|
|
820
|
+
return null;
|
|
821
|
+
};
|
|
822
|
+
const parseRoot = () => {
|
|
823
|
+
const root = new RootNode();
|
|
824
|
+
while (idx < tokens.length) if (tokens[idx].type === "L_BRACKET") {
|
|
825
|
+
const startIdx = idx;
|
|
826
|
+
const tagNode = parseTag();
|
|
827
|
+
if (tagNode !== null) root.addChild(tagNode);
|
|
828
|
+
else {
|
|
829
|
+
const textNode = new TextNode(stringifyTokens(ogText, tokens.slice(startIdx, idx)));
|
|
830
|
+
root.addChild(textNode);
|
|
831
|
+
}
|
|
832
|
+
} else if (tokens[idx].type === "LINEBREAK") {
|
|
833
|
+
idx += 1;
|
|
834
|
+
root.addChild(new LinebreakNode());
|
|
835
|
+
} else {
|
|
836
|
+
const startIdx = idx;
|
|
837
|
+
while (idx < tokens.length && tokens[idx].type !== "L_BRACKET" && tokens[idx].type !== "LINEBREAK") idx += 1;
|
|
838
|
+
const str = stringifyTokens(ogText, tokens.slice(startIdx, idx));
|
|
839
|
+
root.addChild(new TextNode(str));
|
|
840
|
+
}
|
|
841
|
+
return root;
|
|
842
|
+
};
|
|
843
|
+
let root = parseRoot();
|
|
844
|
+
root = this.matchTagNodes(root);
|
|
845
|
+
return root;
|
|
846
|
+
}
|
|
847
|
+
matchTagNodes(rootNode) {
|
|
848
|
+
const transformedRoot = new RootNode();
|
|
849
|
+
for (let i = 0; i < rootNode.children.length; i++) {
|
|
850
|
+
const child = rootNode.children[i];
|
|
851
|
+
if (nodeIsType(child, "StartTagNode")) {
|
|
852
|
+
const endTag = this.findMatchingEndTag(rootNode.children, i, child.tagName);
|
|
853
|
+
const isStandalone = this.standaloneTags.has(child.tagName);
|
|
854
|
+
if (endTag || isStandalone) {
|
|
855
|
+
const tagNode = new TagNode(child, endTag?.node);
|
|
856
|
+
transformedRoot.addChild(tagNode);
|
|
857
|
+
if (endTag) {
|
|
858
|
+
const subRoot = new RootNode(rootNode.children.slice(i + 1, endTag.idx));
|
|
859
|
+
i = endTag.idx;
|
|
860
|
+
const transformedSubRoot = this.matchTagNodes(subRoot);
|
|
861
|
+
tagNode.addChild(transformedSubRoot);
|
|
862
|
+
}
|
|
863
|
+
} else transformedRoot.addChild(new TextNode(child.ogTag));
|
|
864
|
+
} else if (nodeIsType(child, "EndTagNode")) transformedRoot.addChild(new TextNode(child.ogTag));
|
|
865
|
+
else if (nodeIsType(child, "TextNode")) transformedRoot.addChild(child);
|
|
866
|
+
else if (nodeIsType(child, "LinebreakNode")) transformedRoot.addChild(child);
|
|
867
|
+
else throw new Error("Unexpected child of RootNode");
|
|
868
|
+
}
|
|
869
|
+
return transformedRoot;
|
|
870
|
+
}
|
|
871
|
+
findMatchingEndTag(siblings, startIdx, tagName) {
|
|
872
|
+
if (this.standaloneTags.has(tagName)) return null;
|
|
873
|
+
for (let i = startIdx; i < siblings.length; i++) {
|
|
874
|
+
const sibling = siblings[i];
|
|
875
|
+
if (nodeIsType(sibling, "LinebreakNode") && this.linebreakTerminatedTags.has(tagName) || nodeIsType(sibling, "EndTagNode") && sibling.tagName === tagName) return {
|
|
876
|
+
idx: i,
|
|
877
|
+
node: sibling
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
return null;
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
//#endregion
|
|
884
|
+
//#region src/generateHtml.ts
|
|
885
|
+
function generateHtml(input, transforms = htmlTransforms) {
|
|
886
|
+
const tokens = new Lexer().tokenize(input);
|
|
887
|
+
const root = new Parser(transforms).parse(input, tokens);
|
|
888
|
+
return new Generator(transforms).generate(root);
|
|
889
|
+
}
|
|
890
|
+
//#endregion
|
|
891
|
+
exports.AstNode = AstNode;
|
|
892
|
+
exports.AttrNode = AttrNode;
|
|
893
|
+
exports.EndTagNode = EndTagNode;
|
|
894
|
+
exports.Generator = Generator;
|
|
895
|
+
exports.Lexer = Lexer;
|
|
896
|
+
exports.LinebreakNode = LinebreakNode;
|
|
897
|
+
exports.Parser = Parser;
|
|
898
|
+
exports.RootNode = RootNode;
|
|
899
|
+
exports.StartTagNode = StartTagNode;
|
|
900
|
+
exports.TagNode = TagNode;
|
|
901
|
+
exports.TextNode = TextNode;
|
|
902
|
+
exports.generateHtml = generateHtml;
|
|
903
|
+
exports.getTagImmediateAttrVal = getTagImmediateAttrVal;
|
|
904
|
+
exports.getTagImmediateText = getTagImmediateText;
|
|
905
|
+
exports.getWidthHeightAttr = getWidthHeightAttr;
|
|
906
|
+
exports.htmlTransforms = htmlTransforms;
|
|
907
|
+
exports.isDangerousUrl = isDangerousUrl;
|
|
908
|
+
exports.isOrderedList = isOrderedList;
|
|
909
|
+
exports.isStringToken = isStringToken;
|
|
910
|
+
exports.nodeIsType = nodeIsType;
|
|
911
|
+
exports.stringifyTokens = stringifyTokens;
|
|
912
|
+
exports.symbolTable = symbolTable;
|
|
913
|
+
exports.tokenTypeToString = tokenTypeToString;
|
|
1064
914
|
});
|
|
1065
|
-
|
|
915
|
+
|
|
916
|
+
//# sourceMappingURL=index.umd.cjs.map
|