@pixerate/editor 0.23.0 → 0.24.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.
Files changed (155) hide show
  1. package/README.md +96 -1
  2. package/THIRD_PARTY_NOTICES.md +51 -0
  3. package/dist/agent/index.cjs +9 -8
  4. package/dist/agent/index.cjs.map +1 -1
  5. package/dist/agent/index.d.cts +4 -3
  6. package/dist/agent/index.d.ts +4 -3
  7. package/dist/agent/index.js +3 -2
  8. package/dist/agent/index.js.map +1 -1
  9. package/dist/canvas/index.cjs +1210 -17
  10. package/dist/canvas/index.cjs.map +1 -1
  11. package/dist/canvas/index.d.cts +318 -1
  12. package/dist/canvas/index.d.ts +318 -1
  13. package/dist/canvas/index.js +1199 -6
  14. package/dist/canvas/index.js.map +1 -1
  15. package/dist/{chunk-QBJ22YZR.js → chunk-3CN2WD3X.js} +1354 -206
  16. package/dist/chunk-3CN2WD3X.js.map +1 -0
  17. package/dist/{chunk-JJDLPEWL.js → chunk-3LV6RRPH.js} +2 -2
  18. package/dist/{chunk-MJZBNWG7.js → chunk-5S3Z4PPF.js} +78 -557
  19. package/dist/chunk-5S3Z4PPF.js.map +1 -0
  20. package/dist/chunk-664LQYFJ.js +115 -0
  21. package/dist/chunk-664LQYFJ.js.map +1 -0
  22. package/dist/{chunk-AA4ZEVCC.cjs → chunk-D27YFC46.cjs} +101 -580
  23. package/dist/chunk-D27YFC46.cjs.map +1 -0
  24. package/dist/chunk-D6FH2YAX.cjs +131 -0
  25. package/dist/chunk-D6FH2YAX.cjs.map +1 -0
  26. package/dist/{chunk-4SUNJZWB.cjs → chunk-FD4LPFAE.cjs} +48 -200
  27. package/dist/chunk-FD4LPFAE.cjs.map +1 -0
  28. package/dist/chunk-FODNLX5N.js +749 -0
  29. package/dist/chunk-FODNLX5N.js.map +1 -0
  30. package/dist/{chunk-OYXSKQFR.js → chunk-FPENXAEJ.js} +35 -187
  31. package/dist/chunk-FPENXAEJ.js.map +1 -0
  32. package/dist/chunk-HLIMTC6N.js +1 -0
  33. package/dist/chunk-HLIMTC6N.js.map +1 -0
  34. package/dist/{chunk-QGHGJ56O.js → chunk-ITBSKI26.js} +1483 -19
  35. package/dist/chunk-ITBSKI26.js.map +1 -0
  36. package/dist/{chunk-XDMXXC4Z.cjs → chunk-MA2F5KHF.cjs} +350 -227
  37. package/dist/chunk-MA2F5KHF.cjs.map +1 -0
  38. package/dist/{chunk-RIKBJLS2.cjs → chunk-MCSJFWAO.cjs} +1356 -208
  39. package/dist/chunk-MCSJFWAO.cjs.map +1 -0
  40. package/dist/chunk-MKA3AHLV.cjs +256 -0
  41. package/dist/chunk-MKA3AHLV.cjs.map +1 -0
  42. package/dist/chunk-OLZJXL4R.cjs +749 -0
  43. package/dist/chunk-OLZJXL4R.cjs.map +1 -0
  44. package/dist/chunk-OXSV64JX.js +689 -0
  45. package/dist/chunk-OXSV64JX.js.map +1 -0
  46. package/dist/chunk-P3RQ5UJE.cjs +689 -0
  47. package/dist/chunk-P3RQ5UJE.cjs.map +1 -0
  48. package/dist/chunk-P6ODPZ4W.js +256 -0
  49. package/dist/chunk-P6ODPZ4W.js.map +1 -0
  50. package/dist/chunk-PGNZKFQS.js +685 -0
  51. package/dist/chunk-PGNZKFQS.js.map +1 -0
  52. package/dist/chunk-PL4JB3BF.cjs +1 -0
  53. package/dist/chunk-PL4JB3BF.cjs.map +1 -0
  54. package/dist/{chunk-GVSMRPHB.cjs → chunk-SBCZ6RN5.cjs} +1568 -104
  55. package/dist/chunk-SBCZ6RN5.cjs.map +1 -0
  56. package/dist/{chunk-CL37JGFW.cjs → chunk-SML64VJG.cjs} +4 -4
  57. package/dist/{chunk-CL37JGFW.cjs.map → chunk-SML64VJG.cjs.map} +1 -1
  58. package/dist/chunk-TNNJXF46.cjs +115 -0
  59. package/dist/chunk-TNNJXF46.cjs.map +1 -0
  60. package/dist/chunk-U5HZSFCS.js +131 -0
  61. package/dist/chunk-U5HZSFCS.js.map +1 -0
  62. package/dist/{chunk-K3R5NG2D.js → chunk-U5KWZU4X.js} +251 -128
  63. package/dist/chunk-U5KWZU4X.js.map +1 -0
  64. package/dist/chunk-XNORY7M6.cjs +685 -0
  65. package/dist/chunk-XNORY7M6.cjs.map +1 -0
  66. package/dist/commands/index.d.cts +5 -353
  67. package/dist/commands/index.d.ts +5 -353
  68. package/dist/comment-store-BEMgVlAA.d.cts +135 -0
  69. package/dist/comment-store-BEMgVlAA.d.ts +135 -0
  70. package/dist/compare/index.cjs +15 -0
  71. package/dist/compare/index.cjs.map +1 -0
  72. package/dist/compare/index.d.cts +58 -0
  73. package/dist/compare/index.d.ts +58 -0
  74. package/dist/compare/index.js +15 -0
  75. package/dist/compare/index.js.map +1 -0
  76. package/dist/{controller-pePCJLT1.d.cts → controller-BhLLAoi8.d.cts} +45 -4
  77. package/dist/{controller-pePCJLT1.d.ts → controller-BhLLAoi8.d.ts} +45 -4
  78. package/dist/documents-BQjzJNe2.d.ts +76 -0
  79. package/dist/documents-KRTPhvst.d.cts +76 -0
  80. package/dist/extensions/index.cjs +53 -5
  81. package/dist/extensions/index.cjs.map +1 -1
  82. package/dist/extensions/index.d.cts +7 -3
  83. package/dist/extensions/index.d.ts +7 -3
  84. package/dist/extensions/index.js +52 -4
  85. package/dist/generation/index.cjs +1373 -0
  86. package/dist/generation/index.cjs.map +1 -0
  87. package/dist/generation/index.d.cts +554 -0
  88. package/dist/generation/index.d.ts +554 -0
  89. package/dist/generation/index.js +1373 -0
  90. package/dist/generation/index.js.map +1 -0
  91. package/dist/grammar/index.cjs +48 -3
  92. package/dist/grammar/index.cjs.map +1 -1
  93. package/dist/grammar/index.d.cts +322 -100
  94. package/dist/grammar/index.d.ts +322 -100
  95. package/dist/grammar/index.js +54 -9
  96. package/dist/image-editor/index.cjs +1831 -30
  97. package/dist/image-editor/index.cjs.map +1 -1
  98. package/dist/image-editor/index.d.cts +590 -3
  99. package/dist/image-editor/index.d.ts +590 -3
  100. package/dist/image-editor/index.js +1807 -6
  101. package/dist/image-editor/index.js.map +1 -1
  102. package/dist/{index-CCr_z9kF.d.cts → index-BhJBSm2d.d.cts} +370 -4
  103. package/dist/{index-Ck6ajwXh.d.ts → index-fJrlkJCd.d.ts} +370 -4
  104. package/dist/index.cjs +162 -25
  105. package/dist/index.cjs.map +1 -1
  106. package/dist/index.d.cts +14 -8
  107. package/dist/index.d.ts +14 -8
  108. package/dist/index.js +174 -37
  109. package/dist/index.js.map +1 -1
  110. package/dist/migrate-iTlm3a8h.d.cts +112 -0
  111. package/dist/migrate-iTlm3a8h.d.ts +112 -0
  112. package/dist/persistence/index.cjs +676 -0
  113. package/dist/persistence/index.cjs.map +1 -0
  114. package/dist/persistence/index.d.cts +347 -0
  115. package/dist/persistence/index.d.ts +347 -0
  116. package/dist/persistence/index.js +676 -0
  117. package/dist/persistence/index.js.map +1 -0
  118. package/dist/{registry-D5-R90p0.d.cts → registry-BDe-vlv3.d.ts} +2 -40
  119. package/dist/registry-D32LpIc4.d.cts +354 -0
  120. package/dist/{registry-D5-R90p0.d.ts → registry-DnzpgY27.d.cts} +2 -40
  121. package/dist/registry-evKTP4ls.d.ts +354 -0
  122. package/dist/schema-DYDGdYL9.d.cts +41 -0
  123. package/dist/schema-DYDGdYL9.d.ts +41 -0
  124. package/dist/serializers/index.cjs +4 -3
  125. package/dist/serializers/index.cjs.map +1 -1
  126. package/dist/serializers/index.d.cts +2 -1
  127. package/dist/serializers/index.d.ts +2 -1
  128. package/dist/serializers/index.js +3 -2
  129. package/dist/sourcemap-C8AH3MBQ.d.cts +91 -0
  130. package/dist/sourcemap-DA1Evhrv.d.ts +91 -0
  131. package/dist/spreadsheet/index.cjs +37 -3
  132. package/dist/spreadsheet/index.cjs.map +1 -1
  133. package/dist/spreadsheet/index.d.cts +188 -17
  134. package/dist/spreadsheet/index.d.ts +188 -17
  135. package/dist/spreadsheet/index.js +43 -9
  136. package/dist/{tokens-CyLZmIei.d.cts → tokens-D7yXvUU6.d.cts} +15 -2
  137. package/dist/{tokens-CyLZmIei.d.ts → tokens-D7yXvUU6.d.ts} +15 -2
  138. package/dist/{track-changes-BSF58RK0.d.ts → track-changes-BK5sVf4_.d.cts} +18 -136
  139. package/dist/{track-changes-BSF58RK0.d.cts → track-changes-CDjCrwKe.d.ts} +18 -136
  140. package/package.json +16 -1
  141. package/dist/chunk-4SUNJZWB.cjs.map +0 -1
  142. package/dist/chunk-AA4ZEVCC.cjs.map +0 -1
  143. package/dist/chunk-AXV2ZW34.cjs +0 -118
  144. package/dist/chunk-AXV2ZW34.cjs.map +0 -1
  145. package/dist/chunk-B2ZRLN4S.js +0 -118
  146. package/dist/chunk-B2ZRLN4S.js.map +0 -1
  147. package/dist/chunk-GVSMRPHB.cjs.map +0 -1
  148. package/dist/chunk-K3R5NG2D.js.map +0 -1
  149. package/dist/chunk-MJZBNWG7.js.map +0 -1
  150. package/dist/chunk-OYXSKQFR.js.map +0 -1
  151. package/dist/chunk-QBJ22YZR.js.map +0 -1
  152. package/dist/chunk-QGHGJ56O.js.map +0 -1
  153. package/dist/chunk-RIKBJLS2.cjs.map +0 -1
  154. package/dist/chunk-XDMXXC4Z.cjs.map +0 -1
  155. /package/dist/{chunk-JJDLPEWL.js.map → chunk-3LV6RRPH.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
3
 
4
- var _chunkAA4ZEVCCcjs = require('./chunk-AA4ZEVCC.cjs');
4
+ var _chunkXNORY7M6cjs = require('./chunk-XNORY7M6.cjs');
5
5
 
6
6
  // src/serializers/html.ts
7
7
  var DROP_WITH_CONTENT_REGEX = /<(script|style|template|noscript|iframe|object|embed|head|title|svg|math|textarea|select|button)\b[^>]*>[\s\S]*?<\/\1\s*>/gi;
@@ -15,12 +15,12 @@ function sanitizeImportedHtml(html) {
15
15
  const body = BODY_REGEX.exec(content);
16
16
  if (body) content = body[1];
17
17
  content = content.replace(DROP_WITH_CONTENT_REGEX, "").replace(UNCLOSED_RAW_TEXT_REGEX, "").replace(NAMESPACED_TAG_REGEX, "");
18
- const sanitized = _chunkAA4ZEVCCcjs.sanitizeHtml.call(void 0, content, { disallowedTags: "strip" }).trim();
18
+ const sanitized = _chunkXNORY7M6cjs.sanitizeHtml.call(void 0, content, { disallowedTags: "strip" }).trim();
19
19
  return sanitized || "<p></p>";
20
20
  }
21
21
  function plainTextToParagraphHtml(text) {
22
22
  if (!text) return "<p></p>";
23
- return text.replace(/\r\n?/g, "\n").split("\n").map((line) => `<p>${_chunkAA4ZEVCCcjs.escapeHtml.call(void 0, line)}</p>`).join("");
23
+ return text.replace(/\r\n?/g, "\n").split("\n").map((line) => `<p>${_chunkXNORY7M6cjs.escapeHtml.call(void 0, line)}</p>`).join("");
24
24
  }
25
25
 
26
26
  // src/serializers/rtf.ts
@@ -296,4 +296,4 @@ function readRichClipboard(event, schema, mimeType = PIXERATE_DOCUMENT_MIME) {
296
296
 
297
297
 
298
298
  exports.sanitizeImportedHtml = sanitizeImportedHtml; exports.plainTextToParagraphHtml = plainTextToParagraphHtml; exports.rtfToPlainText = rtfToPlainText; exports.PIXERATE_DOCUMENT_MIME = PIXERATE_DOCUMENT_MIME; exports.getSchemaSignature = getSchemaSignature; exports.serializeRichClipboardPayload = serializeRichClipboardPayload; exports.parseRichClipboardPayload = parseRichClipboardPayload; exports.getClipboardData = getClipboardData; exports.readRichClipboard = readRichClipboard;
299
- //# sourceMappingURL=chunk-CL37JGFW.cjs.map
299
+ //# sourceMappingURL=chunk-SML64VJG.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-CL37JGFW.cjs","../src/serializers/html.ts","../src/serializers/rtf.ts","../src/serializers/clipboard.ts"],"names":[],"mappings":"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","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-CL37JGFW.cjs","sourcesContent":[null,"import { sanitizeHtml } from \"./markdown\";\nimport { escapeHtml } from \"./plain-text\";\n\n/**\n * Elements whose content is never document text (scripts, styles, metadata,\n * embedded objects, form controls). They are removed together with their\n * content before sanitizing, so e.g. CSS rules don't show up as paragraphs.\n */\nconst DROP_WITH_CONTENT_REGEX =\n /<(script|style|template|noscript|iframe|object|embed|head|title|svg|math|textarea|select|button)\\b[^>]*>[\\s\\S]*?<\\/\\1\\s*>/gi;\n/** An unclosed `<script>` / `<style>` swallows the rest of the document. */\nconst UNCLOSED_RAW_TEXT_REGEX = /<(script|style)\\b[^>]*>[\\s\\S]*$/i;\nconst BODY_REGEX = /<body\\b[^>]*>([\\s\\S]*?)(?:<\\/body\\s*>|$)/i;\n/** Namespaced tags such as Word's `<o:p>`, which the sanitizer cannot parse. */\nconst NAMESPACED_TAG_REGEX = /<\\/?[a-zA-Z][\\w-]*:[\\w-]+\\b[^>]*>/g;\n\n/**\n * Sanitizes a full HTML document or fragment for insertion into the editor,\n * e.g. an imported `.html` file or HTML from another application.\n *\n * - Keeps only the `<body>` content when the input is a full document.\n * - Removes comments, doctype/XML declarations, CDATA, scripts, styles and\n * other non-text elements together with their content.\n * - Applies the same tag/attribute/URL allowlist as embedded HTML in markdown\n * (see `sanitizeHtml`), but strips disallowed tags instead of escaping them,\n * so wrappers such as `<section>` or `<font>` keep their text.\n *\n * It is string-based (no live DOM), so handlers such as `<img onerror>` never run.\n */\nexport function sanitizeImportedHtml(html: string): string {\n if (!html) return \"<p></p>\";\n let content = html.replace(/^/, \"\");\n content = content\n .replace(/<!--[\\s\\S]*?(?:-->|$)/g, \"\")\n .replace(/<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>|$)/g, \"\")\n .replace(/<![^>]*>/g, \"\")\n .replace(/<\\?[\\s\\S]*?(?:\\?>|$)/g, \"\");\n const body = BODY_REGEX.exec(content);\n if (body) content = body[1];\n content = content\n .replace(DROP_WITH_CONTENT_REGEX, \"\")\n .replace(UNCLOSED_RAW_TEXT_REGEX, \"\")\n .replace(NAMESPACED_TAG_REGEX, \"\");\n const sanitized = sanitizeHtml(content, { disallowedTags: \"strip\" }).trim();\n return sanitized || \"<p></p>\";\n}\n\n/**\n * Converts untrusted plain text to TipTap paragraph HTML, always escaping it.\n *\n * Unlike `plainTextToTipTapHtml`, text that already looks like `<p>…</p>` is\n * not passed through as HTML, which matters for imported files.\n */\nexport function plainTextToParagraphHtml(text: string): string {\n if (!text) return \"<p></p>\";\n return text\n .replace(/\\r\\n?/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => `<p>${escapeHtml(line)}</p>`)\n .join(\"\");\n}\n","/**\n * Destinations whose content is metadata or binary data rather than document\n * text. A group starting with one of these control words (or with `\\*`) is\n * skipped entirely.\n */\nconst SKIPPED_DESTINATIONS = new Set([\n \"author\", \"bkmkend\", \"bkmkstart\", \"colortbl\", \"comment\", \"datastore\",\n \"doccomm\", \"falt\", \"fldinst\", \"filetbl\", \"fonttbl\", \"footer\", \"footerf\",\n \"footerl\", \"footerr\", \"footnote\", \"generator\", \"header\", \"headerf\",\n \"headerl\", \"headerr\", \"info\", \"keywords\", \"latentstyles\", \"listoverridetable\",\n \"listtable\", \"nonshppict\", \"object\", \"operator\", \"pict\", \"private\", \"revtbl\",\n \"rsidtbl\", \"shppict\", \"stylesheet\", \"subject\", \"themedata\", \"title\",\n \"xmlnstbl\", \"colorschememapping\",\n]);\n\n/** Control words that map to a literal character. */\nconst CONTROL_WORD_TEXT: Record<string, string> = {\n par: \"\\n\",\n sect: \"\\n\",\n page: \"\\n\",\n line: \"\\n\",\n row: \"\\n\",\n cell: \"\\t\",\n tab: \"\\t\",\n emdash: \"—\",\n endash: \"–\",\n emspace: \" \",\n enspace: \" \",\n bullet: \"•\",\n lquote: \"‘\",\n rquote: \"’\",\n ldblquote: \"“\",\n rdblquote: \"”\",\n};\n\n/** Windows-1252 code points in 0x80–0x9F that differ from Latin-1. */\nconst CP1252: Record<number, string> = {\n 0x80: \"€\", 0x82: \"‚\", 0x83: \"ƒ\", 0x84: \"„\", 0x85: \"…\",\n 0x86: \"†\", 0x87: \"‡\", 0x88: \"ˆ\", 0x89: \"‰\", 0x8a: \"Š\",\n 0x8b: \"‹\", 0x8c: \"Œ\", 0x8e: \"Ž\", 0x91: \"‘\", 0x92: \"’\",\n 0x93: \"“\", 0x94: \"”\", 0x95: \"•\", 0x96: \"–\", 0x97: \"—\",\n 0x98: \"˜\", 0x99: \"™\", 0x9a: \"š\", 0x9b: \"›\", 0x9c: \"œ\",\n 0x9e: \"ž\", 0x9f: \"Ÿ\",\n};\n\nconst CONTROL_WORD_REGEX = /\\\\([a-zA-Z]{1,32})(-?\\d{1,10})? ?/y;\n\n/**\n * Best-effort plain-text extraction from an RTF document.\n *\n * Handles paragraphs/line breaks/tabs, escaped braces and backslashes,\n * `\\'hh` hex escapes (decoded as Windows-1252), `\\uN` Unicode escapes with\n * their `\\ucN` fallback characters, common typographic control words, and\n * skips metadata destinations (font/colour tables, `\\info`, pictures, field\n * instructions, `\\*` destinations). Formatting (bold, lists, tables) is not\n * preserved. Input that does not start with `{\\rtf` is returned unchanged.\n */\nexport function rtfToPlainText(rtf: string): string {\n if (!rtf) return \"\";\n if (!/^\\s*\\{\\\\rtf/.test(rtf)) return rtf;\n\n let out = \"\";\n const stack: Array<{ skip: boolean; uc: number }> = [];\n let skip = false;\n // Number of fallback characters that follow a \\uN escape.\n let uc = 1;\n let pendingFallback = 0;\n // True right after `{`, so a destination control word can mark the group.\n let groupStart = false;\n\n const emit = (text: string) => {\n if (skip) return;\n if (pendingFallback > 0) {\n pendingFallback--;\n return;\n }\n out += text;\n };\n\n let i = 0;\n while (i < rtf.length) {\n const ch = rtf[i];\n if (ch === \"{\") {\n stack.push({ skip, uc });\n groupStart = true;\n i++;\n continue;\n }\n if (ch === \"}\") {\n const prev = stack.pop();\n if (prev) {\n skip = prev.skip;\n uc = prev.uc;\n }\n pendingFallback = 0;\n groupStart = false;\n i++;\n continue;\n }\n const atGroupStart = groupStart;\n groupStart = false;\n\n if (ch === \"\\\\\") {\n const next = rtf[i + 1];\n if (next === \"\\\\\" || next === \"{\" || next === \"}\") {\n emit(next);\n i += 2;\n continue;\n }\n if (next === \"*\") {\n // `{\\*\\dest …}`: an ignorable destination this reader doesn't know.\n skip = true;\n i += 2;\n continue;\n }\n if (next === \"'\") {\n const code = parseInt(rtf.slice(i + 2, i + 4), 16);\n if (!Number.isNaN(code)) emit(CP1252[code] ?? String.fromCharCode(code));\n i += 4;\n continue;\n }\n if (next === \"~\") {\n emit(\" \");\n i += 2;\n continue;\n }\n if (next === \"_\") {\n emit(\"‑\");\n i += 2;\n continue;\n }\n if (next === \"\\n\" || next === \"\\r\") {\n emit(\"\\n\");\n i += 2;\n continue;\n }\n CONTROL_WORD_REGEX.lastIndex = i;\n const match = CONTROL_WORD_REGEX.exec(rtf);\n if (!match) {\n // Other control symbols (`\\-`, `\\|`, `\\:`) produce no text.\n i += 2;\n continue;\n }\n i = CONTROL_WORD_REGEX.lastIndex;\n const word = match[1];\n const param = match[2] !== undefined ? parseInt(match[2], 10) : undefined;\n if (atGroupStart && SKIPPED_DESTINATIONS.has(word)) {\n skip = true;\n } else if (word === \"u\" && param !== undefined) {\n emit(String.fromCharCode(param < 0 ? param + 65536 : param));\n if (!skip) pendingFallback = uc;\n } else if (word === \"uc\" && param !== undefined) {\n uc = param;\n } else if (word === \"bin\" && param !== undefined) {\n // Raw binary data: skip it.\n i += param;\n } else if (CONTROL_WORD_TEXT[word] !== undefined) {\n emit(CONTROL_WORD_TEXT[word]);\n }\n continue;\n }\n // Raw newlines are formatting in RTF; only control words break lines.\n if (ch === \"\\n\" || ch === \"\\r\") {\n i++;\n continue;\n }\n emit(ch);\n i++;\n }\n\n return out.replace(/\\n+$/, \"\");\n}\n","import { Slice, type Schema } from \"@tiptap/pm/model\";\n\n/**\n * Custom clipboard MIME type for content copied from a @pixerate/editor\n * rich-text editor. It carries the ProseMirror slice as JSON so pasting back\n * into a compatible editor is lossless (no HTML round trip).\n */\nexport const PIXERATE_DOCUMENT_MIME = \"application/x.pixerate.document+json\";\n\n/** Payload written under {@link PIXERATE_DOCUMENT_MIME}. */\nexport interface RichClipboardPayload {\n version: 1;\n /** {@link getSchemaSignature} of the source editor's schema. */\n schema: string;\n /** `Slice.toJSON()` of the copied selection. */\n slice: { content?: unknown[]; openStart?: number; openEnd?: number } | null;\n}\n\nconst signatureCache = new WeakMap<Schema, string>();\n\n/** 32-bit FNV-1a, enough to tell schemas apart without a crypto dependency. */\nfunction fnv1a(text: string): string {\n let hash = 0x811c9dc5;\n for (let i = 0; i < text.length; i++) {\n hash ^= text.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\");\n}\n\n/**\n * Returns a stable signature for a ProseMirror schema: node names, content\n * expressions, groups, attribute names and mark names. Two editors with the\n * same extensions produce the same signature, so a slice copied from one can\n * be deserialized in the other without losing or rejecting nodes.\n */\nexport function getSchemaSignature(schema: Schema): string {\n const cached = signatureCache.get(schema);\n if (cached) return cached;\n const parts: string[] = [];\n for (const [name, type] of Object.entries(schema.nodes)) {\n const spec = type.spec;\n parts.push(\n `n:${name}|${spec.content ?? \"\"}|${spec.group ?? \"\"}|${spec.marks ?? \"\"}|${Object.keys(type.spec.attrs ?? {}).sort().join(\",\")}`,\n );\n }\n for (const [name, type] of Object.entries(schema.marks)) {\n parts.push(`m:${name}|${Object.keys(type.spec.attrs ?? {}).sort().join(\",\")}`);\n }\n const signature = `pm1-${fnv1a(parts.join(\";\"))}`;\n signatureCache.set(schema, signature);\n return signature;\n}\n\n/** Serializes a slice into the {@link PIXERATE_DOCUMENT_MIME} payload string. */\nexport function serializeRichClipboardPayload(slice: Slice, schema: Schema): string {\n const payload: RichClipboardPayload = {\n version: 1,\n schema: getSchemaSignature(schema),\n slice: slice.toJSON(),\n };\n return JSON.stringify(payload);\n}\n\n/**\n * Parses a {@link PIXERATE_DOCUMENT_MIME} payload into a slice for `schema`.\n * Returns `null` (so callers fall back to HTML / plain text) when the payload\n * is malformed, from another payload version, or from an editor whose schema\n * signature differs.\n */\nexport function parseRichClipboardPayload(data: string | null | undefined, schema: Schema): Slice | null {\n if (!data) return null;\n try {\n const payload = JSON.parse(data) as Partial<RichClipboardPayload>;\n if (!payload || payload.version !== 1) return null;\n if (payload.schema !== getSchemaSignature(schema)) return null;\n if (!payload.slice) return null;\n return Slice.fromJSON(schema, payload.slice as any);\n } catch {\n return null;\n }\n}\n\n/** Minimal clipboard data surface (`DataTransfer`). */\nexport interface ClipboardDataLike {\n getData(format: string): string;\n setData(format: string, data: string): void;\n clearData?(format?: string): void;\n}\n\n/**\n * Returns the `clipboardData` of a native `ClipboardEvent` or of a React\n * synthetic clipboard event (which wraps the native event in `nativeEvent`).\n */\nexport function getClipboardData(event: unknown): ClipboardDataLike | null {\n if (!event || typeof event !== \"object\") return null;\n const native = \"nativeEvent\" in event ? (event as any).nativeEvent : event;\n return ((event as any).clipboardData ?? native?.clipboardData ?? null) as ClipboardDataLike | null;\n}\n\n/**\n * Reads a slice from a paste event's {@link PIXERATE_DOCUMENT_MIME} data.\n * Returns `null` when the data is missing or its schema does not match.\n */\nexport function readRichClipboard(\n event: unknown,\n schema: Schema,\n mimeType: string = PIXERATE_DOCUMENT_MIME,\n): Slice | null {\n const data = getClipboardData(event);\n if (!data) return null;\n let raw: string | undefined;\n try {\n raw = data.getData(mimeType);\n } catch {\n return null;\n }\n return parseRichClipboardPayload(raw, schema);\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-SML64VJG.cjs","../src/serializers/html.ts","../src/serializers/rtf.ts","../src/serializers/clipboard.ts"],"names":[],"mappings":"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","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-SML64VJG.cjs","sourcesContent":[null,"import { sanitizeHtml } from \"./markdown\";\nimport { escapeHtml } from \"./plain-text\";\n\n/**\n * Elements whose content is never document text (scripts, styles, metadata,\n * embedded objects, form controls). They are removed together with their\n * content before sanitizing, so e.g. CSS rules don't show up as paragraphs.\n */\nconst DROP_WITH_CONTENT_REGEX =\n /<(script|style|template|noscript|iframe|object|embed|head|title|svg|math|textarea|select|button)\\b[^>]*>[\\s\\S]*?<\\/\\1\\s*>/gi;\n/** An unclosed `<script>` / `<style>` swallows the rest of the document. */\nconst UNCLOSED_RAW_TEXT_REGEX = /<(script|style)\\b[^>]*>[\\s\\S]*$/i;\nconst BODY_REGEX = /<body\\b[^>]*>([\\s\\S]*?)(?:<\\/body\\s*>|$)/i;\n/** Namespaced tags such as Word's `<o:p>`, which the sanitizer cannot parse. */\nconst NAMESPACED_TAG_REGEX = /<\\/?[a-zA-Z][\\w-]*:[\\w-]+\\b[^>]*>/g;\n\n/**\n * Sanitizes a full HTML document or fragment for insertion into the editor,\n * e.g. an imported `.html` file or HTML from another application.\n *\n * - Keeps only the `<body>` content when the input is a full document.\n * - Removes comments, doctype/XML declarations, CDATA, scripts, styles and\n * other non-text elements together with their content.\n * - Applies the same tag/attribute/URL allowlist as embedded HTML in markdown\n * (see `sanitizeHtml`), but strips disallowed tags instead of escaping them,\n * so wrappers such as `<section>` or `<font>` keep their text.\n *\n * It is string-based (no live DOM), so handlers such as `<img onerror>` never run.\n */\nexport function sanitizeImportedHtml(html: string): string {\n if (!html) return \"<p></p>\";\n let content = html.replace(/^/, \"\");\n content = content\n .replace(/<!--[\\s\\S]*?(?:-->|$)/g, \"\")\n .replace(/<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>|$)/g, \"\")\n .replace(/<![^>]*>/g, \"\")\n .replace(/<\\?[\\s\\S]*?(?:\\?>|$)/g, \"\");\n const body = BODY_REGEX.exec(content);\n if (body) content = body[1];\n content = content\n .replace(DROP_WITH_CONTENT_REGEX, \"\")\n .replace(UNCLOSED_RAW_TEXT_REGEX, \"\")\n .replace(NAMESPACED_TAG_REGEX, \"\");\n const sanitized = sanitizeHtml(content, { disallowedTags: \"strip\" }).trim();\n return sanitized || \"<p></p>\";\n}\n\n/**\n * Converts untrusted plain text to TipTap paragraph HTML, always escaping it.\n *\n * Unlike `plainTextToTipTapHtml`, text that already looks like `<p>…</p>` is\n * not passed through as HTML, which matters for imported files.\n */\nexport function plainTextToParagraphHtml(text: string): string {\n if (!text) return \"<p></p>\";\n return text\n .replace(/\\r\\n?/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => `<p>${escapeHtml(line)}</p>`)\n .join(\"\");\n}\n","/**\n * Destinations whose content is metadata or binary data rather than document\n * text. A group starting with one of these control words (or with `\\*`) is\n * skipped entirely.\n */\nconst SKIPPED_DESTINATIONS = new Set([\n \"author\", \"bkmkend\", \"bkmkstart\", \"colortbl\", \"comment\", \"datastore\",\n \"doccomm\", \"falt\", \"fldinst\", \"filetbl\", \"fonttbl\", \"footer\", \"footerf\",\n \"footerl\", \"footerr\", \"footnote\", \"generator\", \"header\", \"headerf\",\n \"headerl\", \"headerr\", \"info\", \"keywords\", \"latentstyles\", \"listoverridetable\",\n \"listtable\", \"nonshppict\", \"object\", \"operator\", \"pict\", \"private\", \"revtbl\",\n \"rsidtbl\", \"shppict\", \"stylesheet\", \"subject\", \"themedata\", \"title\",\n \"xmlnstbl\", \"colorschememapping\",\n]);\n\n/** Control words that map to a literal character. */\nconst CONTROL_WORD_TEXT: Record<string, string> = {\n par: \"\\n\",\n sect: \"\\n\",\n page: \"\\n\",\n line: \"\\n\",\n row: \"\\n\",\n cell: \"\\t\",\n tab: \"\\t\",\n emdash: \"—\",\n endash: \"–\",\n emspace: \" \",\n enspace: \" \",\n bullet: \"•\",\n lquote: \"‘\",\n rquote: \"’\",\n ldblquote: \"“\",\n rdblquote: \"”\",\n};\n\n/** Windows-1252 code points in 0x80–0x9F that differ from Latin-1. */\nconst CP1252: Record<number, string> = {\n 0x80: \"€\", 0x82: \"‚\", 0x83: \"ƒ\", 0x84: \"„\", 0x85: \"…\",\n 0x86: \"†\", 0x87: \"‡\", 0x88: \"ˆ\", 0x89: \"‰\", 0x8a: \"Š\",\n 0x8b: \"‹\", 0x8c: \"Œ\", 0x8e: \"Ž\", 0x91: \"‘\", 0x92: \"’\",\n 0x93: \"“\", 0x94: \"”\", 0x95: \"•\", 0x96: \"–\", 0x97: \"—\",\n 0x98: \"˜\", 0x99: \"™\", 0x9a: \"š\", 0x9b: \"›\", 0x9c: \"œ\",\n 0x9e: \"ž\", 0x9f: \"Ÿ\",\n};\n\nconst CONTROL_WORD_REGEX = /\\\\([a-zA-Z]{1,32})(-?\\d{1,10})? ?/y;\n\n/**\n * Best-effort plain-text extraction from an RTF document.\n *\n * Handles paragraphs/line breaks/tabs, escaped braces and backslashes,\n * `\\'hh` hex escapes (decoded as Windows-1252), `\\uN` Unicode escapes with\n * their `\\ucN` fallback characters, common typographic control words, and\n * skips metadata destinations (font/colour tables, `\\info`, pictures, field\n * instructions, `\\*` destinations). Formatting (bold, lists, tables) is not\n * preserved. Input that does not start with `{\\rtf` is returned unchanged.\n */\nexport function rtfToPlainText(rtf: string): string {\n if (!rtf) return \"\";\n if (!/^\\s*\\{\\\\rtf/.test(rtf)) return rtf;\n\n let out = \"\";\n const stack: Array<{ skip: boolean; uc: number }> = [];\n let skip = false;\n // Number of fallback characters that follow a \\uN escape.\n let uc = 1;\n let pendingFallback = 0;\n // True right after `{`, so a destination control word can mark the group.\n let groupStart = false;\n\n const emit = (text: string) => {\n if (skip) return;\n if (pendingFallback > 0) {\n pendingFallback--;\n return;\n }\n out += text;\n };\n\n let i = 0;\n while (i < rtf.length) {\n const ch = rtf[i];\n if (ch === \"{\") {\n stack.push({ skip, uc });\n groupStart = true;\n i++;\n continue;\n }\n if (ch === \"}\") {\n const prev = stack.pop();\n if (prev) {\n skip = prev.skip;\n uc = prev.uc;\n }\n pendingFallback = 0;\n groupStart = false;\n i++;\n continue;\n }\n const atGroupStart = groupStart;\n groupStart = false;\n\n if (ch === \"\\\\\") {\n const next = rtf[i + 1];\n if (next === \"\\\\\" || next === \"{\" || next === \"}\") {\n emit(next);\n i += 2;\n continue;\n }\n if (next === \"*\") {\n // `{\\*\\dest …}`: an ignorable destination this reader doesn't know.\n skip = true;\n i += 2;\n continue;\n }\n if (next === \"'\") {\n const code = parseInt(rtf.slice(i + 2, i + 4), 16);\n if (!Number.isNaN(code)) emit(CP1252[code] ?? String.fromCharCode(code));\n i += 4;\n continue;\n }\n if (next === \"~\") {\n emit(\" \");\n i += 2;\n continue;\n }\n if (next === \"_\") {\n emit(\"‑\");\n i += 2;\n continue;\n }\n if (next === \"\\n\" || next === \"\\r\") {\n emit(\"\\n\");\n i += 2;\n continue;\n }\n CONTROL_WORD_REGEX.lastIndex = i;\n const match = CONTROL_WORD_REGEX.exec(rtf);\n if (!match) {\n // Other control symbols (`\\-`, `\\|`, `\\:`) produce no text.\n i += 2;\n continue;\n }\n i = CONTROL_WORD_REGEX.lastIndex;\n const word = match[1];\n const param = match[2] !== undefined ? parseInt(match[2], 10) : undefined;\n if (atGroupStart && SKIPPED_DESTINATIONS.has(word)) {\n skip = true;\n } else if (word === \"u\" && param !== undefined) {\n emit(String.fromCharCode(param < 0 ? param + 65536 : param));\n if (!skip) pendingFallback = uc;\n } else if (word === \"uc\" && param !== undefined) {\n uc = param;\n } else if (word === \"bin\" && param !== undefined) {\n // Raw binary data: skip it.\n i += param;\n } else if (CONTROL_WORD_TEXT[word] !== undefined) {\n emit(CONTROL_WORD_TEXT[word]);\n }\n continue;\n }\n // Raw newlines are formatting in RTF; only control words break lines.\n if (ch === \"\\n\" || ch === \"\\r\") {\n i++;\n continue;\n }\n emit(ch);\n i++;\n }\n\n return out.replace(/\\n+$/, \"\");\n}\n","import { Slice, type Schema } from \"@tiptap/pm/model\";\n\n/**\n * Custom clipboard MIME type for content copied from a @pixerate/editor\n * rich-text editor. It carries the ProseMirror slice as JSON so pasting back\n * into a compatible editor is lossless (no HTML round trip).\n */\nexport const PIXERATE_DOCUMENT_MIME = \"application/x.pixerate.document+json\";\n\n/** Payload written under {@link PIXERATE_DOCUMENT_MIME}. */\nexport interface RichClipboardPayload {\n version: 1;\n /** {@link getSchemaSignature} of the source editor's schema. */\n schema: string;\n /** `Slice.toJSON()` of the copied selection. */\n slice: { content?: unknown[]; openStart?: number; openEnd?: number } | null;\n}\n\nconst signatureCache = new WeakMap<Schema, string>();\n\n/** 32-bit FNV-1a, enough to tell schemas apart without a crypto dependency. */\nfunction fnv1a(text: string): string {\n let hash = 0x811c9dc5;\n for (let i = 0; i < text.length; i++) {\n hash ^= text.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\");\n}\n\n/**\n * Returns a stable signature for a ProseMirror schema: node names, content\n * expressions, groups, attribute names and mark names. Two editors with the\n * same extensions produce the same signature, so a slice copied from one can\n * be deserialized in the other without losing or rejecting nodes.\n */\nexport function getSchemaSignature(schema: Schema): string {\n const cached = signatureCache.get(schema);\n if (cached) return cached;\n const parts: string[] = [];\n for (const [name, type] of Object.entries(schema.nodes)) {\n const spec = type.spec;\n parts.push(\n `n:${name}|${spec.content ?? \"\"}|${spec.group ?? \"\"}|${spec.marks ?? \"\"}|${Object.keys(type.spec.attrs ?? {}).sort().join(\",\")}`,\n );\n }\n for (const [name, type] of Object.entries(schema.marks)) {\n parts.push(`m:${name}|${Object.keys(type.spec.attrs ?? {}).sort().join(\",\")}`);\n }\n const signature = `pm1-${fnv1a(parts.join(\";\"))}`;\n signatureCache.set(schema, signature);\n return signature;\n}\n\n/** Serializes a slice into the {@link PIXERATE_DOCUMENT_MIME} payload string. */\nexport function serializeRichClipboardPayload(slice: Slice, schema: Schema): string {\n const payload: RichClipboardPayload = {\n version: 1,\n schema: getSchemaSignature(schema),\n slice: slice.toJSON(),\n };\n return JSON.stringify(payload);\n}\n\n/**\n * Parses a {@link PIXERATE_DOCUMENT_MIME} payload into a slice for `schema`.\n * Returns `null` (so callers fall back to HTML / plain text) when the payload\n * is malformed, from another payload version, or from an editor whose schema\n * signature differs.\n */\nexport function parseRichClipboardPayload(data: string | null | undefined, schema: Schema): Slice | null {\n if (!data) return null;\n try {\n const payload = JSON.parse(data) as Partial<RichClipboardPayload>;\n if (!payload || payload.version !== 1) return null;\n if (payload.schema !== getSchemaSignature(schema)) return null;\n if (!payload.slice) return null;\n return Slice.fromJSON(schema, payload.slice as any);\n } catch {\n return null;\n }\n}\n\n/** Minimal clipboard data surface (`DataTransfer`). */\nexport interface ClipboardDataLike {\n getData(format: string): string;\n setData(format: string, data: string): void;\n clearData?(format?: string): void;\n}\n\n/**\n * Returns the `clipboardData` of a native `ClipboardEvent` or of a React\n * synthetic clipboard event (which wraps the native event in `nativeEvent`).\n */\nexport function getClipboardData(event: unknown): ClipboardDataLike | null {\n if (!event || typeof event !== \"object\") return null;\n const native = \"nativeEvent\" in event ? (event as any).nativeEvent : event;\n return ((event as any).clipboardData ?? native?.clipboardData ?? null) as ClipboardDataLike | null;\n}\n\n/**\n * Reads a slice from a paste event's {@link PIXERATE_DOCUMENT_MIME} data.\n * Returns `null` when the data is missing or its schema does not match.\n */\nexport function readRichClipboard(\n event: unknown,\n schema: Schema,\n mimeType: string = PIXERATE_DOCUMENT_MIME,\n): Slice | null {\n const data = getClipboardData(event);\n if (!data) return null;\n let raw: string | undefined;\n try {\n raw = data.getData(mimeType);\n } catch {\n return null;\n }\n return parseRichClipboardPayload(raw, schema);\n}\n"]}
@@ -0,0 +1,115 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/spreadsheet/csv.ts
2
+ var BOM = "\uFEFF";
3
+ function parseCsv(text, options = {}) {
4
+ const delimiter = _nullishCoalesce(options.delimiter, () => ( ","));
5
+ if (delimiter.length !== 1 || delimiter === '"' || delimiter === "\n" || delimiter === "\r") {
6
+ throw new Error(`Invalid CSV delimiter: ${JSON.stringify(delimiter)}`);
7
+ }
8
+ const input = text.startsWith(BOM) ? text.slice(1) : text;
9
+ const records = [];
10
+ let record = [];
11
+ let field = "";
12
+ let i = 0;
13
+ let recordStarted = false;
14
+ const endField = () => {
15
+ record.push(field);
16
+ field = "";
17
+ };
18
+ const endRecord = () => {
19
+ endField();
20
+ records.push(record);
21
+ record = [];
22
+ recordStarted = false;
23
+ };
24
+ let atFieldStart = true;
25
+ while (i < input.length) {
26
+ const char = input[i];
27
+ if (char === '"' && atFieldStart) {
28
+ const quoted = readQuoted(input, i, delimiter);
29
+ if (quoted.wellFormed || !options.requireWellFormedQuotes) {
30
+ recordStarted = true;
31
+ atFieldStart = false;
32
+ field += quoted.value;
33
+ i = quoted.end;
34
+ continue;
35
+ }
36
+ }
37
+ if (char === delimiter) {
38
+ recordStarted = true;
39
+ endField();
40
+ atFieldStart = true;
41
+ i++;
42
+ continue;
43
+ }
44
+ if (char === "\r" || char === "\n") {
45
+ endRecord();
46
+ atFieldStart = true;
47
+ i += char === "\r" && input[i + 1] === "\n" ? 2 : 1;
48
+ continue;
49
+ }
50
+ recordStarted = true;
51
+ atFieldStart = false;
52
+ field += char;
53
+ i++;
54
+ }
55
+ if (recordStarted || field !== "" || record.length > 0) endRecord();
56
+ return records;
57
+ }
58
+ function readQuoted(input, start, delimiter) {
59
+ let value = "";
60
+ let i = start + 1;
61
+ while (i < input.length) {
62
+ if (input[i] === '"') {
63
+ if (input[i + 1] === '"') {
64
+ value += '"';
65
+ i += 2;
66
+ continue;
67
+ }
68
+ const next = input[i + 1];
69
+ const wellFormed = next === void 0 || next === delimiter || next === "\r" || next === "\n";
70
+ return { value, end: i + 1, wellFormed };
71
+ }
72
+ value += input[i];
73
+ i++;
74
+ }
75
+ return { value, end: i, wellFormed: false };
76
+ }
77
+ function escapeCsvField(value, delimiter = ",", quoteAll = false) {
78
+ if (quoteAll || value.includes(delimiter) || /["\r\n]/.test(value)) {
79
+ return `"${value.replace(/"/g, '""')}"`;
80
+ }
81
+ return value;
82
+ }
83
+ function serializeCsv(rows, options = {}) {
84
+ const delimiter = _nullishCoalesce(options.delimiter, () => ( ","));
85
+ const lineEnding = _nullishCoalesce(options.lineEnding, () => ( "\r\n"));
86
+ const body = rows.map(
87
+ (row) => row.map((value) => escapeCsvField(value == null ? "" : String(value), delimiter, options.quoteAll)).join(delimiter)
88
+ ).join(lineEnding);
89
+ return options.bom ? BOM + body : body;
90
+ }
91
+ function parseTsv(text) {
92
+ const normalized = text.startsWith(BOM) ? text.slice(1) : text;
93
+ if (!normalized.includes('"')) {
94
+ const body = normalized.replace(/\r\n?/g, "\n").replace(/\n$/, "");
95
+ return body === "" ? [] : body.split("\n").map((line) => line.split(" "));
96
+ }
97
+ return parseCsv(normalized, { delimiter: " ", requireWellFormedQuotes: true });
98
+ }
99
+ function serializeTsv(rows) {
100
+ return rows.map(
101
+ (row) => row.map((value) => {
102
+ const text = value == null ? "" : String(value);
103
+ return /[\t\r\n]/.test(text) || text.startsWith('"') ? `"${text.replace(/"/g, '""')}"` : text;
104
+ }).join(" ")
105
+ ).join("\n");
106
+ }
107
+
108
+
109
+
110
+
111
+
112
+
113
+
114
+ exports.parseCsv = parseCsv; exports.escapeCsvField = escapeCsvField; exports.serializeCsv = serializeCsv; exports.parseTsv = parseTsv; exports.serializeTsv = serializeTsv;
115
+ //# sourceMappingURL=chunk-TNNJXF46.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-TNNJXF46.cjs","../src/spreadsheet/csv.ts"],"names":[],"mappings":"AAAA;ACoCA,IAAM,IAAA,EAAM,QAAA;AAEL,SAAS,QAAA,CAAS,IAAA,EAAc,QAAA,EAA2B,CAAC,CAAA,EAAe;AAChF,EAAA,MAAM,UAAA,mBAAY,OAAA,CAAQ,SAAA,UAAa,KAAA;AACvC,EAAA,GAAA,CAAI,SAAA,CAAU,OAAA,IAAW,EAAA,GAAK,UAAA,IAAc,IAAA,GAAO,UAAA,IAAc,KAAA,GAAQ,UAAA,IAAc,IAAA,EAAM;AAC3F,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,uBAAA,EAA0B,IAAA,CAAK,SAAA,CAAU,SAAS,CAAC,CAAA,CAAA;AACrE,EAAA;AACqD,EAAA;AAExB,EAAA;AACL,EAAA;AACZ,EAAA;AACJ,EAAA;AAGY,EAAA;AAEG,EAAA;AACJ,IAAA;AACT,IAAA;AACV,EAAA;AACwB,EAAA;AACb,IAAA;AACU,IAAA;AACT,IAAA;AACM,IAAA;AAClB,EAAA;AAGmB,EAAA;AAEM,EAAA;AACH,IAAA;AAEc,IAAA;AACa,MAAA;AAEc,MAAA;AACzC,QAAA;AACD,QAAA;AACC,QAAA;AACL,QAAA;AACX,QAAA;AACF,MAAA;AACF,IAAA;AAEwB,IAAA;AACN,MAAA;AACP,MAAA;AACM,MAAA;AACf,MAAA;AACA,MAAA;AACF,IAAA;AAEoC,IAAA;AACxB,MAAA;AACK,MAAA;AACmC,MAAA;AAClD,MAAA;AACF,IAAA;AAEgB,IAAA;AACD,IAAA;AACN,IAAA;AACT,IAAA;AACF,EAAA;AAEkE,EAAA;AAC3D,EAAA;AACT;AAO0H;AAC5G,EAAA;AACI,EAAA;AACS,EAAA;AACD,IAAA;AACM,MAAA;AACf,QAAA;AACJ,QAAA;AACL,QAAA;AACF,MAAA;AACwB,MAAA;AACuC,MAAA;AACxB,MAAA;AACzC,IAAA;AACgB,IAAA;AAChB,IAAA;AACF,EAAA;AAC0C,EAAA;AAC5C;AAGyF;AACnB,EAAA;AAC9B,IAAA;AACtC,EAAA;AACO,EAAA;AACT;AAEqH;AAC5E,EAAA;AACE,EAAA;AAEtC,EAAA;AACwD,IAAA;AAEzC,EAAA;AACgB,EAAA;AACpC;AAQmD;AACS,EAAA;AAC3B,EAAA;AACoC,IAAA;AACG,IAAA;AACtE,EAAA;AAC+C,EAAA;AACjD;AAOkF;AAE7E,EAAA;AAEmB,IAAA;AACgC,MAAA;AACkB,MAAA;AAExD,IAAA;AAEJ,EAAA;AACd;AD5EwE;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-TNNJXF46.cjs","sourcesContent":[null,"/**\n * RFC 4180 CSV (and other delimiter-separated values) parsing and\n * serialization.\n *\n * - Fields may be quoted with `\"`; a quote inside a quoted field is written\n * as `\"\"`. Quoted fields may contain delimiters and line breaks.\n * - Records end at CRLF, LF or CR. A final line break does not add an empty\n * record.\n * - A leading UTF-8 byte order mark is ignored.\n * - The parser is lenient like spreadsheet apps: a quote inside an unquoted\n * field is kept as text, text after a closing quote is appended, and an\n * unterminated quoted field runs to the end of the input.\n */\n\nexport interface CsvParseOptions {\n /** Field separator. Default `,`. */\n delimiter?: string;\n /**\n * Only treat a leading `\"` as a quote when the quoted field is closed and\n * followed by a delimiter or line break; otherwise keep it as text. Used for\n * clipboard TSV, where plain text may legitimately start with a quote.\n */\n requireWellFormedQuotes?: boolean;\n}\n\nexport interface CsvSerializeOptions {\n /** Field separator. Default `,`. */\n delimiter?: string;\n /** Record separator. Default `\\r\\n` (RFC 4180). */\n lineEnding?: string;\n /** Prefix the output with a UTF-8 byte order mark (helps Excel detect UTF-8). */\n bom?: boolean;\n /** Quote every field, not only those that need it. */\n quoteAll?: boolean;\n}\n\nconst BOM = '';\n\nexport function parseCsv(text: string, options: CsvParseOptions = {}): string[][] {\n const delimiter = options.delimiter ?? ',';\n if (delimiter.length !== 1 || delimiter === '\"' || delimiter === '\\n' || delimiter === '\\r') {\n throw new Error(`Invalid CSV delimiter: ${JSON.stringify(delimiter)}`);\n }\n const input = text.startsWith(BOM) ? text.slice(1) : text;\n\n const records: string[][] = [];\n let record: string[] = [];\n let field = '';\n let i = 0;\n // True once the current record has any content (so a trailing newline does\n // not create an empty record, but an empty line in the middle does).\n let recordStarted = false;\n\n const endField = () => {\n record.push(field);\n field = '';\n };\n const endRecord = () => {\n endField();\n records.push(record);\n record = [];\n recordStarted = false;\n };\n\n // True at the first character of a field: only there does `\"` open a quote.\n let atFieldStart = true;\n\n while (i < input.length) {\n const char = input[i];\n\n if (char === '\"' && atFieldStart) {\n const quoted = readQuoted(input, i, delimiter);\n // Otherwise fall through and keep the quote as text.\n if (quoted.wellFormed || !options.requireWellFormedQuotes) {\n recordStarted = true;\n atFieldStart = false;\n field += quoted.value;\n i = quoted.end;\n continue;\n }\n }\n\n if (char === delimiter) {\n recordStarted = true;\n endField();\n atFieldStart = true;\n i++;\n continue;\n }\n\n if (char === '\\r' || char === '\\n') {\n endRecord();\n atFieldStart = true;\n i += char === '\\r' && input[i + 1] === '\\n' ? 2 : 1;\n continue;\n }\n\n recordStarted = true;\n atFieldStart = false;\n field += char;\n i++;\n }\n\n if (recordStarted || field !== '' || record.length > 0) endRecord();\n return records;\n}\n\n/**\n * Reads the quoted field opening at `start`. `end` is the index after the\n * closing quote (or the input length when unterminated); `wellFormed` means\n * it was closed and followed by a delimiter, line break or the end of input.\n */\nfunction readQuoted(input: string, start: number, delimiter: string): { value: string; end: number; wellFormed: boolean } {\n let value = '';\n let i = start + 1;\n while (i < input.length) {\n if (input[i] === '\"') {\n if (input[i + 1] === '\"') {\n value += '\"';\n i += 2;\n continue;\n }\n const next = input[i + 1];\n const wellFormed = next === undefined || next === delimiter || next === '\\r' || next === '\\n';\n return { value, end: i + 1, wellFormed };\n }\n value += input[i];\n i++;\n }\n return { value, end: i, wellFormed: false };\n}\n\n/** Quotes `value` when it contains the delimiter, a quote or a line break. */\nexport function escapeCsvField(value: string, delimiter = ',', quoteAll = false): string {\n if (quoteAll || value.includes(delimiter) || /[\"\\r\\n]/.test(value)) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n}\n\nexport function serializeCsv(rows: ReadonlyArray<ReadonlyArray<unknown>>, options: CsvSerializeOptions = {}): string {\n const delimiter = options.delimiter ?? ',';\n const lineEnding = options.lineEnding ?? '\\r\\n';\n const body = rows\n .map((row) =>\n row.map((value) => escapeCsvField(value == null ? '' : String(value), delimiter, options.quoteAll)).join(delimiter),\n )\n .join(lineEnding);\n return options.bom ? BOM + body : body;\n}\n\n/**\n * Parses tab-separated clipboard text as spreadsheet apps write it: cells\n * containing line breaks or tabs are quoted CSV-style. A field is only\n * treated as quoted when it starts with `\"` *and* its closing quote ends the\n * field, so plain text that happens to start with a quote is kept as is.\n */\nexport function parseTsv(text: string): string[][] {\n const normalized = text.startsWith(BOM) ? text.slice(1) : text;\n if (!normalized.includes('\"')) {\n const body = normalized.replace(/\\r\\n?/g, '\\n').replace(/\\n$/, '');\n return body === '' ? [] : body.split('\\n').map((line) => line.split('\\t'));\n }\n return parseCsv(normalized, { delimiter: '\\t', requireWellFormedQuotes: true });\n}\n\n/**\n * Serializes values as TSV for the clipboard. Fields containing a tab, line\n * break or a leading quote are quoted so `parseTsv` (and spreadsheet apps)\n * read them back as one cell.\n */\nexport function serializeTsv(rows: ReadonlyArray<ReadonlyArray<unknown>>): string {\n return rows\n .map((row) =>\n row\n .map((value) => {\n const text = value == null ? '' : String(value);\n return /[\\t\\r\\n]/.test(text) || text.startsWith('\"') ? `\"${text.replace(/\"/g, '\"\"')}\"` : text;\n })\n .join('\\t'),\n )\n .join('\\n');\n}\n"]}
@@ -0,0 +1,131 @@
1
+ // src/persistence/migrate.ts
2
+ function hasLoadProblems(report) {
3
+ return report.problems.length > 0 || report.readOnly !== null;
4
+ }
5
+ function createLoadReport(partial = {}) {
6
+ return {
7
+ migratedFrom: null,
8
+ version: null,
9
+ problems: [],
10
+ readOnly: null,
11
+ unknownKeys: [],
12
+ ...partial
13
+ };
14
+ }
15
+ var isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
16
+ var deepClone = (value) => typeof structuredClone === "function" ? structuredClone(value) : JSON.parse(JSON.stringify(value));
17
+ function toObject(json) {
18
+ let value = json;
19
+ if (typeof json === "string") {
20
+ try {
21
+ value = JSON.parse(json);
22
+ } catch {
23
+ return void 0;
24
+ }
25
+ }
26
+ return isObject(value) ? deepClone(value) : void 0;
27
+ }
28
+ function migrateDocument(json, options) {
29
+ const versionKey = options.versionKey ?? "version";
30
+ const target = options.currentVersion;
31
+ const original = toObject(json);
32
+ if (!original) {
33
+ return {
34
+ doc: { [versionKey]: target },
35
+ report: createLoadReport({
36
+ readOnly: { kind: "invalid", message: "document is not a JSON object" }
37
+ })
38
+ };
39
+ }
40
+ const raw = original[versionKey];
41
+ const found = typeof raw === "number" && Number.isInteger(raw) && raw >= 0 ? raw : null;
42
+ const from = found ?? options.missingVersion ?? target;
43
+ const report = createLoadReport({ version: found });
44
+ if (from > target) {
45
+ report.readOnly = {
46
+ kind: "newerVersion",
47
+ version: from,
48
+ supported: target,
49
+ message: `document has version ${from}, newer than the supported ${target}`
50
+ };
51
+ return { doc: original, report };
52
+ }
53
+ if (from === target) {
54
+ original[versionKey] = target;
55
+ return { doc: original, report };
56
+ }
57
+ let doc = deepClone(original);
58
+ for (let step = from; step < target; step++) {
59
+ const fn = options.steps?.[step];
60
+ if (!fn) {
61
+ report.readOnly = {
62
+ kind: "migrationFailed",
63
+ from: step,
64
+ message: `no migration step from version ${step}`
65
+ };
66
+ return { doc: original, report };
67
+ }
68
+ try {
69
+ doc = fn(doc) ?? doc;
70
+ } catch (error) {
71
+ report.readOnly = {
72
+ kind: "migrationFailed",
73
+ from: step,
74
+ message: `migration from version ${step} failed: ${error instanceof Error ? error.message : String(error)}`
75
+ };
76
+ return { doc: original, report };
77
+ }
78
+ doc[versionKey] = step + 1;
79
+ }
80
+ report.migratedFrom = from;
81
+ return { doc, report };
82
+ }
83
+ function loadSections(doc, sections, options = {}) {
84
+ const source = isObject(doc) ? doc : {};
85
+ const ignore = new Set(options.ignore ?? ["version"]);
86
+ const value = {};
87
+ const problems = [];
88
+ for (const key of Object.keys(sections)) {
89
+ const spec = sections[key];
90
+ const fallback = () => typeof spec.defaults === "function" ? spec.defaults() : spec.defaults;
91
+ if (!Object.prototype.hasOwnProperty.call(source, key)) {
92
+ value[key] = fallback();
93
+ continue;
94
+ }
95
+ try {
96
+ const parsed = spec.parse(source[key]);
97
+ if (parsed === void 0) throw new Error("invalid value");
98
+ value[key] = parsed;
99
+ } catch (error) {
100
+ problems.push({
101
+ section: key,
102
+ message: error instanceof Error ? error.message : String(error)
103
+ });
104
+ value[key] = fallback();
105
+ }
106
+ }
107
+ const unknown = {};
108
+ for (const key of Object.keys(source)) {
109
+ if (!(key in sections) && !ignore.has(key)) unknown[key] = source[key];
110
+ }
111
+ return { value, problems, unknown };
112
+ }
113
+ function loadDocument(json, sections, options) {
114
+ const { doc, report } = migrateDocument(json, options);
115
+ const ignore = options.ignore ?? [options.versionKey ?? "version"];
116
+ const result = loadSections(report.readOnly?.kind === "invalid" ? {} : doc, sections, {
117
+ ignore
118
+ });
119
+ report.problems = result.problems;
120
+ report.unknownKeys = Object.keys(result.unknown);
121
+ return { ...result, report };
122
+ }
123
+
124
+ export {
125
+ hasLoadProblems,
126
+ createLoadReport,
127
+ migrateDocument,
128
+ loadSections,
129
+ loadDocument
130
+ };
131
+ //# sourceMappingURL=chunk-U5HZSFCS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/persistence/migrate.ts"],"sourcesContent":["// Portions ported from craft-libs-main/crates/settings/src/migrate.rs, src/document.rs and\n// src/error.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/** A section whose stored value did not fit; its defaults were used instead. */\nexport interface SectionProblem {\n /** Top-level key of the section. */\n section: string;\n message: string;\n}\n\n/** Why a loaded document must not be written back. */\nexport type ReadOnlyReason =\n | { kind: \"newerVersion\"; version: number; supported: number; message: string }\n | { kind: \"migrationFailed\"; from: number; message: string }\n | { kind: \"invalid\"; message: string };\n\n/** What happened while loading a document. Nothing in here is fatal. */\nexport interface LoadReport {\n /** Set when the document was upgraded step by step from this older version. */\n migratedFrom: number | null;\n /** The version found in the input (`null` when it had none). */\n version: number | null;\n /** Sections replaced by their defaults (see `loadSections`). */\n problems: SectionProblem[];\n /**\n * Set when the document must not be saved over: written by a newer build,\n * a migration step failed, or the input was not an object. Show the values,\n * but never overwrite the stored document.\n */\n readOnly: ReadOnlyReason | null;\n /** Top-level keys this build does not know; kept in `unknown` so a save can write them back. */\n unknownKeys: string[];\n}\n\n/** True when something should be shown to the user. */\nexport function hasLoadProblems(report: LoadReport): boolean {\n return report.problems.length > 0 || report.readOnly !== null;\n}\n\nexport function createLoadReport(partial: Partial<LoadReport> = {}): LoadReport {\n return {\n migratedFrom: null,\n version: null,\n problems: [],\n readOnly: null,\n unknownKeys: [],\n ...partial,\n };\n}\n\nexport type JsonObject = Record<string, unknown>;\n\n/** One migration step: turns a document at version `from` into version `from + 1`. */\nexport type MigrationStep = (doc: JsonObject) => JsonObject | void;\n\nexport interface MigrateOptions {\n /** The version this build writes. */\n currentVersion: number;\n /** Steps keyed by the version they start from. */\n steps?: Record<number, MigrationStep>;\n /** Key holding the version (default `\"version\"`). */\n versionKey?: string;\n /**\n * Version assumed when the key is missing (default: `currentVersion`, i.e. a\n * hand-written document is taken as current and the key is added).\n */\n missingVersion?: number;\n}\n\nexport interface MigrateResult {\n /** The migrated document (a deep copy; the input is never modified). */\n doc: JsonObject;\n report: LoadReport;\n}\n\nconst isObject = (value: unknown): value is JsonObject =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst deepClone = <T>(value: T): T =>\n typeof structuredClone === \"function\"\n ? structuredClone(value)\n : (JSON.parse(JSON.stringify(value)) as T);\n\n/** Parses a JSON string, or deep-copies an object. `undefined` when it is not an object. */\nfunction toObject(json: unknown): JsonObject | undefined {\n let value = json;\n if (typeof json === \"string\") {\n try {\n value = JSON.parse(json);\n } catch {\n return undefined;\n }\n }\n return isObject(value) ? deepClone(value) : undefined;\n}\n\n/**\n * Brings a stored document up to `currentVersion` by running one step per\n * version (`steps[v]` turns version `v` into `v + 1`).\n *\n * - Missing version: taken as `missingVersion` (default current); the key is added.\n * - Newer than `currentVersion`: left alone and reported `readOnly` (never overwrite\n * a file written by a newer build).\n * - A missing or throwing step: the document is returned as it was before\n * migrating and reported `readOnly`.\n * - Keys the steps do not touch are preserved.\n */\nexport function migrateDocument(json: unknown, options: MigrateOptions): MigrateResult {\n const versionKey = options.versionKey ?? \"version\";\n const target = options.currentVersion;\n const original = toObject(json);\n if (!original) {\n return {\n doc: { [versionKey]: target },\n report: createLoadReport({\n readOnly: { kind: \"invalid\", message: \"document is not a JSON object\" },\n }),\n };\n }\n const raw = original[versionKey];\n const found = typeof raw === \"number\" && Number.isInteger(raw) && raw >= 0 ? raw : null;\n const from = found ?? options.missingVersion ?? target;\n const report = createLoadReport({ version: found });\n\n if (from > target) {\n report.readOnly = {\n kind: \"newerVersion\",\n version: from,\n supported: target,\n message: `document has version ${from}, newer than the supported ${target}`,\n };\n return { doc: original, report };\n }\n if (from === target) {\n original[versionKey] = target;\n return { doc: original, report };\n }\n\n let doc = deepClone(original);\n for (let step = from; step < target; step++) {\n const fn = options.steps?.[step];\n if (!fn) {\n report.readOnly = {\n kind: \"migrationFailed\",\n from: step,\n message: `no migration step from version ${step}`,\n };\n return { doc: original, report };\n }\n try {\n doc = fn(doc) ?? doc;\n } catch (error) {\n report.readOnly = {\n kind: \"migrationFailed\",\n from: step,\n message: `migration from version ${step} failed: ${\n error instanceof Error ? error.message : String(error)\n }`,\n };\n // Never hand back half-migrated values.\n return { doc: original, report };\n }\n doc[versionKey] = step + 1;\n }\n report.migratedFrom = from;\n return { doc, report };\n}\n\n/** How one top-level section is read. */\nexport interface SectionSpec<V> {\n /** Validates / converts the stored value; throw (or return `undefined`) to reject it. */\n parse: (value: unknown) => V | undefined;\n /** Used when the section is missing or rejected. */\n defaults: V | (() => V);\n}\n\nexport type SectionSpecs<T> = { [K in keyof T]: SectionSpec<T[K]> };\n\nexport interface LoadSectionsOptions {\n /** Keys that are neither sections nor unknown (default `[\"version\"]`). */\n ignore?: string[];\n}\n\nexport interface LoadSectionsResult<T> {\n value: T;\n /** Sections that were present but rejected (missing ones are not problems). */\n problems: SectionProblem[];\n /** Top-level keys not described by `sections`; write them back to keep them. */\n unknown: JsonObject;\n}\n\n/**\n * Reads `doc` one top-level section at a time: a section that does not parse\n * is reported and replaced by its defaults, every other section is kept. This\n * keeps one bad value (e.g. a renamed enum) from resetting the whole document.\n */\nexport function loadSections<T>(\n doc: unknown,\n sections: SectionSpecs<T>,\n options: LoadSectionsOptions = {},\n): LoadSectionsResult<T> {\n const source = isObject(doc) ? doc : {};\n const ignore = new Set(options.ignore ?? [\"version\"]);\n const value = {} as T;\n const problems: SectionProblem[] = [];\n for (const key of Object.keys(sections) as (keyof T & string)[]) {\n const spec = sections[key];\n const fallback = () =>\n typeof spec.defaults === \"function\"\n ? (spec.defaults as () => T[typeof key])()\n : spec.defaults;\n if (!Object.prototype.hasOwnProperty.call(source, key)) {\n value[key] = fallback();\n continue;\n }\n try {\n const parsed = spec.parse(source[key]);\n if (parsed === undefined) throw new Error(\"invalid value\");\n value[key] = parsed;\n } catch (error) {\n problems.push({\n section: key,\n message: error instanceof Error ? error.message : String(error),\n });\n value[key] = fallback();\n }\n }\n const unknown: JsonObject = {};\n for (const key of Object.keys(source)) {\n if (!(key in sections) && !ignore.has(key)) unknown[key] = source[key];\n }\n return { value, problems, unknown };\n}\n\nexport interface LoadDocumentOptions extends MigrateOptions, LoadSectionsOptions {}\n\nexport interface LoadDocumentResult<T> extends LoadSectionsResult<T> {\n report: LoadReport;\n}\n\n/**\n * `migrateDocument` followed by `loadSections`, with one `LoadReport`\n * (`problems` and `unknownKeys` filled in).\n */\nexport function loadDocument<T>(\n json: unknown,\n sections: SectionSpecs<T>,\n options: LoadDocumentOptions,\n): LoadDocumentResult<T> {\n const { doc, report } = migrateDocument(json, options);\n const ignore = options.ignore ?? [options.versionKey ?? \"version\"];\n const result = loadSections(report.readOnly?.kind === \"invalid\" ? {} : doc, sections, {\n ignore,\n });\n report.problems = result.problems;\n report.unknownKeys = Object.keys(result.unknown);\n return { ...result, report };\n}\n"],"mappings":"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","names":[]}