@pixerate/editor 0.23.0 → 0.25.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 (187) hide show
  1. package/README.md +167 -2
  2. package/THIRD_PARTY_NOTICES.md +80 -0
  3. package/dist/agent/index.cjs +10 -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 +4 -2
  8. package/dist/agent/index.js.map +1 -1
  9. package/dist/canvas/index.cjs +4437 -411
  10. package/dist/canvas/index.cjs.map +1 -1
  11. package/dist/canvas/index.d.cts +934 -4
  12. package/dist/canvas/index.d.ts +934 -4
  13. package/dist/canvas/index.js +4309 -283
  14. package/dist/canvas/index.js.map +1 -1
  15. package/dist/chunk-4BVP64JJ.cjs +1406 -0
  16. package/dist/chunk-4BVP64JJ.cjs.map +1 -0
  17. package/dist/chunk-664LQYFJ.js +115 -0
  18. package/dist/chunk-664LQYFJ.js.map +1 -0
  19. package/dist/chunk-7WISYZFO.cjs +740 -0
  20. package/dist/chunk-7WISYZFO.cjs.map +1 -0
  21. package/dist/chunk-AL6JMGWW.cjs +783 -0
  22. package/dist/chunk-AL6JMGWW.cjs.map +1 -0
  23. package/dist/chunk-BVP3TSLH.cjs +69 -0
  24. package/dist/chunk-BVP3TSLH.cjs.map +1 -0
  25. package/dist/{chunk-RIKBJLS2.cjs → chunk-C7P22VIP.cjs} +2001 -279
  26. package/dist/chunk-C7P22VIP.cjs.map +1 -0
  27. package/dist/chunk-D6FH2YAX.cjs +131 -0
  28. package/dist/chunk-D6FH2YAX.cjs.map +1 -0
  29. package/dist/chunk-ECCCYKGL.js +740 -0
  30. package/dist/chunk-ECCCYKGL.js.map +1 -0
  31. package/dist/{chunk-4SUNJZWB.cjs → chunk-FD4LPFAE.cjs} +48 -200
  32. package/dist/chunk-FD4LPFAE.cjs.map +1 -0
  33. package/dist/{chunk-QBJ22YZR.js → chunk-FH6F67DN.js} +1999 -277
  34. package/dist/chunk-FH6F67DN.js.map +1 -0
  35. package/dist/{chunk-OYXSKQFR.js → chunk-FPENXAEJ.js} +35 -187
  36. package/dist/chunk-FPENXAEJ.js.map +1 -0
  37. package/dist/chunk-HLIMTC6N.js +1 -0
  38. package/dist/chunk-HLIMTC6N.js.map +1 -0
  39. package/dist/chunk-HRMEDT2L.js +1406 -0
  40. package/dist/chunk-HRMEDT2L.js.map +1 -0
  41. package/dist/{chunk-QGHGJ56O.js → chunk-IXHSYOVY.js} +2518 -122
  42. package/dist/chunk-IXHSYOVY.js.map +1 -0
  43. package/dist/chunk-MKA3AHLV.cjs +256 -0
  44. package/dist/chunk-MKA3AHLV.cjs.map +1 -0
  45. package/dist/chunk-NAXVVS5I.js +783 -0
  46. package/dist/chunk-NAXVVS5I.js.map +1 -0
  47. package/dist/chunk-O5RYH2PG.js +69 -0
  48. package/dist/chunk-O5RYH2PG.js.map +1 -0
  49. package/dist/chunk-OXSV64JX.js +689 -0
  50. package/dist/chunk-OXSV64JX.js.map +1 -0
  51. package/dist/chunk-P3RQ5UJE.cjs +689 -0
  52. package/dist/chunk-P3RQ5UJE.cjs.map +1 -0
  53. package/dist/chunk-P6ODPZ4W.js +256 -0
  54. package/dist/chunk-P6ODPZ4W.js.map +1 -0
  55. package/dist/chunk-PL4JB3BF.cjs +1 -0
  56. package/dist/chunk-PL4JB3BF.cjs.map +1 -0
  57. package/dist/{chunk-GVSMRPHB.cjs → chunk-PO6A6QQH.cjs} +2607 -211
  58. package/dist/chunk-PO6A6QQH.cjs.map +1 -0
  59. package/dist/{chunk-JJDLPEWL.js → chunk-QGYDWPRM.js} +2 -2
  60. package/dist/chunk-RR7F5GUM.js +5726 -0
  61. package/dist/chunk-RR7F5GUM.js.map +1 -0
  62. package/dist/chunk-TNNJXF46.cjs +115 -0
  63. package/dist/chunk-TNNJXF46.cjs.map +1 -0
  64. package/dist/chunk-U5HZSFCS.js +131 -0
  65. package/dist/chunk-U5HZSFCS.js.map +1 -0
  66. package/dist/{chunk-MJZBNWG7.js → chunk-UAKDG62Z.js} +309 -581
  67. package/dist/chunk-UAKDG62Z.js.map +1 -0
  68. package/dist/{chunk-CL37JGFW.cjs → chunk-V3CHHWOE.cjs} +4 -4
  69. package/dist/{chunk-CL37JGFW.cjs.map → chunk-V3CHHWOE.cjs.map} +1 -1
  70. package/dist/chunk-WSQKHXW7.cjs +5726 -0
  71. package/dist/chunk-WSQKHXW7.cjs.map +1 -0
  72. package/dist/{chunk-AA4ZEVCC.cjs → chunk-X4N4WUKB.cjs} +336 -608
  73. package/dist/chunk-X4N4WUKB.cjs.map +1 -0
  74. package/dist/commands/index.cjs +74 -1
  75. package/dist/commands/index.cjs.map +1 -1
  76. package/dist/commands/index.d.cts +38 -353
  77. package/dist/commands/index.d.ts +38 -353
  78. package/dist/commands/index.js +73 -0
  79. package/dist/commands/index.js.map +1 -1
  80. package/dist/comment-store-BEMgVlAA.d.cts +135 -0
  81. package/dist/comment-store-BEMgVlAA.d.ts +135 -0
  82. package/dist/compare/index.cjs +15 -0
  83. package/dist/compare/index.cjs.map +1 -0
  84. package/dist/compare/index.d.cts +58 -0
  85. package/dist/compare/index.d.ts +58 -0
  86. package/dist/compare/index.js +15 -0
  87. package/dist/compare/index.js.map +1 -0
  88. package/dist/controller-BIJiNoVs.d.cts +1842 -0
  89. package/dist/controller-BIJiNoVs.d.ts +1842 -0
  90. package/dist/documents-CHT1U5Vs.d.ts +86 -0
  91. package/dist/documents-Gp7wb0Me.d.cts +86 -0
  92. package/dist/extensions/index.cjs +100 -5
  93. package/dist/extensions/index.cjs.map +1 -1
  94. package/dist/extensions/index.d.cts +16 -4
  95. package/dist/extensions/index.d.ts +16 -4
  96. package/dist/extensions/index.js +100 -5
  97. package/dist/generation/index.cjs +2317 -0
  98. package/dist/generation/index.cjs.map +1 -0
  99. package/dist/generation/index.d.cts +1015 -0
  100. package/dist/generation/index.d.ts +1015 -0
  101. package/dist/generation/index.js +2317 -0
  102. package/dist/generation/index.js.map +1 -0
  103. package/dist/grammar/index.cjs +48 -3
  104. package/dist/grammar/index.cjs.map +1 -1
  105. package/dist/grammar/index.d.cts +322 -100
  106. package/dist/grammar/index.d.ts +322 -100
  107. package/dist/grammar/index.js +54 -9
  108. package/dist/image-editor/index.cjs +4392 -481
  109. package/dist/image-editor/index.cjs.map +1 -1
  110. package/dist/image-editor/index.d.cts +1249 -97
  111. package/dist/image-editor/index.d.ts +1249 -97
  112. package/dist/image-editor/index.js +4281 -370
  113. package/dist/image-editor/index.js.map +1 -1
  114. package/dist/index-7a6bHTLy.d.ts +1754 -0
  115. package/dist/index-Csd5qI8u.d.cts +1754 -0
  116. package/dist/index.cjs +1682 -99
  117. package/dist/index.cjs.map +1 -1
  118. package/dist/index.d.cts +118 -21
  119. package/dist/index.d.ts +118 -21
  120. package/dist/index.js +1630 -47
  121. package/dist/index.js.map +1 -1
  122. package/dist/mention-text-CDnCFd3c.d.cts +53 -0
  123. package/dist/mention-text-CDnCFd3c.d.ts +53 -0
  124. package/dist/migrate-iTlm3a8h.d.cts +112 -0
  125. package/dist/migrate-iTlm3a8h.d.ts +112 -0
  126. package/dist/model-C1zApQM8.d.cts +219 -0
  127. package/dist/model-C1zApQM8.d.ts +219 -0
  128. package/dist/persistence/index.cjs +676 -0
  129. package/dist/persistence/index.cjs.map +1 -0
  130. package/dist/persistence/index.d.cts +230 -0
  131. package/dist/persistence/index.d.ts +230 -0
  132. package/dist/persistence/index.js +676 -0
  133. package/dist/persistence/index.js.map +1 -0
  134. package/dist/{registry-D5-R90p0.d.cts → registry-BDe-vlv3.d.ts} +2 -40
  135. package/dist/{registry-GJI4gToU.d.ts → registry-CEgwXED1.d.cts} +12 -1
  136. package/dist/{registry-GJI4gToU.d.cts → registry-CEgwXED1.d.ts} +12 -1
  137. package/dist/registry-D32LpIc4.d.cts +354 -0
  138. package/dist/{registry-D5-R90p0.d.ts → registry-DnzpgY27.d.cts} +2 -40
  139. package/dist/registry-evKTP4ls.d.ts +354 -0
  140. package/dist/schema-DYDGdYL9.d.cts +41 -0
  141. package/dist/schema-DYDGdYL9.d.ts +41 -0
  142. package/dist/serializers/index.cjs +12 -3
  143. package/dist/serializers/index.cjs.map +1 -1
  144. package/dist/serializers/index.d.cts +40 -12
  145. package/dist/serializers/index.d.ts +40 -12
  146. package/dist/serializers/index.js +12 -3
  147. package/dist/sourcemap-C8AH3MBQ.d.cts +91 -0
  148. package/dist/sourcemap-DA1Evhrv.d.ts +91 -0
  149. package/dist/spreadsheet/index.cjs +161 -3
  150. package/dist/spreadsheet/index.cjs.map +1 -1
  151. package/dist/spreadsheet/index.d.cts +611 -20
  152. package/dist/spreadsheet/index.d.ts +611 -20
  153. package/dist/spreadsheet/index.js +168 -10
  154. package/dist/storage-BpFfspHm.d.cts +120 -0
  155. package/dist/storage-BpFfspHm.d.ts +120 -0
  156. package/dist/tokens/index.cjs +115 -0
  157. package/dist/tokens/index.cjs.map +1 -0
  158. package/dist/tokens/index.d.cts +212 -0
  159. package/dist/tokens/index.d.ts +212 -0
  160. package/dist/tokens/index.js +115 -0
  161. package/dist/tokens/index.js.map +1 -0
  162. package/dist/{tokens-CyLZmIei.d.cts → tokens-D7yXvUU6.d.cts} +15 -2
  163. package/dist/{tokens-CyLZmIei.d.ts → tokens-D7yXvUU6.d.ts} +15 -2
  164. package/dist/{track-changes-BSF58RK0.d.cts → track-changes-D_VAPELi.d.cts} +110 -144
  165. package/dist/{track-changes-BSF58RK0.d.ts → track-changes-Db_fGEvx.d.ts} +110 -144
  166. package/package.json +21 -1
  167. package/dist/chunk-4SUNJZWB.cjs.map +0 -1
  168. package/dist/chunk-AA4ZEVCC.cjs.map +0 -1
  169. package/dist/chunk-AXV2ZW34.cjs +0 -118
  170. package/dist/chunk-AXV2ZW34.cjs.map +0 -1
  171. package/dist/chunk-B2ZRLN4S.js +0 -118
  172. package/dist/chunk-B2ZRLN4S.js.map +0 -1
  173. package/dist/chunk-GVSMRPHB.cjs.map +0 -1
  174. package/dist/chunk-K3R5NG2D.js +0 -3100
  175. package/dist/chunk-K3R5NG2D.js.map +0 -1
  176. package/dist/chunk-MJZBNWG7.js.map +0 -1
  177. package/dist/chunk-OYXSKQFR.js.map +0 -1
  178. package/dist/chunk-QBJ22YZR.js.map +0 -1
  179. package/dist/chunk-QGHGJ56O.js.map +0 -1
  180. package/dist/chunk-RIKBJLS2.cjs.map +0 -1
  181. package/dist/chunk-XDMXXC4Z.cjs +0 -3100
  182. package/dist/chunk-XDMXXC4Z.cjs.map +0 -1
  183. package/dist/controller-pePCJLT1.d.cts +0 -959
  184. package/dist/controller-pePCJLT1.d.ts +0 -959
  185. package/dist/index-CCr_z9kF.d.cts +0 -899
  186. package/dist/index-Ck6ajwXh.d.ts +0 -899
  187. /package/dist/{chunk-JJDLPEWL.js.map → chunk-QGYDWPRM.js.map} +0 -0
@@ -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":[]}