@unisim/doc 0.1.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 (90) hide show
  1. package/README.md +91 -0
  2. package/dist/convert.d.ts +54 -0
  3. package/dist/convert.d.ts.map +1 -0
  4. package/dist/convert.js +216 -0
  5. package/dist/convert.js.map +1 -0
  6. package/dist/image.d.ts +17 -0
  7. package/dist/image.d.ts.map +1 -0
  8. package/dist/image.js +66 -0
  9. package/dist/image.js.map +1 -0
  10. package/dist/index.d.ts +10 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +51 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/merge.d.ts +14 -0
  15. package/dist/merge.d.ts.map +1 -0
  16. package/dist/merge.js +51 -0
  17. package/dist/merge.js.map +1 -0
  18. package/dist/metrics.d.ts +19 -0
  19. package/dist/metrics.d.ts.map +1 -0
  20. package/dist/metrics.js +151 -0
  21. package/dist/metrics.js.map +1 -0
  22. package/dist/model.d.ts +114 -0
  23. package/dist/model.d.ts.map +1 -0
  24. package/dist/model.js +121 -0
  25. package/dist/model.js.map +1 -0
  26. package/dist/pdfcore.d.ts +118 -0
  27. package/dist/pdfcore.d.ts.map +1 -0
  28. package/dist/pdfcore.js +398 -0
  29. package/dist/pdfcore.js.map +1 -0
  30. package/dist/read/csv.d.ts +17 -0
  31. package/dist/read/csv.d.ts.map +1 -0
  32. package/dist/read/csv.js +167 -0
  33. package/dist/read/csv.js.map +1 -0
  34. package/dist/read/doc.d.ts +3 -0
  35. package/dist/read/doc.d.ts.map +1 -0
  36. package/dist/read/doc.js +360 -0
  37. package/dist/read/doc.js.map +1 -0
  38. package/dist/read/docx.d.ts +3 -0
  39. package/dist/read/docx.d.ts.map +1 -0
  40. package/dist/read/docx.js +455 -0
  41. package/dist/read/docx.js.map +1 -0
  42. package/dist/read/html.d.ts +4 -0
  43. package/dist/read/html.d.ts.map +1 -0
  44. package/dist/read/html.js +236 -0
  45. package/dist/read/html.js.map +1 -0
  46. package/dist/read/json.d.ts +9 -0
  47. package/dist/read/json.d.ts.map +1 -0
  48. package/dist/read/json.js +105 -0
  49. package/dist/read/json.js.map +1 -0
  50. package/dist/read/markdown.d.ts +4 -0
  51. package/dist/read/markdown.d.ts.map +1 -0
  52. package/dist/read/markdown.js +247 -0
  53. package/dist/read/markdown.js.map +1 -0
  54. package/dist/read/odt.d.ts +3 -0
  55. package/dist/read/odt.d.ts.map +1 -0
  56. package/dist/read/odt.js +359 -0
  57. package/dist/read/odt.js.map +1 -0
  58. package/dist/read/rtf.d.ts +3 -0
  59. package/dist/read/rtf.d.ts.map +1 -0
  60. package/dist/read/rtf.js +341 -0
  61. package/dist/read/rtf.js.map +1 -0
  62. package/dist/read/text.d.ts +4 -0
  63. package/dist/read/text.d.ts.map +1 -0
  64. package/dist/read/text.js +62 -0
  65. package/dist/read/text.js.map +1 -0
  66. package/dist/unzip.d.ts +23 -0
  67. package/dist/unzip.d.ts.map +1 -0
  68. package/dist/unzip.js +152 -0
  69. package/dist/unzip.js.map +1 -0
  70. package/dist/write/data.d.ts +16 -0
  71. package/dist/write/data.d.ts.map +1 -0
  72. package/dist/write/data.js +89 -0
  73. package/dist/write/data.js.map +1 -0
  74. package/dist/write/pdf.d.ts +10 -0
  75. package/dist/write/pdf.d.ts.map +1 -0
  76. package/dist/write/pdf.js +696 -0
  77. package/dist/write/pdf.js.map +1 -0
  78. package/dist/write/pdfSettings.d.ts +13 -0
  79. package/dist/write/pdfSettings.d.ts.map +1 -0
  80. package/dist/write/pdfSettings.js +26 -0
  81. package/dist/write/pdfSettings.js.map +1 -0
  82. package/dist/write/text.d.ts +5 -0
  83. package/dist/write/text.d.ts.map +1 -0
  84. package/dist/write/text.js +341 -0
  85. package/dist/write/text.js.map +1 -0
  86. package/dist/xml.d.ts +22 -0
  87. package/dist/xml.d.ts.map +1 -0
  88. package/dist/xml.js +83 -0
  89. package/dist/xml.js.map +1 -0
  90. package/package.json +31 -0
