@uniweb/semantic-parser 1.10.0 → 1.11.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/package.json +1 -1
- package/src/sanitize.js +40 -13
package/package.json
CHANGED
package/src/sanitize.js
CHANGED
|
@@ -347,9 +347,16 @@ function rebuild(input, policy) {
|
|
|
347
347
|
|
|
348
348
|
/**
|
|
349
349
|
* What a rebuild would leave out of `input`, item by item — the same walk as
|
|
350
|
-
* `rebuild`, reporting instead of writing
|
|
351
|
-
*
|
|
352
|
-
*
|
|
350
|
+
* `rebuild`, reporting instead of writing — and, when it leaves nothing out but
|
|
351
|
+
* writes the markup differently, one `spelling` item at the first difference.
|
|
352
|
+
* Empty when a rebuild writes `input` back exactly as given.
|
|
353
|
+
*
|
|
354
|
+
* ⭐ Exactly, not "up to spelling" (since 2026-10-18): every text run and
|
|
355
|
+
* attribute value a rebuild writes is escaped, so markup in that form reads the
|
|
356
|
+
* same to any reader. Markup spelled otherwise — a `<` left in text, a CDATA
|
|
357
|
+
* section, a reference the rebuild would write as its character — can read one
|
|
358
|
+
* way here and another way to a reader that parses it as written, which a store
|
|
359
|
+
* holding it for every reader cannot allow.
|
|
353
360
|
*/
|
|
354
361
|
function inspect(input, policy) {
|
|
355
362
|
const outside = [];
|
|
@@ -394,6 +401,14 @@ function inspect(input, policy) {
|
|
|
394
401
|
}
|
|
395
402
|
}
|
|
396
403
|
}
|
|
404
|
+
if (!outside.length) {
|
|
405
|
+
const rebuilt = rebuild(input, policy);
|
|
406
|
+
if (rebuilt !== input) {
|
|
407
|
+
let at = 0;
|
|
408
|
+
while (input[at] === rebuilt[at]) at++;
|
|
409
|
+
outside.push({ reason: "spelling", value: input.slice(at, at + 40) });
|
|
410
|
+
}
|
|
411
|
+
}
|
|
397
412
|
return outside;
|
|
398
413
|
}
|
|
399
414
|
|
|
@@ -412,14 +427,16 @@ export function sanitizeMathML(mathml) {
|
|
|
412
427
|
/**
|
|
413
428
|
* What in a MathML string falls outside the allowlist `sanitizeMathML` rebuilds
|
|
414
429
|
* from: each element and attribute a rebuild drops, each style declaration it
|
|
415
|
-
* drops, and any comment, doctype or processing instruction
|
|
416
|
-
*
|
|
430
|
+
* drops, and any comment, doctype or processing instruction — or, when it drops
|
|
431
|
+
* nothing, a `spelling` item if the rebuild writes the markup differently. Empty
|
|
432
|
+
* when `sanitizeMathML` writes the markup back exactly as given, so a writer
|
|
433
|
+
* that stores what `sanitizeMathML` returns stores markup within it.
|
|
417
434
|
*
|
|
418
435
|
* This is how content is checked rather than cleaned — a writer refused with
|
|
419
436
|
* what it sent can fix it, where a cleaned value changes without a word.
|
|
420
437
|
*
|
|
421
438
|
* @param {string} mathml
|
|
422
|
-
* @returns {Array<{reason: 'element'|'attribute'|'style'|'markup', element?: string, attribute?: string, value?: string}>}
|
|
439
|
+
* @returns {Array<{reason: 'element'|'attribute'|'style'|'markup'|'spelling', element?: string, attribute?: string, value?: string}>}
|
|
423
440
|
*/
|
|
424
441
|
export function inspectMathML(mathml) {
|
|
425
442
|
if (typeof mathml !== "string" || !mathml) return [];
|
|
@@ -443,11 +460,11 @@ export function sanitizeSVG(svg) {
|
|
|
443
460
|
|
|
444
461
|
/**
|
|
445
462
|
* What in an SVG string falls outside the allowlist `sanitizeSVG` rebuilds
|
|
446
|
-
* from, reported as `inspectMathML` reports MathML. Empty when
|
|
447
|
-
*
|
|
463
|
+
* from, reported as `inspectMathML` reports MathML. Empty when `sanitizeSVG`
|
|
464
|
+
* writes the markup back exactly as given.
|
|
448
465
|
*
|
|
449
466
|
* @param {string} svg
|
|
450
|
-
* @returns {Array<{reason: 'element'|'attribute'|'style'|'markup', element?: string, attribute?: string, value?: string}>}
|
|
467
|
+
* @returns {Array<{reason: 'element'|'attribute'|'style'|'markup'|'spelling', element?: string, attribute?: string, value?: string}>}
|
|
451
468
|
*/
|
|
452
469
|
export function inspectSVG(svg) {
|
|
453
470
|
if (typeof svg !== "string" || !svg) return [];
|
|
@@ -480,8 +497,8 @@ export function isImageSource(url) {
|
|
|
480
497
|
|
|
481
498
|
/**
|
|
482
499
|
* Whether a `data:` URL holds an image a page may show: a PNG, JPEG, GIF, WebP
|
|
483
|
-
* or AVIF in base64, or SVG — percent-encoded or base64 — whose markup is
|
|
484
|
-
*
|
|
500
|
+
* or AVIF in base64, or SVG — percent-encoded or base64 — whose markup is
|
|
501
|
+
* exactly what `sanitizeSVG` writes of it (`inspectSVG`). ⭐ Admitted [Diego, 2026-10-16]: a
|
|
485
502
|
* picture an `<img>` loads runs no script, and a built-in starter image is one.
|
|
486
503
|
* The URL is read as a browser reads it: tab and newline removed, leading and
|
|
487
504
|
* trailing spaces and controls trimmed.
|
|
@@ -598,6 +615,14 @@ export function isCssColor(value) {
|
|
|
598
615
|
return typeof value === "string" && CSS_COLOR.test(value) && !NOT_A_COLOR.test(value);
|
|
599
616
|
}
|
|
600
617
|
|
|
618
|
+
/** How a rebuild writes markup — what `inspect` compares the input with. */
|
|
619
|
+
const WRITTEN =
|
|
620
|
+
"exactly as a rebuild writes it: a text run with `&`, `<` and `>` written `&`, `<` and `>`, and every other character as itself; " +
|
|
621
|
+
"a start tag `<name>` or `<name/>` and an end tag `</name>`, the name as `elements` spells it, with no space before `>` or `/>`; " +
|
|
622
|
+
"each attribute once, as one space then `name=\"value\"` — the name as `attributes` spells it, or a common one in lower case — " +
|
|
623
|
+
"with `&`, `<`, `>` and `\"` in the value written `&`, `<`, `>` and `"`; " +
|
|
624
|
+
"a `style` value as its declarations, each `property:value;` with the property in lower case and the value trimmed";
|
|
625
|
+
|
|
601
626
|
/**
|
|
602
627
|
* The same rules, as data — for a reader that implements them in another
|
|
603
628
|
* language, such as a backend checking content when it is written. Every list
|
|
@@ -632,7 +657,8 @@ export function allowlists() {
|
|
|
632
657
|
unsafeValue: UNSAFE_VALUE.source,
|
|
633
658
|
urlInAValue: "only url(#id), a reference within the document",
|
|
634
659
|
style: "declaration by declaration: a property of letters and -, a value with none of \\ < > { } /* and no unsafe value",
|
|
635
|
-
markup: "no comment, doctype
|
|
660
|
+
markup: "no comment, doctype, processing instruction or CDATA section",
|
|
661
|
+
written: WRITTEN,
|
|
636
662
|
},
|
|
637
663
|
imageData: {
|
|
638
664
|
raster: RASTER_DATA.source,
|
|
@@ -649,7 +675,8 @@ export function allowlists() {
|
|
|
649
675
|
unsafeValue: UNSAFE_VALUE.source,
|
|
650
676
|
urlInAValue: "only url(#id), a reference within the document",
|
|
651
677
|
style: "declaration by declaration: a property of letters and -, a value with none of \\ < > { } /* and no unsafe value",
|
|
652
|
-
markup: "no comment, doctype
|
|
678
|
+
markup: "no comment, doctype, processing instruction or CDATA section",
|
|
679
|
+
written: `${WRITTEN}; an \`href\` or \`xlink:href\` value trimmed`,
|
|
653
680
|
},
|
|
654
681
|
},
|
|
655
682
|
};
|