@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.
- package/README.md +91 -0
- package/dist/convert.d.ts +54 -0
- package/dist/convert.d.ts.map +1 -0
- package/dist/convert.js +216 -0
- package/dist/convert.js.map +1 -0
- package/dist/image.d.ts +17 -0
- package/dist/image.d.ts.map +1 -0
- package/dist/image.js +66 -0
- package/dist/image.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/merge.d.ts +14 -0
- package/dist/merge.d.ts.map +1 -0
- package/dist/merge.js +51 -0
- package/dist/merge.js.map +1 -0
- package/dist/metrics.d.ts +19 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +151 -0
- package/dist/metrics.js.map +1 -0
- package/dist/model.d.ts +114 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +121 -0
- package/dist/model.js.map +1 -0
- package/dist/pdfcore.d.ts +118 -0
- package/dist/pdfcore.d.ts.map +1 -0
- package/dist/pdfcore.js +398 -0
- package/dist/pdfcore.js.map +1 -0
- package/dist/read/csv.d.ts +17 -0
- package/dist/read/csv.d.ts.map +1 -0
- package/dist/read/csv.js +167 -0
- package/dist/read/csv.js.map +1 -0
- package/dist/read/doc.d.ts +3 -0
- package/dist/read/doc.d.ts.map +1 -0
- package/dist/read/doc.js +360 -0
- package/dist/read/doc.js.map +1 -0
- package/dist/read/docx.d.ts +3 -0
- package/dist/read/docx.d.ts.map +1 -0
- package/dist/read/docx.js +455 -0
- package/dist/read/docx.js.map +1 -0
- package/dist/read/html.d.ts +4 -0
- package/dist/read/html.d.ts.map +1 -0
- package/dist/read/html.js +236 -0
- package/dist/read/html.js.map +1 -0
- package/dist/read/json.d.ts +9 -0
- package/dist/read/json.d.ts.map +1 -0
- package/dist/read/json.js +105 -0
- package/dist/read/json.js.map +1 -0
- package/dist/read/markdown.d.ts +4 -0
- package/dist/read/markdown.d.ts.map +1 -0
- package/dist/read/markdown.js +247 -0
- package/dist/read/markdown.js.map +1 -0
- package/dist/read/odt.d.ts +3 -0
- package/dist/read/odt.d.ts.map +1 -0
- package/dist/read/odt.js +359 -0
- package/dist/read/odt.js.map +1 -0
- package/dist/read/rtf.d.ts +3 -0
- package/dist/read/rtf.d.ts.map +1 -0
- package/dist/read/rtf.js +341 -0
- package/dist/read/rtf.js.map +1 -0
- package/dist/read/text.d.ts +4 -0
- package/dist/read/text.d.ts.map +1 -0
- package/dist/read/text.js +62 -0
- package/dist/read/text.js.map +1 -0
- package/dist/unzip.d.ts +23 -0
- package/dist/unzip.d.ts.map +1 -0
- package/dist/unzip.js +152 -0
- package/dist/unzip.js.map +1 -0
- package/dist/write/data.d.ts +16 -0
- package/dist/write/data.d.ts.map +1 -0
- package/dist/write/data.js +89 -0
- package/dist/write/data.js.map +1 -0
- package/dist/write/pdf.d.ts +10 -0
- package/dist/write/pdf.d.ts.map +1 -0
- package/dist/write/pdf.js +696 -0
- package/dist/write/pdf.js.map +1 -0
- package/dist/write/pdfSettings.d.ts +13 -0
- package/dist/write/pdfSettings.d.ts.map +1 -0
- package/dist/write/pdfSettings.js +26 -0
- package/dist/write/pdfSettings.js.map +1 -0
- package/dist/write/text.d.ts +5 -0
- package/dist/write/text.d.ts.map +1 -0
- package/dist/write/text.js +341 -0
- package/dist/write/text.js.map +1 -0
- package/dist/xml.d.ts +22 -0
- package/dist/xml.d.ts.map +1 -0
- package/dist/xml.js +83 -0
- package/dist/xml.js.map +1 -0
- package/package.json +31 -0
package/dist/read/rtf.js
ADDED
|
@@ -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 @@
|
|
|
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"}
|
package/dist/unzip.d.ts
ADDED
|
@@ -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"}
|