@@ -0,0 +1,341 @@
1
+ // ---------------------------------------------------------------------------
2
+ // RTF → RichDoc.
3
+ //
4
+ // RTF is a text format with braces, which makes it look far more tractable than
5
+ // the binary .doc — and it mostly is. A tokeniser over `\control`, `{group}`
6
+ // and literal text gets bold, italic, underline, paragraphs and headings, which
7
+ // is most of what a converted document needs.
8
+ //
9
+ // THREE THINGS THAT ARE NOT OBVIOUS AND BREAK IT IF MISSED
10
+ // --------------------------------------------------------
11
+ // * FORMATTING IS SCOPED TO THE GROUP. `{\b bold}` ends when the brace does,
12
+ // so state has to be pushed and popped with the braces rather than tracked
13
+ // flat. Flat tracking makes one stray `\b` bold the rest of the document.
14
+ // * `\'xx` IS A BYTE, NOT A CHARACTER, and which character it is depends on
15
+ // the document's codepage (`\ansicpg1252`). Bytes are collected and decoded
16
+ // as a group so a multi-byte sequence survives.
17
+ // * DESTINATIONS MUST BE SKIPPED. `{\fonttbl…}`, `{\colortbl…}`, `{\*\…}` and
18
+ // `{\stylesheet…}` are all text that is NOT document text; without skipping
19
+ // them a converted file opens with a list of every font it uses.
20
+ //
21
+ // Pictures are not read. `\pict` holds hex-encoded WMF or PNG, and the WMF half
22
+ // browsers cannot draw at all, so the group is skipped and a notice is raised.
23
+ // ---------------------------------------------------------------------------
24
+ import { addNotice, mergeRuns, tidy } from '../model.js';
25
+ /** Groups whose contents are metadata rather than document text. */
26
+ const SKIPPED_DESTINATIONS = new Set([
27
+ 'fonttbl', 'colortbl', 'stylesheet', 'listtable', 'listoverridetable',
28
+ 'info', 'pict', 'header', 'footer', 'headerl', 'headerr', 'headerf',
29
+ 'footerl', 'footerr', 'footerf', 'footnote', 'comment', 'generator',
30
+ 'themedata', 'colorschememapping', 'latentstyles', 'datastore', 'xmlnstbl',
31
+ 'nonshppict', 'shppict', 'field', 'filetbl', 'revtbl', 'annotation',
32
+ 'bkmkstart', 'bkmkend', 'template', 'atnid', 'atnauthor',
33
+ ]);
34
+ export async function readRtf(file) {
35
+ const source = await file.text();
36
+ if (!source.startsWith('{\\rt')) {
37
+ throw new Error('This doesn’t look like an RTF file inside.');
38
+ }
39
+ const doc = { blocks: [], notices: [] };
40
+ const codepage = /\\ansicpg(\d+)/.exec(source)?.[1] ?? '1252';
41
+ const decoder = makeDecoder(codepage);
42
+ const stack = [];
43
+ let state = {
44
+ bold: false, italic: false, underline: false, strike: false,
45
+ heading: 0, list: false, skip: false, unicodeSkip: 1,
46
+ };
47
+ let runs = [];
48
+ let pendingBytes = [];
49
+ let sawPicture = false;
50
+ let listItems = [];
51
+ let listOrdered = false;
52
+ const flushBytes = () => {
53
+ if (!pendingBytes.length)
54
+ return;
55
+ const text = decoder(new Uint8Array(pendingBytes));
56
+ pendingBytes = [];
57
+ if (!state.skip)
58
+ runs.push({ text, ...styleOf(state) });
59
+ };
60
+ const flushList = () => {
61
+ if (listItems.length) {
62
+ doc.blocks.push({ kind: 'list', ordered: listOrdered, items: listItems });
63
+ listItems = [];
64
+ }
65
+ };
66
+ const endParagraph = () => {
67
+ flushBytes();
68
+ const merged = mergeRuns(runs);
69
+ runs = [];
70
+ if (!merged.length) {
71
+ flushList();
72
+ doc.blocks.push({ kind: 'paragraph', runs: [{ text: ' ' }] });
73
+ return;
74
+ }
75
+ if (state.list) {
76
+ listItems.push({ runs: merged, level: 0 });
77
+ return;
78
+ }
79
+ flushList();
80
+ if (state.heading > 0) {
81
+ const level = Math.min(4, Math.max(1, state.heading));
82
+ doc.blocks.push({ kind: 'heading', level, runs: merged });
83
+ }
84
+ else {
85
+ doc.blocks.push({ kind: 'paragraph', runs: merged });
86
+ }
87
+ };
88
+ let i = 0;
89
+ while (i < source.length) {
90
+ const ch = source[i];
91
+ if (ch === '{') {
92
+ flushBytes();
93
+ stack.push({ ...state });
94
+ i += 1;
95
+ continue;
96
+ }
97
+ if (ch === '}') {
98
+ flushBytes();
99
+ const restored = stack.pop();
100
+ if (restored)
101
+ state = restored;
102
+ i += 1;
103
+ continue;
104
+ }
105
+ if (ch === '\\') {
106
+ // An escaped literal: \\ \{ \} are the characters themselves.
107
+ const next = source[i + 1];
108
+ if (next === '\\' || next === '{' || next === '}') {
109
+ pendingBytes.push(next.charCodeAt(0));
110
+ i += 2;
111
+ continue;
112
+ }
113
+ // A hex byte.
114
+ if (next === "'") {
115
+ const hex = source.slice(i + 2, i + 4);
116
+ pendingBytes.push(parseInt(hex, 16) || 0);
117
+ i += 4;
118
+ continue;
119
+ }
120
+ // ⚠️ `\*` MUST BE HANDLED HERE, before the control-word regex, and the
121
+ // reason is worth keeping: `*` is not a letter, so the regex below does
122
+ // not match it, and the fallthrough consumed the backslash and then
123
+ // treated the `*` as ORDINARY TEXT. Every `{\*\generator …}` and
124
+ // `{\*\listtable …}` LibreOffice writes therefore contributed a literal
125
+ // asterisk, and a converted RTF opened with "*****" before its title.
126
+ // It means "skip this group unless you know the destination", and we
127
+ // know none of them.
128
+ if (next === '*') {
129
+ flushBytes();
130
+ state.skip = true;
131
+ i += 2;
132
+ continue;
133
+ }
134
+ const match = /^\\([a-zA-Z]+)(-?\d+)? ?/.exec(source.slice(i));
135
+ if (!match) {
136
+ i += 1;
137
+ continue;
138
+ }
139
+ flushBytes();
140
+ const word = match[1];
141
+ const value = match[2] === undefined ? null : Number(match[2]);
142
+ i += match[0].length;
143
+ // A destination marker: `{\*\foo …}` means "skip this whole group if you
144
+ // don't know \foo", which for our purposes is always.
145
+ if (word === '*') {
146
+ state.skip = true;
147
+ continue;
148
+ }
149
+ if (SKIPPED_DESTINATIONS.has(word)) {
150
+ if (word === 'pict')
151
+ sawPicture = true;
152
+ state.skip = true;
153
+ continue;
154
+ }
155
+ switch (word) {
156
+ case 'par':
157
+ case 'sect':
158
+ endParagraph();
159
+ break;
160
+ case 'line':
161
+ if (!state.skip)
162
+ runs.push({ text: '\n', ...styleOf(state) });
163
+ break;
164
+ case 'page':
165
+ endParagraph();
166
+ doc.blocks.push({ kind: 'pagebreak' });
167
+ break;
168
+ case 'tab':
169
+ if (!state.skip)
170
+ runs.push({ text: ' ', ...styleOf(state) });
171
+ break;
172
+ case 'b':
173
+ state.bold = value !== 0;
174
+ break;
175
+ case 'i':
176
+ state.italic = value !== 0;
177
+ break;
178
+ case 'ul':
179
+ state.underline = value !== 0;
180
+ break;
181
+ case 'ulnone':
182
+ state.underline = false;
183
+ break;
184
+ case 'strike':
185
+ state.strike = value !== 0;
186
+ break;
187
+ case 'plain':
188
+ state.bold = state.italic = state.underline = state.strike = false;
189
+ break;
190
+ case 'outlinelevel':
191
+ state.heading = value === null ? 0 : value + 1;
192
+ break;
193
+ case 's':
194
+ // `\s1`–`\s9` are the built-in heading styles in almost every
195
+ // producer's stylesheet. Not guaranteed, but right far more often
196
+ // than treating a styled heading as body text.
197
+ state.heading = value !== null && value >= 1 && value <= 9 ? value : 0;
198
+ break;
199
+ case 'pard':
200
+ // Resets paragraph formatting — including list membership and any
201
+ // heading level, which is what ends a list.
202
+ state.heading = 0;
203
+ state.list = false;
204
+ break;
205
+ case 'ls':
206
+ case 'listtext':
207
+ state.list = true;
208
+ break;
209
+ case 'pntext':
210
+ // The literal bullet or number a non-list-aware reader should show.
211
+ // Skipped, because the writers draw their own markers and this would
212
+ // double them up.
213
+ state.skip = true;
214
+ break;
215
+ case 'pnlvlblt':
216
+ listOrdered = false;
217
+ state.list = true;
218
+ break;
219
+ case 'pnlvlbody':
220
+ listOrdered = true;
221
+ state.list = true;
222
+ break;
223
+ case 'u': {
224
+ // A Unicode character, given as a SIGNED 16-bit value — so 8212
225
+ // (em dash) arrives fine but anything above U+7FFF arrives negative.
226
+ if (value !== null && !state.skip) {
227
+ const code = value < 0 ? value + 65536 : value;
228
+ runs.push({ text: String.fromCharCode(code), ...styleOf(state) });
229
+ }
230
+ // `\uc` says how many CHARACTERS of ANSI fallback follow, spelling
231
+ // the same glyph for a reader too old to understand `\u`. They must
232
+ // be swallowed or the document gets the character twice.
233
+ i = skipFallback(source, i, state.unicodeSkip);
234
+ break;
235
+ }
236
+ case 'uc':
237
+ state.unicodeSkip = value ?? 1;
238
+ break;
239
+ case 'cell':
240
+ if (!state.skip)
241
+ runs.push({ text: ' ', ...styleOf(state) });
242
+ break;
243
+ case 'row':
244
+ endParagraph();
245
+ break;
246
+ default:
247
+ break;
248
+ }
249
+ continue;
250
+ }
251
+ if (ch === '\n' || ch === '\r') {
252
+ i += 1;
253
+ continue;
254
+ }
255
+ pendingBytes.push(ch.charCodeAt(0));
256
+ i += 1;
257
+ }
258
+ endParagraph();
259
+ flushList();
260
+ if (sawPicture) {
261
+ addNotice(doc, 'Pictures were left out — RTF stores them in a Windows format browsers can’t draw.');
262
+ }
263
+ // RTF's tables are rows of cells with no structure around them, so they come
264
+ // through as tab-separated lines rather than as a laid-out grid.
265
+ if (/\\trowd/.test(source)) {
266
+ addNotice(doc, 'Tables came through as plain lines — RTF doesn’t describe them as a grid.');
267
+ }
268
+ if (!doc.blocks.length)
269
+ throw new Error('No readable text was found in this RTF.');
270
+ doc.title = /\{\\title ([^}]*)\}/.exec(source)?.[1]?.trim() || undefined;
271
+ return tidy(doc);
272
+ }
273
+ /**
274
+ * Step over the ANSI fallback that follows a `\uN`.
275
+ *
276
+ * ⚠️ `\uc1` means ONE CHARACTER, NOT ONE STRING POSITION, and conflating the
277
+ * two is the bug this function exists to prevent. The fallback for an em dash
278
+ * is written `\'97` — four characters spelling one byte — so advancing the
279
+ * cursor by `unicodeSkip` left `'97` behind as literal text, and every em dash
280
+ * in a converted RTF came out as `—'97`. A fallback character can be:
281
+ *
282
+ * \'xx a hex byte, four characters
283
+ * \\ \{ an escaped literal, two characters
284
+ * x an ordinary character, one
285
+ *
286
+ * A control word among them ends the run early — it is the next instruction,
287
+ * not a fallback — so the loop stops rather than eating it.
288
+ */
289
+ function skipFallback(source, at, count) {
290
+ let i = at;
291
+ for (let n = 0; n < count && i < source.length; n += 1) {
292
+ if (source[i] === '\\') {
293
+ const next = source[i + 1];
294
+ if (next === "'") {
295
+ i += 4;
296
+ continue;
297
+ }
298
+ if (next === '\\' || next === '{' || next === '}') {
299
+ i += 2;
300
+ continue;
301
+ }
302
+ break;
303
+ }
304
+ if (source[i] === '{' || source[i] === '}')
305
+ break;
306
+ i += 1;
307
+ }
308
+ return i;
309
+ }
310
+ function styleOf(state) {
311
+ const style = {};
312
+ if (state.bold)
313
+ style.bold = true;
314
+ if (state.italic)
315
+ style.italic = true;
316
+ if (state.underline)
317
+ style.underline = true;
318
+ if (state.strike)
319
+ style.strike = true;
320
+ return style;
321
+ }
322
+ /**
323
+ * A decoder for the document's declared codepage.
324
+ *
325
+ * `TextDecoder` knows these by their web names, and an unknown one throws
326
+ * rather than falling back — so an exotic `\ansicpg` would take the whole
327
+ * conversion down. Windows-1252 is the overwhelmingly common case and a decent
328
+ * last resort.
329
+ */
330
+ function makeDecoder(codepage) {
331
+ const label = codepage === '65001' ? 'utf-8' : `windows-${codepage}`;
332
+ try {
333
+ const decoder = new TextDecoder(label);
334
+ return (bytes) => decoder.decode(bytes);
335
+ }
336
+ catch {
337
+ const fallback = new TextDecoder('windows-1252');
338
+ return (bytes) => fallback.decode(bytes);
339
+ }
340
+ }
341
+ //# sourceMappingURL=rtf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rtf.js","sourceRoot":"","sources":["../../src/read/rtf.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type RichDoc } from '../model.js';
2
+ export declare function readText(file: File): Promise<RichDoc>;
3
+ export declare function parseTextDoc(source: string, filename?: string): RichDoc;
4
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/read/text.ts"],"names":[],"mappings":"AAeA,OAAO,EAAoB,KAAK,OAAO,EAAE,MAAM,aAAa,CAAA;AAE5D,wBAAsB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAE3D;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAwBvE"}
@@ -0,0 +1,62 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Plain text → RichDoc.
3
+ //
4
+ // The smallest reader, and the one that has to guess most. A .txt has no
5
+ // structure at all, so the only question is what a BLANK LINE means — and the
6
+ // answer differs between a wrapped-at-72-columns file from an email client and
7
+ // a file with one paragraph per line from a note app. Both are common.
8
+ //
9
+ // The rule: a blank line always separates paragraphs. Within a block of lines,
10
+ // they are JOINED if the file looks hard-wrapped (most lines near the same
11
+ // length, none very long) and kept as separate lines otherwise. Joining a file
12
+ // that was not hard-wrapped ruins a list; not joining one that was gives a PDF
13
+ // with a ragged right edge every 72 characters.
14
+ // ---------------------------------------------------------------------------
15
+ import { tidy } from '../model.js';
16
+ export async function readText(file) {
17
+ return parseTextDoc(await file.text(), file.name);
18
+ }
19
+ export function parseTextDoc(source, filename) {
20
+ const lines = source.replace(/\r\n?/g, '\n').split('\n');
21
+ const blocks = [];
22
+ const rewrap = looksHardWrapped(lines);
23
+ let buffer = [];
24
+ const flush = () => {
25
+ if (!buffer.length)
26
+ return;
27
+ const text = rewrap ? buffer.join(' ') : buffer.join('\n');
28
+ blocks.push({ kind: 'paragraph', runs: [{ text }] });
29
+ buffer = [];
30
+ };
31
+ for (const line of lines) {
32
+ if (!line.trim()) {
33
+ flush();
34
+ continue;
35
+ }
36
+ buffer.push(line.replace(/\t/g, ' ').trimEnd());
37
+ }
38
+ flush();
39
+ if (!blocks.length)
40
+ throw new Error('That text file is empty.');
41
+ return tidy({ blocks, notices: [], title: filename?.replace(/\.(txt|text|log)$/i, '') });
42
+ }
43
+ /**
44
+ * Does this file look hard-wrapped at a fixed column?
45
+ *
46
+ * The test is the shape of the line lengths, not any one line: a hard-wrapped
47
+ * file has most of its lines bunched just under a limit and none far over it.
48
+ * A file of one-paragraph-per-line has a wide spread and long lines.
49
+ */
50
+ function looksHardWrapped(lines) {
51
+ const filled = lines.map((l) => l.trimEnd().length).filter((n) => n > 0);
52
+ if (filled.length < 4)
53
+ return false;
54
+ const longest = Math.max(...filled);
55
+ if (longest > 120)
56
+ return false; // something is a full paragraph on one line
57
+ // How many lines sit in the top quarter of the observed width. Hard wrapping
58
+ // pushes almost every line there; free-form text does not.
59
+ const nearLimit = filled.filter((n) => n >= longest * 0.75).length;
60
+ return nearLimit / filled.length > 0.6;
61
+ }
62
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/read/text.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,wBAAwB;AACxB,EAAE;AACF,yEAAyE;AACzE,8EAA8E;AAC9E,+EAA+E;AAC/E,uEAAuE;AACvE,EAAE;AACF,+EAA+E;AAC/E,2EAA2E;AAC3E,+EAA+E;AAC/E,+EAA+E;AAC/E,gDAAgD;AAChD,8EAA8E;AAE9E,OAAO,EAAE,IAAI,EAA4B,MAAM,aAAa,CAAA;AAE5D,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAU;IACvC,OAAO,YAAY,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,QAAiB;IAC5D,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACxD,MAAM,MAAM,GAAY,EAAE,CAAA;IAC1B,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAA;IAEtC,IAAI,MAAM,GAAa,EAAE,CAAA;IACzB,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,IAAI,CAAC,MAAM,CAAC,MAAM;YAAE,OAAM;QAC1B,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC1D,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;QACpD,MAAM,GAAG,EAAE,CAAA;IACb,CAAC,CAAA;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YACjB,KAAK,EAAE,CAAA;YACP,SAAQ;QACV,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,CAAA;IACpD,CAAC;IACD,KAAK,EAAE,CAAA;IAEP,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAA;IAC/D,OAAO,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC,EAAE,CAAC,CAAA;AAC1F,CAAC;AAED;;;;;;GAMG;AACH,SAAS,gBAAgB,CAAC,KAAwB;IAChD,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACxE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAA;IAEnC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAA;IACnC,IAAI,OAAO,GAAG,GAAG;QAAE,OAAO,KAAK,CAAA,CAAC,4CAA4C;IAE5E,6EAA6E;IAC7E,2DAA2D;IAC3D,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,OAAO,GAAG,IAAI,CAAC,CAAC,MAAM,CAAA;IAClE,OAAO,SAAS,GAAG,MAAM,CAAC,MAAM,GAAG,GAAG,CAAA;AACxC,CAAC"}
@@ -0,0 +1,23 @@
1
+ export declare class ZipArchive {
2
+ private bytes;
3
+ private view;
4
+ private entries;
5
+ private constructor();
6
+ static open(source: Blob | ArrayBuffer): Promise<ZipArchive>;
7
+ /** Every path in the archive, in directory order. */
8
+ get names(): string[];
9
+ has(name: string): boolean;
10
+ bytesOf(name: string): Promise<Uint8Array | null>;
11
+ textOf(name: string): Promise<string | null>;
12
+ blobOf(name: string, type: string): Promise<Blob | null>;
13
+ /**
14
+ * Find the end-of-central-directory record and read every entry from it.
15
+ *
16
+ * The record is at the very end unless the archive has a comment, so it is
17
+ * searched for backwards over the last 64 KB — the most a comment can be.
18
+ */
19
+ private readDirectory;
20
+ }
21
+ /** Whether the browser can read ZIP-based documents at all. */
22
+ export declare function unzipSupported(): boolean;
23
+ //# sourceMappingURL=unzip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unzip.d.ts","sourceRoot":"","sources":["../src/unzip.ts"],"names":[],"mappings":"AAkCA,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,IAAI,CAAU;IACtB,OAAO,CAAC,OAAO,CAA2B;IAE1C,OAAO;WAKM,IAAI,CAAC,MAAM,EAAE,IAAI,GAAG,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAOlE,qDAAqD;IACrD,IAAI,KAAK,IAAI,MAAM,EAAE,CAEpB;IAED,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIpB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAwBjD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAO5C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAK9D;;;;;OAKG;IACH,OAAO,CAAC,aAAa;CAoDtB;AAgBD,+DAA+D;AAC/D,wBAAgB,cAAc,IAAI,OAAO,CAExC"}
package/dist/unzip.js ADDED
@@ -0,0 +1,152 @@
1
+ // ---------------------------------------------------------------------------
2
+ // A ZIP reader, in one page and with no dependency.
3
+ //
4
+ // A .docx and a .odt are both ZIPs of XML, so reading either starts here. The
5
+ // app already WRITES ZIPs (`zip.ts`) for "Download all"; this is the other
6
+ // direction, and it needs one thing that writing did not: DEFLATE.
7
+ //
8
+ // `DecompressionStream('deflate-raw')` is that, built into the browser — the
9
+ // same primitive PalsPayIn leans on for its relay payloads. It is why this file
10
+ // is a hundred lines instead of a fflate dependency: the compression is the
11
+ // hard part and the platform already has it, leaving only the container, which
12
+ // is a central directory of fixed-width records.
13
+ //
14
+ // WHY THE CENTRAL DIRECTORY AND NOT THE LOCAL HEADERS
15
+ // ---------------------------------------------------
16
+ // Walking local headers front-to-back looks simpler and is a trap: an entry
17
+ // written by a streaming producer sets its sizes to zero and puts the real ones
18
+ // in a data descriptor AFTER the data, so you cannot know where the entry ends
19
+ // without decompressing it first. The central directory at the tail always has
20
+ // the true sizes. Word and LibreOffice both produce files that need this.
21
+ // ---------------------------------------------------------------------------
22
+ const END_OF_CENTRAL = 0x06054b50;
23
+ const CENTRAL_HEADER = 0x02014b50;
24
+ const ZIP64_END_LOCATOR = 0x07064b50;
25
+ export class ZipArchive {
26
+ bytes;
27
+ view;
28
+ entries = new Map();
29
+ constructor(bytes) {
30
+ this.bytes = bytes;
31
+ this.view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
32
+ }
33
+ static async open(source) {
34
+ const buffer = source instanceof Blob ? await source.arrayBuffer() : source;
35
+ const archive = new ZipArchive(new Uint8Array(buffer));
36
+ archive.readDirectory();
37
+ return archive;
38
+ }
39
+ /** Every path in the archive, in directory order. */
40
+ get names() {
41
+ return [...this.entries.keys()];
42
+ }
43
+ has(name) {
44
+ return this.entries.has(name);
45
+ }
46
+ async bytesOf(name) {
47
+ const entry = this.entries.get(name);
48
+ if (!entry)
49
+ return null;
50
+ // The local header repeats the name and extra field, and its lengths are
51
+ // the ones that count — a producer may write a different extra field here
52
+ // than in the central directory, so the data offset must be computed from
53
+ // this copy rather than from the directory's.
54
+ const local = entry.offset;
55
+ if (this.view.getUint32(local, true) !== 0x04034b50) {
56
+ throw new Error(`${name} is not where this archive says it is.`);
57
+ }
58
+ const nameLength = this.view.getUint16(local + 26, true);
59
+ const extraLength = this.view.getUint16(local + 28, true);
60
+ const start = local + 30 + nameLength + extraLength;
61
+ const raw = this.bytes.subarray(start, start + entry.compressedSize);
62
+ if (entry.method === 0)
63
+ return raw;
64
+ if (entry.method !== 8) {
65
+ throw new Error(`This file uses a compression method (${entry.method}) browsers can’t undo.`);
66
+ }
67
+ return inflateRaw(raw);
68
+ }
69
+ async textOf(name) {
70
+ const bytes = await this.bytesOf(name);
71
+ // Every XML part in an Office or OpenDocument package is UTF-8; the
72
+ // declaration says so and nothing in the wild disagrees.
73
+ return bytes ? new TextDecoder('utf-8').decode(bytes) : null;
74
+ }
75
+ async blobOf(name, type) {
76
+ const bytes = await this.bytesOf(name);
77
+ return bytes ? new Blob([bytes], { type }) : null;
78
+ }
79
+ /**
80
+ * Find the end-of-central-directory record and read every entry from it.
81
+ *
82
+ * The record is at the very end unless the archive has a comment, so it is
83
+ * searched for backwards over the last 64 KB — the most a comment can be.
84
+ */
85
+ readDirectory() {
86
+ const size = this.bytes.length;
87
+ if (size < 22)
88
+ throw new Error('That file is too small to be a document.');
89
+ let eocd = -1;
90
+ const floor = Math.max(0, size - 22 - 0xffff);
91
+ for (let i = size - 22; i >= floor; i -= 1) {
92
+ if (this.view.getUint32(i, true) === END_OF_CENTRAL) {
93
+ eocd = i;
94
+ break;
95
+ }
96
+ }
97
+ if (eocd < 0)
98
+ throw new Error('That doesn’t look like a Word or OpenDocument file.');
99
+ let count = this.view.getUint16(eocd + 10, true);
100
+ let directoryAt = this.view.getUint32(eocd + 16, true);
101
+ // ZIP64. A .docx never needs it, but a .odt with a few hundred megabytes of
102
+ // embedded images can, and the 32-bit fields read as 0xffffffff when it
103
+ // does — which without this points the directory scan at nothing.
104
+ if (directoryAt === 0xffffffff || count === 0xffff) {
105
+ for (let i = eocd - 20; i >= 0; i -= 1) {
106
+ if (this.view.getUint32(i, true) === ZIP64_END_LOCATOR) {
107
+ const zip64At = Number(this.view.getBigUint64(i + 8, true));
108
+ count = Number(this.view.getBigUint64(zip64At + 32, true));
109
+ directoryAt = Number(this.view.getBigUint64(zip64At + 48, true));
110
+ break;
111
+ }
112
+ }
113
+ }
114
+ let cursor = directoryAt;
115
+ for (let i = 0; i < count; i += 1) {
116
+ if (cursor + 46 > size || this.view.getUint32(cursor, true) !== CENTRAL_HEADER)
117
+ break;
118
+ const method = this.view.getUint16(cursor + 10, true);
119
+ const compressedSize = this.view.getUint32(cursor + 20, true);
120
+ const nameLength = this.view.getUint16(cursor + 28, true);
121
+ const extraLength = this.view.getUint16(cursor + 30, true);
122
+ const commentLength = this.view.getUint16(cursor + 32, true);
123
+ const offset = this.view.getUint32(cursor + 42, true);
124
+ // Names are UTF-8 when bit 11 of the flags is set and CP437 otherwise.
125
+ // Every part path we look up is ASCII, where the two agree, so decoding
126
+ // as UTF-8 throughout is safe and saves carrying a CP437 table.
127
+ const name = new TextDecoder('utf-8').decode(this.bytes.subarray(cursor + 46, cursor + 46 + nameLength));
128
+ this.entries.set(name, { name, method, offset, compressedSize });
129
+ cursor += 46 + nameLength + extraLength + commentLength;
130
+ }
131
+ if (!this.entries.size)
132
+ throw new Error('That archive has nothing in it.');
133
+ }
134
+ }
135
+ /**
136
+ * Raw DEFLATE, via the browser.
137
+ *
138
+ * 'deflate-raw' rather than 'deflate': ZIP stores the bare compressed stream
139
+ * with no zlib header or Adler checksum around it, and asking for 'deflate'
140
+ * makes the browser reject the first two bytes as a bad header.
141
+ */
142
+ async function inflateRaw(data) {
143
+ const stream = new Blob([data])
144
+ .stream()
145
+ .pipeThrough(new DecompressionStream('deflate-raw'));
146
+ return new Uint8Array(await new Response(stream).arrayBuffer());
147
+ }
148
+ /** Whether the browser can read ZIP-based documents at all. */
149
+ export function unzipSupported() {
150
+ return typeof DecompressionStream !== 'undefined';
151
+ }
152
+ //# sourceMappingURL=unzip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unzip.js","sourceRoot":"","sources":["../src/unzip.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { Grid } from '../model.js';
2
+ export declare function gridToCsv(grid: Grid): string;
3
+ export interface JsonOptions {
4
+ /** Turn "42" into 42 and "true" into true. */
5
+ inferTypes: boolean;
6
+ }
7
+ /**
8
+ * A grid as an array of objects.
9
+ *
10
+ * Columns become keys. Where the source had no header row, the keys are
11
+ * `column1`, `column2`… rather than the first row's values — using data as keys
12
+ * silently deletes a row, and a file with no header is exactly the file where
13
+ * every row matters.
14
+ */
15
+ export declare function gridToJson(grid: Grid, options?: JsonOptions): string;
16
+ //# sourceMappingURL=data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../src/write/data.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAEvC,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAK5C;AAcD,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,UAAU,EAAE,OAAO,CAAA;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,WAAkC,GAAG,MAAM,CAc1F"}