@uniweb/press 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/press",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Press your React components into downloadable files — Word, Excel, PDF. Registration-based pattern with lazy-loaded format adapters.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -48,17 +48,23 @@
48
48
  * // ]
49
49
  */
50
50
 
51
- // Decode HTML-attribute entities written by sequence.js's escapeAttr().
52
- // Inverse of the four replacements there. `&` last so a literal
53
- // `"` round-trips correctly.
54
- function decodeAttr(s) {
55
- return String(s)
56
- .replace(/"/g, '"')
57
- .replace(/&lt;/g, '<')
58
- .replace(/&gt;/g, '>')
59
- .replace(/&amp;/g, '&')
51
+ // Decode the references semantic-parser writes. It escapes text (`&`, `<`,
52
+ // `>`) and attribute values (those and `"`), so a run's characters are the
53
+ // decoded string. One pass, so `&amp;lt;` yields `&lt;` rather than `<`.
54
+ // ⛔ Until 2026-10-14 only attributes were decoded: text arrived unescaped, and
55
+ // a literal `<b>` someone typed was read here as bold.
56
+ const REFERENCES = { amp: '&', lt: '<', gt: '>', quot: '"', apos: "'", nbsp: '\u00a0' }
57
+
58
+ function decodeReferences(s) {
59
+ return String(s).replace(/&(#[xX][0-9a-fA-F]+|#[0-9]+|[a-zA-Z]+);/g, (match, ref) => {
60
+ if (ref[0] !== '#') return REFERENCES[ref] ?? match
61
+ const code = ref[1] === 'x' || ref[1] === 'X' ? parseInt(ref.slice(2), 16) : parseInt(ref.slice(1), 10)
62
+ return code > 0 && code <= 0x10ffff ? String.fromCodePoint(code) : match
63
+ })
60
64
  }
61
65
 
66
+ const decodeAttr = decodeReferences
67
+
62
68
  function readAttr(attrs, name) {
63
69
  const re = new RegExp(`${name}="([^"]*)"`)
64
70
  const m = attrs.match(re)
@@ -68,7 +74,7 @@ function readAttr(attrs, name) {
68
74
  export function parseStyledString(inputString) {
69
75
  const createTextPart = (content, styles) => ({
70
76
  type: 'text',
71
- content,
77
+ content: decodeReferences(content),
72
78
  ...styles,
73
79
  })
74
80