@autorag/librarian 2.13.4 → 2.13.6
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/NOTICE +3 -0
- package/README.md +50 -18
- package/dist/agent/agent.d.ts +111 -40
- package/dist/agent/cloud-release-extension.d.ts +43 -0
- package/dist/agent/decision-backends.d.ts +49 -0
- package/dist/agent/decision-model-check.d.ts +92 -0
- package/dist/agent/dupey-tool.d.ts +2 -0
- package/dist/agent/everything-search-tool.d.ts +1 -0
- package/dist/agent/fsearch-search-tool.d.ts +1 -0
- package/dist/agent/index.d.ts +4 -1
- package/dist/agent/jev-extension.d.ts +27 -32
- package/dist/agent/jikji-find-tool.d.ts +5 -0
- package/dist/agent/name-candidates.d.ts +88 -0
- package/dist/agent/permission-gate.d.ts +2 -5
- package/dist/agent/query-routing.d.ts +1 -1
- package/dist/agent/search-documents.d.ts +1 -1
- package/dist/agent/sllm-decision.d.ts +34 -0
- package/dist/cli/commands/duplicates.d.ts +3 -2
- package/dist/cli/commands/models.d.ts +2 -0
- package/dist/cli/commands/search.d.ts +2 -0
- package/dist/cli/config.d.ts +49 -30
- package/dist/cli/index.js +13522 -10169
- package/dist/cli/setup.d.ts +27 -1
- package/dist/cloud/jev-backend.d.ts +26 -4
- package/dist/core.js +6079 -2840
- package/dist/datasource/index.d.ts +2 -2
- package/dist/datasource/skills/obsidian/index.d.ts +1 -1
- package/dist/datasource/skills/obsidian/methods.d.ts +1 -1
- package/dist/datasource/skills/obsidian/skill.d.ts +1 -0
- package/dist/datasource/skills/obsidian/vault-index.d.ts +1 -1
- package/dist/datasource/skills/wombat/client.d.ts +17 -0
- package/dist/datasource/skills/wombat/index.d.ts +4 -0
- package/dist/datasource/skills/wombat/methods.d.ts +15 -0
- package/dist/datasource/skills/wombat/skill.d.ts +38 -0
- package/dist/datasource/skills/wombat/types.d.ts +89 -0
- package/dist/dupey/cli.d.ts +21 -1
- package/dist/dupey/filter.d.ts +8 -1
- package/dist/dupey/index.d.ts +1 -0
- package/dist/dupey/scan-plan.d.ts +23 -0
- package/dist/embedding/index.d.ts +3 -1
- package/dist/everything/client.d.ts +1 -2
- package/dist/filesystem/cloud-placeholder.d.ts +313 -21
- package/dist/filesystem/shared-exclusive-queue.d.ts +16 -0
- package/dist/fsearch/client.d.ts +3 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6184 -2905
- package/dist/jikji/answer-pack.d.ts +7 -1
- package/dist/jikji/client.d.ts +28 -14
- package/dist/jikji/diagnostics.d.ts +16 -2
- package/dist/jikji/index.d.ts +3 -3
- package/dist/jikji/installer.d.ts +11 -5
- package/dist/jikji/retry-command.d.ts +10 -0
- package/dist/jikji/types.d.ts +47 -1
- package/dist/jikji/version.d.ts +20 -0
- package/dist/mcp/index.js +6154 -2902
- package/dist/mcp/server.d.ts +3 -0
- package/dist/minsync/binary.d.ts +10 -5
- package/dist/minsync/client.d.ts +7 -10
- package/dist/minsync/embedder-config.d.ts +11 -10
- package/dist/minsync/errors.d.ts +3 -0
- package/dist/minsync/index.d.ts +1 -1
- package/dist/minsync/installer.d.ts +1 -1
- package/dist/minsync/method.d.ts +1 -0
- package/dist/minsync/types.d.ts +0 -9
- package/dist/minsync/version.d.ts +20 -0
- package/dist/mirror/cloud-fingerprints.d.ts +30 -0
- package/dist/mirror/cloud.d.ts +79 -0
- package/dist/mirror/index.d.ts +4 -0
- package/dist/mirror/sync.d.ts +79 -1
- package/dist/parser/csv.d.ts +26 -0
- package/dist/parser/defaults.d.ts +1 -1
- package/dist/parser/index.d.ts +2 -0
- package/dist/parser/kordoc.d.ts +6 -3
- package/dist/parser/parse-worker.js +668 -28
- package/dist/parser/spreadsheet-render.d.ts +53 -0
- package/dist/parser/spreadsheet.d.ts +27 -0
- package/dist/profiles/loop-guard.d.ts +8 -2
- package/dist/profiles/retrieval-tools.d.ts +2 -1
- package/dist/profiles.js +13520 -10280
- package/dist/retrieval/skip.d.ts +1 -1
- package/dist/retrieval/types.d.ts +1 -1
- package/package.json +3 -3
- package/skills/autorag/SKILL.md +7 -4
- package/skills/autorag-doctor/SKILL.md +8 -3
- package/skills/autorag-lite-setup/SKILL.md +4 -4
- package/skills/autorag-setup/SKILL.md +53 -30
- package/dist/datasource/skills/cloud-drive/index.d.ts +0 -2
- package/dist/datasource/skills/cloud-drive/rclone-connector.d.ts +0 -49
- package/dist/datasource/skills/cloud-drive/skill.d.ts +0 -14
- package/dist/minsync/kiwi.d.ts +0 -17
- package/dist/minsync/lexical-language.d.ts +0 -18
|
@@ -90,35 +90,340 @@ var init_language = __esm(() => {
|
|
|
90
90
|
};
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
-
// src/parser/
|
|
94
|
-
function
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
93
|
+
// src/parser/spreadsheet-render.ts
|
|
94
|
+
function estimateLineTokens(text) {
|
|
95
|
+
let halves = 0;
|
|
96
|
+
for (const char of text) {
|
|
97
|
+
const code = char.codePointAt(0) ?? 0;
|
|
98
|
+
halves += code < 128 ? 1 : code < 2048 ? 2 : 4;
|
|
99
|
+
}
|
|
100
|
+
return Math.ceil(halves / 2);
|
|
100
101
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
102
|
+
function classifyText(text) {
|
|
103
|
+
const trimmed = text.trim();
|
|
104
|
+
if (NUMBER_TEXT.test(trimmed))
|
|
105
|
+
return "number";
|
|
106
|
+
if (DATE_TEXT.test(trimmed))
|
|
107
|
+
return "date";
|
|
108
|
+
return "text";
|
|
109
|
+
}
|
|
110
|
+
function renderWorkbook(sheets) {
|
|
111
|
+
return sheets.map(renderSheet).join(`
|
|
112
|
+
|
|
113
|
+
`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
class SheetView {
|
|
117
|
+
rowCount;
|
|
118
|
+
colCount;
|
|
119
|
+
#grid;
|
|
120
|
+
#merges = new Map;
|
|
121
|
+
constructor(grid) {
|
|
122
|
+
this.#grid = grid;
|
|
123
|
+
this.rowCount = grid.rows.length;
|
|
124
|
+
const widest = grid.rows.reduce((max, row) => Math.max(max, row?.length ?? 0), 0);
|
|
125
|
+
const merges = (grid.merges ?? []).filter((merge) => merge.top < this.rowCount && merge.left < widest);
|
|
126
|
+
this.colCount = merges.reduce((max, merge) => Math.max(max, Math.min(merge.right, MAX_COLUMNS - 1) + 1), widest);
|
|
127
|
+
for (const merge of merges) {
|
|
128
|
+
const bottom = Math.min(merge.bottom, this.rowCount - 1);
|
|
129
|
+
const right = Math.min(merge.right, this.colCount - 1);
|
|
130
|
+
for (let row = merge.top;row <= bottom; row++) {
|
|
131
|
+
for (let col = merge.left;col <= right; col++)
|
|
132
|
+
this.#merges.set(row * COLUMN_STRIDE + col, merge);
|
|
133
|
+
}
|
|
112
134
|
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
135
|
+
}
|
|
136
|
+
resolve(row, col) {
|
|
137
|
+
const merge = this.#merges.get(row * COLUMN_STRIDE + col);
|
|
138
|
+
const anchorRow = merge?.top ?? row;
|
|
139
|
+
const anchorCol = merge?.left ?? col;
|
|
140
|
+
const cell = this.#grid.rows[anchorRow]?.[anchorCol];
|
|
141
|
+
if (cell === undefined || clean(cell.text) === "")
|
|
142
|
+
return;
|
|
143
|
+
return { cell, row: anchorRow, col: anchorCol, merge };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function renderSheet(grid) {
|
|
147
|
+
const view = new SheetView(grid);
|
|
148
|
+
const heading = `## ${grid.name}${grid.hidden === true ? " (hidden)" : ""}`;
|
|
149
|
+
const blocks = [];
|
|
150
|
+
let pendingCaptions = [];
|
|
151
|
+
let previous;
|
|
152
|
+
const bands = findBands(view);
|
|
153
|
+
for (const [index, band] of bands.entries()) {
|
|
154
|
+
const rows = range(band.top, band.bottom);
|
|
155
|
+
if (rows.every((row) => singleValue(view, row, band) !== undefined)) {
|
|
156
|
+
const next = bands[index + 1];
|
|
157
|
+
const captionsNext = next !== undefined && rows.length <= MAX_CAPTION_BLOCK_ROWS && next.top - band.bottom - 1 <= MAX_CAPTION_GAP_ROWS && !range(next.top, next.bottom).every((row) => singleValue(view, row, next) !== undefined);
|
|
158
|
+
if (captionsNext) {
|
|
159
|
+
pendingCaptions = rows.map((row) => singleValue(view, row, band));
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
blocks.push(rows.map((row) => `[${grid.name}!${cellRange(band.left, band.right, row)}] ${singleValue(view, row, band)}`).join(`
|
|
163
|
+
`));
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
let start = 0;
|
|
167
|
+
const ownCaptions = [];
|
|
168
|
+
while (start < rows.length && singleValue(view, rows[start], band) !== undefined) {
|
|
169
|
+
ownCaptions.push(singleValue(view, rows[start], band));
|
|
170
|
+
start++;
|
|
171
|
+
}
|
|
172
|
+
const body = rows.slice(start);
|
|
173
|
+
let captions = [...pendingCaptions, ...ownCaptions];
|
|
174
|
+
pendingCaptions = [];
|
|
175
|
+
const detected = detectHeader(view, band, body);
|
|
176
|
+
let header = detected?.header;
|
|
177
|
+
let dataRows = detected === undefined ? body : body.slice(detected.headerRows);
|
|
178
|
+
if (header === undefined && previous !== undefined && continuesTable(view, band, body, previous)) {
|
|
179
|
+
header = previous.header;
|
|
180
|
+
dataRows = body;
|
|
181
|
+
if (captions.length === 0)
|
|
182
|
+
captions = [...previous.captions];
|
|
183
|
+
}
|
|
184
|
+
if (header !== undefined)
|
|
185
|
+
previous = { band, header, captions };
|
|
186
|
+
const lines = dataRows.flatMap((row) => renderRow(grid.name, view, band, row, dataRows[0], header, captions));
|
|
187
|
+
if (lines.length > 0)
|
|
188
|
+
blocks.push(lines.join(`
|
|
189
|
+
`));
|
|
190
|
+
}
|
|
191
|
+
return [heading, ...blocks].join(`
|
|
192
|
+
|
|
193
|
+
`);
|
|
194
|
+
}
|
|
195
|
+
function findBands(view) {
|
|
196
|
+
const bands = [];
|
|
197
|
+
let current;
|
|
198
|
+
for (let row = 0;row < view.rowCount; row++) {
|
|
199
|
+
let left = Number.POSITIVE_INFINITY;
|
|
200
|
+
let right = Number.NEGATIVE_INFINITY;
|
|
201
|
+
for (let col = 0;col < view.colCount; col++) {
|
|
202
|
+
if (view.resolve(row, col) === undefined)
|
|
203
|
+
continue;
|
|
204
|
+
left = Math.min(left, col);
|
|
205
|
+
right = Math.max(right, col);
|
|
206
|
+
}
|
|
207
|
+
if (right < left) {
|
|
208
|
+
if (current !== undefined)
|
|
209
|
+
bands.push(current);
|
|
210
|
+
current = undefined;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (current === undefined)
|
|
214
|
+
current = { top: row, bottom: row, left, right };
|
|
215
|
+
else {
|
|
216
|
+
current.bottom = row;
|
|
217
|
+
current.left = Math.min(current.left, left);
|
|
218
|
+
current.right = Math.max(current.right, right);
|
|
120
219
|
}
|
|
220
|
+
}
|
|
221
|
+
if (current !== undefined)
|
|
222
|
+
bands.push(current);
|
|
223
|
+
return bands;
|
|
224
|
+
}
|
|
225
|
+
function rowValues(view, row, band) {
|
|
226
|
+
const values = [];
|
|
227
|
+
const seen = new Set;
|
|
228
|
+
for (let col = band.left;col <= band.right; col++) {
|
|
229
|
+
const resolved = view.resolve(row, col);
|
|
230
|
+
if (resolved === undefined)
|
|
231
|
+
continue;
|
|
232
|
+
const key = resolved.row * COLUMN_STRIDE + resolved.col;
|
|
233
|
+
if (seen.has(key))
|
|
234
|
+
continue;
|
|
235
|
+
seen.add(key);
|
|
236
|
+
values.push(resolved);
|
|
237
|
+
}
|
|
238
|
+
return values;
|
|
239
|
+
}
|
|
240
|
+
function singleValue(view, row, band) {
|
|
241
|
+
const values = rowValues(view, row, band);
|
|
242
|
+
return values.length === 1 ? clean(values[0].cell.text) : undefined;
|
|
243
|
+
}
|
|
244
|
+
function detectHeader(view, band, body) {
|
|
245
|
+
const [first, second] = body;
|
|
246
|
+
if (first === undefined)
|
|
247
|
+
return;
|
|
248
|
+
const firstValues = rowValues(view, first, band);
|
|
249
|
+
if (firstValues.length < 2 || !firstValues.every((value) => headerLike(value.cell)))
|
|
250
|
+
return;
|
|
251
|
+
const grouped = firstValues.some((value) => value.row === first && value.merge !== undefined && value.merge.right > value.merge.left);
|
|
252
|
+
if (grouped && second !== undefined && body.length >= 3) {
|
|
253
|
+
const childValues = rowValues(view, second, band).filter((value) => value.row === second);
|
|
254
|
+
if (childValues.length >= 2 && childValues.every((value) => headerLike(value.cell))) {
|
|
255
|
+
const labels = new Map;
|
|
256
|
+
for (let col = band.left;col <= band.right; col++) {
|
|
257
|
+
const parent = labelAt(view, first, col);
|
|
258
|
+
const child = labelAt(view, second, col);
|
|
259
|
+
const label = child !== "" && child !== parent ? parent === "" ? child : `${parent} > ${child}` : parent;
|
|
260
|
+
if (label !== "")
|
|
261
|
+
labels.set(col, label);
|
|
262
|
+
}
|
|
263
|
+
const data = body.slice(2);
|
|
264
|
+
return { header: { labels, typedColumns: typedColumns(view, band, data, MIN_TYPED_SHARE, 1) }, headerRows: 2 };
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const data = body.slice(1);
|
|
268
|
+
if (data.length < MIN_HEADER_DATA_ROWS)
|
|
269
|
+
return;
|
|
270
|
+
const typed = typedColumns(view, band, data, MIN_TYPED_SHARE, MIN_HEADER_DATA_ROWS);
|
|
271
|
+
if (typed.length === 0)
|
|
272
|
+
return;
|
|
273
|
+
const labels = new Map;
|
|
274
|
+
for (let col = band.left;col <= band.right; col++) {
|
|
275
|
+
const label = labelAt(view, first, col);
|
|
276
|
+
if (label !== "")
|
|
277
|
+
labels.set(col, label);
|
|
278
|
+
}
|
|
279
|
+
return { header: { labels, typedColumns: typed }, headerRows: 1 };
|
|
280
|
+
}
|
|
281
|
+
function headerLike(cell) {
|
|
282
|
+
const text = clean(cell.text);
|
|
283
|
+
if (cell.kind === "number")
|
|
284
|
+
return YEAR_TEXT.test(text);
|
|
285
|
+
return cell.kind === "text" && text.length <= MAX_HEADER_CELL_CHARS;
|
|
286
|
+
}
|
|
287
|
+
function labelAt(view, row, col) {
|
|
288
|
+
const resolved = view.resolve(row, col);
|
|
289
|
+
return resolved === undefined ? "" : clean(resolved.cell.text);
|
|
290
|
+
}
|
|
291
|
+
function typedColumns(view, band, rows, share, minimum) {
|
|
292
|
+
const columns = [];
|
|
293
|
+
for (let col = band.left;col <= band.right; col++) {
|
|
294
|
+
let filled = 0;
|
|
295
|
+
let typed = 0;
|
|
296
|
+
for (const row of rows) {
|
|
297
|
+
const resolved = view.resolve(row, col);
|
|
298
|
+
if (resolved === undefined || resolved.col !== col)
|
|
299
|
+
continue;
|
|
300
|
+
filled++;
|
|
301
|
+
if (resolved.cell.kind !== "text")
|
|
302
|
+
typed++;
|
|
303
|
+
}
|
|
304
|
+
if (filled >= minimum && typed / filled >= share)
|
|
305
|
+
columns.push(col);
|
|
306
|
+
}
|
|
307
|
+
return columns;
|
|
308
|
+
}
|
|
309
|
+
function continuesTable(view, band, body, previous) {
|
|
310
|
+
if (band.left < previous.band.left || band.right > previous.band.right)
|
|
311
|
+
return false;
|
|
312
|
+
const columns = previous.header.typedColumns.filter((col) => col >= band.left && col <= band.right);
|
|
313
|
+
if (columns.length === 0)
|
|
314
|
+
return false;
|
|
315
|
+
const typed = typedColumns(view, band, body, MIN_TYPED_SHARE, 1);
|
|
316
|
+
return columns.every((col) => typed.includes(col));
|
|
317
|
+
}
|
|
318
|
+
function renderRow(sheet, view, band, row, firstDataRow, header, captions) {
|
|
319
|
+
const items = [];
|
|
320
|
+
let spanning;
|
|
321
|
+
for (let col = band.left;col <= band.right; col++) {
|
|
322
|
+
const resolved = view.resolve(row, col);
|
|
323
|
+
if (resolved === undefined || resolved.col !== col)
|
|
324
|
+
continue;
|
|
325
|
+
if (resolved.row !== row && (resolved.row < firstDataRow || !fillsDown(resolved.merge)))
|
|
326
|
+
continue;
|
|
327
|
+
const comment = resolved.row === row && resolved.cell.comment !== undefined ? clean(resolved.cell.comment) : "";
|
|
328
|
+
const text = clean(resolved.cell.text);
|
|
329
|
+
const value = comment === "" ? text : `${text} (comment: ${comment})`;
|
|
330
|
+
if (resolved.merge !== undefined && resolved.merge.right > resolved.merge.left)
|
|
331
|
+
spanning = col;
|
|
332
|
+
items.push(header === undefined ? { col, value } : { col, label: header.labels.get(col) ?? columnName(col), value });
|
|
333
|
+
}
|
|
334
|
+
if (items.length === 0)
|
|
335
|
+
return [];
|
|
336
|
+
const [only] = items;
|
|
337
|
+
if (items.length === 1 && only !== undefined && only.col === spanning)
|
|
338
|
+
items[0] = { col: only.col, value: only.value };
|
|
339
|
+
const caption = captionText(captions);
|
|
340
|
+
const prefix = (left, right) => `[${sheet}!${cellRange(left, right, row)}${caption}] `;
|
|
341
|
+
const whole = prefix(band.left, band.right) + items.map(itemText).join(" | ");
|
|
342
|
+
if (estimateLineTokens(whole) <= MAX_LINE_TOKENS)
|
|
343
|
+
return [whole];
|
|
344
|
+
return splitRow(items, prefix);
|
|
345
|
+
}
|
|
346
|
+
function splitRow(items, prefix) {
|
|
347
|
+
const [key, ...rest] = items;
|
|
348
|
+
const keyText = itemText(key);
|
|
349
|
+
const lines = [];
|
|
350
|
+
let piece = [];
|
|
351
|
+
const flush = () => {
|
|
352
|
+
if (piece.length === 0)
|
|
353
|
+
return;
|
|
354
|
+
const head = lines.length === 0 ? "" : `${keyText} | `;
|
|
355
|
+
const first = lines.length === 0 ? key : piece[0];
|
|
356
|
+
lines.push(prefix(first.col, piece.at(-1).col) + head + piece.map(itemText).join(" | "));
|
|
357
|
+
piece = [];
|
|
121
358
|
};
|
|
359
|
+
piece.push(key);
|
|
360
|
+
for (const item of rest) {
|
|
361
|
+
for (const part of fitItem(item, prefix, keyText)) {
|
|
362
|
+
const candidate = [...piece, part];
|
|
363
|
+
const head = lines.length === 0 ? "" : `${keyText} | `;
|
|
364
|
+
const start = lines.length === 0 ? key : candidate[0];
|
|
365
|
+
const text = prefix(start.col, part.col) + head + candidate.map(itemText).join(" | ");
|
|
366
|
+
if (piece.length > 0 && estimateLineTokens(text) > MAX_LINE_TOKENS)
|
|
367
|
+
flush();
|
|
368
|
+
piece.push(part);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
flush();
|
|
372
|
+
return lines;
|
|
373
|
+
}
|
|
374
|
+
function fitItem(item, prefix, keyText) {
|
|
375
|
+
const overhead = estimateLineTokens(`${prefix(item.col, item.col)}${keyText} | ${item.label ?? ""}: `);
|
|
376
|
+
const budget = Math.max(16, MAX_LINE_TOKENS - overhead);
|
|
377
|
+
if (estimateLineTokens(item.value) <= budget)
|
|
378
|
+
return [item];
|
|
379
|
+
const parts = [];
|
|
380
|
+
let current = "";
|
|
381
|
+
for (const char of item.value) {
|
|
382
|
+
if (current !== "" && estimateLineTokens(current + char) > budget) {
|
|
383
|
+
parts.push({ ...item, value: current });
|
|
384
|
+
current = "";
|
|
385
|
+
}
|
|
386
|
+
current += char;
|
|
387
|
+
}
|
|
388
|
+
if (current !== "")
|
|
389
|
+
parts.push({ ...item, value: current });
|
|
390
|
+
return parts;
|
|
391
|
+
}
|
|
392
|
+
function fillsDown(merge) {
|
|
393
|
+
return merge !== undefined && merge.left === merge.right;
|
|
394
|
+
}
|
|
395
|
+
function itemText(item) {
|
|
396
|
+
return item.label === undefined ? item.value : `${item.label}: ${item.value}`;
|
|
397
|
+
}
|
|
398
|
+
function captionText(captions) {
|
|
399
|
+
if (captions.length === 0)
|
|
400
|
+
return "";
|
|
401
|
+
const joined = captions.join(" · ");
|
|
402
|
+
return ` · ${joined.length > MAX_CAPTION_CHARS ? `${joined.slice(0, MAX_CAPTION_CHARS - 1)}…` : joined}`;
|
|
403
|
+
}
|
|
404
|
+
function clean(text) {
|
|
405
|
+
return text.trim().replace(/\s*(?:\r\n|\r|\n)\s*/g, " / ").replace(/[\t\f\v]+/g, " ").replace(/\p{Cc}/gu, "");
|
|
406
|
+
}
|
|
407
|
+
function cellRange(left, right, row) {
|
|
408
|
+
const start = `${columnName(left)}${row + 1}`;
|
|
409
|
+
return left === right ? start : `${start}:${columnName(right)}${row + 1}`;
|
|
410
|
+
}
|
|
411
|
+
function columnName(col) {
|
|
412
|
+
let name = "";
|
|
413
|
+
for (let rest = col + 1;rest > 0; rest = Math.floor((rest - 1) / 26)) {
|
|
414
|
+
name = String.fromCharCode(65 + (rest - 1) % 26) + name;
|
|
415
|
+
}
|
|
416
|
+
return name;
|
|
417
|
+
}
|
|
418
|
+
function range(first, last) {
|
|
419
|
+
return Array.from({ length: last - first + 1 }, (_, index) => first + index);
|
|
420
|
+
}
|
|
421
|
+
var MAX_LINE_TOKENS = 768, MIN_HEADER_DATA_ROWS = 3, MIN_TYPED_SHARE = 0.8, MAX_COLUMNS = 16384, MAX_HEADER_CELL_CHARS = 60, MAX_CAPTION_CHARS = 120, MAX_CAPTION_BLOCK_ROWS = 3, MAX_CAPTION_GAP_ROWS = 2, COLUMN_STRIDE, NUMBER_TEXT, DATE_TEXT, YEAR_TEXT;
|
|
422
|
+
var init_spreadsheet_render = __esm(() => {
|
|
423
|
+
COLUMN_STRIDE = 1 << 20;
|
|
424
|
+
NUMBER_TEXT = /^[-+]?[₩$€£¥]?\s?(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?\s?(?:%|원|천원|만원|백만원|억원)?$|^[-+]?\.\d+%?$/;
|
|
425
|
+
DATE_TEXT = /^\d{4}[-./]\d{1,2}(?:[-./]\d{1,2})?\.?$/;
|
|
426
|
+
YEAR_TEXT = /^(?:19|20)\d{2}$/;
|
|
122
427
|
});
|
|
123
428
|
|
|
124
429
|
// src/parser/text.ts
|
|
@@ -167,6 +472,194 @@ class Parser {
|
|
|
167
472
|
version = "1";
|
|
168
473
|
}
|
|
169
474
|
|
|
475
|
+
// src/parser/csv.ts
|
|
476
|
+
import { basename, extname } from "node:path";
|
|
477
|
+
function toCell(text) {
|
|
478
|
+
return text.trim() === "" ? undefined : { text, kind: classifyText(text) };
|
|
479
|
+
}
|
|
480
|
+
function parseRows(text, delimiter, maxRows) {
|
|
481
|
+
const rows = [];
|
|
482
|
+
let total = 0;
|
|
483
|
+
let row = [];
|
|
484
|
+
let index = 0;
|
|
485
|
+
while (index < text.length) {
|
|
486
|
+
let field;
|
|
487
|
+
if (text[index] === '"') {
|
|
488
|
+
const quoted = readQuoted(text, index + 1);
|
|
489
|
+
const end = nextBoundary(text, quoted.end, delimiter);
|
|
490
|
+
field = quoted.value + text.slice(quoted.end, end);
|
|
491
|
+
index = end;
|
|
492
|
+
} else {
|
|
493
|
+
const end = nextBoundary(text, index, delimiter);
|
|
494
|
+
field = text.slice(index, end);
|
|
495
|
+
index = end;
|
|
496
|
+
}
|
|
497
|
+
row.push(field);
|
|
498
|
+
if (index >= text.length)
|
|
499
|
+
break;
|
|
500
|
+
if (text[index] === delimiter) {
|
|
501
|
+
index++;
|
|
502
|
+
if (index >= text.length)
|
|
503
|
+
row.push("");
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
index += text[index] === "\r" && text[index + 1] === `
|
|
507
|
+
` ? 2 : 1;
|
|
508
|
+
if (total < maxRows)
|
|
509
|
+
rows.push(row);
|
|
510
|
+
total++;
|
|
511
|
+
row = [];
|
|
512
|
+
}
|
|
513
|
+
if (row.length > 0) {
|
|
514
|
+
if (total < maxRows)
|
|
515
|
+
rows.push(row);
|
|
516
|
+
total++;
|
|
517
|
+
}
|
|
518
|
+
return { rows, total };
|
|
519
|
+
}
|
|
520
|
+
function readQuoted(text, start) {
|
|
521
|
+
let value = "";
|
|
522
|
+
let cursor = start;
|
|
523
|
+
for (;; ) {
|
|
524
|
+
const quote = text.indexOf('"', cursor);
|
|
525
|
+
if (quote === -1)
|
|
526
|
+
return { value: value + text.slice(cursor), end: text.length };
|
|
527
|
+
value += text.slice(cursor, quote);
|
|
528
|
+
if (text[quote + 1] !== '"')
|
|
529
|
+
return { value, end: quote + 1 };
|
|
530
|
+
value += '"';
|
|
531
|
+
cursor = quote + 2;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
function nextBoundary(text, from, delimiter) {
|
|
535
|
+
for (let index = from;index < text.length; index++) {
|
|
536
|
+
const char = text[index];
|
|
537
|
+
if (char === delimiter || char === `
|
|
538
|
+
` || char === "\r")
|
|
539
|
+
return index;
|
|
540
|
+
}
|
|
541
|
+
return text.length;
|
|
542
|
+
}
|
|
543
|
+
function sniffDelimiter(text) {
|
|
544
|
+
const lines = leadingLines(text);
|
|
545
|
+
let best = CSV_DELIMITERS[0];
|
|
546
|
+
let bestScore = 0;
|
|
547
|
+
for (const candidate of CSV_DELIMITERS) {
|
|
548
|
+
const counts = lines.map((line) => countOutsideQuotes(line, candidate));
|
|
549
|
+
const first = counts[0] ?? 0;
|
|
550
|
+
if (first === 0)
|
|
551
|
+
continue;
|
|
552
|
+
const score = counts.filter((count) => count === first).length;
|
|
553
|
+
if (score > bestScore) {
|
|
554
|
+
best = candidate;
|
|
555
|
+
bestScore = score;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return best;
|
|
559
|
+
}
|
|
560
|
+
function leadingLines(text) {
|
|
561
|
+
const lines = [];
|
|
562
|
+
let start = 0;
|
|
563
|
+
let quoted = false;
|
|
564
|
+
for (let index = 0;index < text.length && lines.length < SNIFF_LINES; index++) {
|
|
565
|
+
const char = text[index];
|
|
566
|
+
if (char === '"')
|
|
567
|
+
quoted = !quoted;
|
|
568
|
+
else if (!quoted && (char === `
|
|
569
|
+
` || char === "\r")) {
|
|
570
|
+
if (index > start)
|
|
571
|
+
lines.push(text.slice(start, index));
|
|
572
|
+
start = index + 1;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (lines.length < SNIFF_LINES && start < text.length)
|
|
576
|
+
lines.push(text.slice(start));
|
|
577
|
+
return lines;
|
|
578
|
+
}
|
|
579
|
+
function countOutsideQuotes(line, delimiter) {
|
|
580
|
+
let count = 0;
|
|
581
|
+
let quoted = false;
|
|
582
|
+
for (const char of line) {
|
|
583
|
+
if (char === '"')
|
|
584
|
+
quoted = !quoted;
|
|
585
|
+
else if (!quoted && char === delimiter)
|
|
586
|
+
count++;
|
|
587
|
+
}
|
|
588
|
+
return count;
|
|
589
|
+
}
|
|
590
|
+
var DELIMITED_EXTENSIONS, DEFAULT_MAX_ROWS = 1e5, SNIFF_LINES = 50, CSV_DELIMITERS, SEPARATOR_DIRECTIVE, CsvParser;
|
|
591
|
+
var init_csv = __esm(() => {
|
|
592
|
+
init_spreadsheet_render();
|
|
593
|
+
init_text();
|
|
594
|
+
DELIMITED_EXTENSIONS = [".csv", ".tsv"];
|
|
595
|
+
CSV_DELIMITERS = [",", ";", "\t", "|"];
|
|
596
|
+
SEPARATOR_DIRECTIVE = /^sep=(.)\r?\n/i;
|
|
597
|
+
CsvParser = class CsvParser extends Parser {
|
|
598
|
+
name = "csv";
|
|
599
|
+
extensions = DELIMITED_EXTENSIONS;
|
|
600
|
+
version = "2";
|
|
601
|
+
#maxRows;
|
|
602
|
+
constructor(options = {}) {
|
|
603
|
+
super();
|
|
604
|
+
this.#maxRows = options.maxRows ?? DEFAULT_MAX_ROWS;
|
|
605
|
+
}
|
|
606
|
+
async parse(input) {
|
|
607
|
+
const extension = extname(input.virtualPath);
|
|
608
|
+
const format = extension.slice(1).toLowerCase();
|
|
609
|
+
let text = decodeText(input.bytes).replace(/^\uFEFF/, "");
|
|
610
|
+
const directive = SEPARATOR_DIRECTIVE.exec(text);
|
|
611
|
+
if (directive !== null)
|
|
612
|
+
text = text.slice(directive[0].length);
|
|
613
|
+
const delimiter = directive?.[1] ?? (format === "tsv" ? "\t" : sniffDelimiter(text));
|
|
614
|
+
const { rows, total } = parseRows(text, delimiter, this.#maxRows);
|
|
615
|
+
const diagnostics = total > this.#maxRows ? [
|
|
616
|
+
{
|
|
617
|
+
code: "parser-warning",
|
|
618
|
+
severity: "warning",
|
|
619
|
+
message: `"${basename(input.virtualPath)}": indexed the first ${this.#maxRows} of ${total} rows`
|
|
620
|
+
}
|
|
621
|
+
] : [];
|
|
622
|
+
const grid = { name: basename(input.virtualPath, extension), rows: rows.map((row) => row.map(toCell)) };
|
|
623
|
+
return {
|
|
624
|
+
markdown: normalizeMarkdown(renderWorkbook([grid])),
|
|
625
|
+
metadata: { parser: this.name, format },
|
|
626
|
+
...diagnostics.length > 0 ? { diagnostics } : {}
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
// src/parser/errors.ts
|
|
633
|
+
function messageFrom(cause) {
|
|
634
|
+
if (cause instanceof Error)
|
|
635
|
+
return cause.message;
|
|
636
|
+
if (typeof cause === "string")
|
|
637
|
+
return cause;
|
|
638
|
+
return "unknown parser failure";
|
|
639
|
+
}
|
|
640
|
+
var ParseError, ParseIsolationError;
|
|
641
|
+
var init_errors = __esm(() => {
|
|
642
|
+
ParseError = class ParseError extends Error {
|
|
643
|
+
parserName;
|
|
644
|
+
virtualPath;
|
|
645
|
+
constructor(parserName, virtualPath, cause) {
|
|
646
|
+
super(`Parser "${parserName}" failed for ${virtualPath}: ${messageFrom(cause)}`);
|
|
647
|
+
this.name = "ParseError";
|
|
648
|
+
this.parserName = parserName;
|
|
649
|
+
this.virtualPath = virtualPath;
|
|
650
|
+
this.cause = cause;
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
ParseIsolationError = class ParseIsolationError extends Error {
|
|
654
|
+
code;
|
|
655
|
+
constructor(code, message) {
|
|
656
|
+
super(message);
|
|
657
|
+
this.name = "ParseIsolationError";
|
|
658
|
+
this.code = code;
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
});
|
|
662
|
+
|
|
170
663
|
// src/parser/eml.ts
|
|
171
664
|
import { simpleParser } from "mailparser";
|
|
172
665
|
function addressText(address) {
|
|
@@ -250,7 +743,7 @@ var KORDOC_VERSION, KORDOC_EXTENSIONS, KORDOC_IMAGE_EXTENSIONS, defaultParse = a
|
|
|
250
743
|
var init_kordoc = __esm(() => {
|
|
251
744
|
init_errors();
|
|
252
745
|
KORDOC_VERSION = installedKordocVersion();
|
|
253
|
-
KORDOC_EXTENSIONS = [".hwp", ".hwpx", ".hml", ".hwpml", ".pdf", ".docx"
|
|
746
|
+
KORDOC_EXTENSIONS = [".hwp", ".hwpx", ".hml", ".hwpml", ".pdf", ".docx"];
|
|
254
747
|
KORDOC_IMAGE_EXTENSIONS = [".png", ".jpg", ".jpeg", ".webp"];
|
|
255
748
|
KordocParser = class KordocParser extends Parser {
|
|
256
749
|
name = "kordoc";
|
|
@@ -665,7 +1158,7 @@ var init_plain_text = __esm(() => {
|
|
|
665
1158
|
});
|
|
666
1159
|
|
|
667
1160
|
// src/parser/registry.ts
|
|
668
|
-
import { extname } from "node:path";
|
|
1161
|
+
import { extname as extname2 } from "node:path";
|
|
669
1162
|
|
|
670
1163
|
class ParserRegistry {
|
|
671
1164
|
parsersByExtension = new Map;
|
|
@@ -684,7 +1177,7 @@ class ParserRegistry {
|
|
|
684
1177
|
}
|
|
685
1178
|
}
|
|
686
1179
|
getForVirtualPath(virtualPath) {
|
|
687
|
-
return this.parsersByExtension.get(normalizeExtension(
|
|
1180
|
+
return this.parsersByExtension.get(normalizeExtension(extname2(virtualPath)));
|
|
688
1181
|
}
|
|
689
1182
|
list() {
|
|
690
1183
|
return Array.from(new Set(this.parsersByExtension.values()));
|
|
@@ -696,6 +1189,149 @@ function normalizeExtension(extension) {
|
|
|
696
1189
|
}
|
|
697
1190
|
var init_registry = () => {};
|
|
698
1191
|
|
|
1192
|
+
// src/parser/spreadsheet.ts
|
|
1193
|
+
import { extname as extname3 } from "node:path";
|
|
1194
|
+
import * as XLSX from "xlsx";
|
|
1195
|
+
function assertWorkbookSignature(format, bytes) {
|
|
1196
|
+
if (startsWith(bytes, ZIP_SIGNATURE) || startsWith(bytes, OLE_SIGNATURE))
|
|
1197
|
+
return;
|
|
1198
|
+
const head = new TextDecoder().decode(bytes.subarray(0, 64)).replace(/^\uFEFF/, "").trimStart();
|
|
1199
|
+
if (!head.startsWith("<")) {
|
|
1200
|
+
throw new Error(`not a ${format} workbook: neither a ZIP or OLE2 file nor HTML/XML markup`);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
function startsWith(bytes, prefix) {
|
|
1204
|
+
return prefix.every((byte, index) => bytes[index] === byte);
|
|
1205
|
+
}
|
|
1206
|
+
function toGrid(name, sheet, hidden, date1904) {
|
|
1207
|
+
const data = sheet?.["!data"] ?? [];
|
|
1208
|
+
return {
|
|
1209
|
+
name,
|
|
1210
|
+
hidden: hidden !== undefined && hidden !== 0,
|
|
1211
|
+
rows: data.map((row) => row?.map((cell) => cell === undefined ? undefined : toCell2(cell, date1904))),
|
|
1212
|
+
merges: (sheet?.["!merges"] ?? []).map((merge) => ({
|
|
1213
|
+
top: merge.s.r,
|
|
1214
|
+
left: merge.s.c,
|
|
1215
|
+
bottom: merge.e.r,
|
|
1216
|
+
right: merge.e.c
|
|
1217
|
+
}))
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
function toCell2(cell, date1904) {
|
|
1221
|
+
const comment = (cell.c ?? []).map((note) => note.t?.trim() ?? "").filter((text) => text !== "").join(" / ");
|
|
1222
|
+
const shown = displayed(cell, date1904);
|
|
1223
|
+
if (shown === undefined)
|
|
1224
|
+
return;
|
|
1225
|
+
return comment === "" ? shown : { ...shown, comment };
|
|
1226
|
+
}
|
|
1227
|
+
function displayed(cell, date1904) {
|
|
1228
|
+
if (cell.v === undefined || cell.v === null) {
|
|
1229
|
+
return cell.f === undefined ? undefined : { text: `=${cell.f}`, kind: "formula" };
|
|
1230
|
+
}
|
|
1231
|
+
switch (cell.t) {
|
|
1232
|
+
case "n":
|
|
1233
|
+
return typeof cell.v === "number" ? formatNumber(cell.v, cell.z, date1904) : textCell(String(cell.v));
|
|
1234
|
+
case "b":
|
|
1235
|
+
return { text: cell.v === true ? "TRUE" : "FALSE", kind: "boolean" };
|
|
1236
|
+
case "e":
|
|
1237
|
+
return { text: cell.w ?? "#ERROR", kind: "error" };
|
|
1238
|
+
case "d":
|
|
1239
|
+
return { text: cell.w ?? String(cell.v), kind: "date" };
|
|
1240
|
+
case "z":
|
|
1241
|
+
return;
|
|
1242
|
+
default:
|
|
1243
|
+
return textCell(String(cell.v));
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
function textCell(text) {
|
|
1247
|
+
return text.trim() === "" ? undefined : { text, kind: classifyText(text) };
|
|
1248
|
+
}
|
|
1249
|
+
function formatNumber(value, format, date1904) {
|
|
1250
|
+
const plain = formatGeneral(value);
|
|
1251
|
+
const code = typeof format === "string" ? format : format === undefined ? "General" : XLSX.SSF.get_table()[format];
|
|
1252
|
+
if (code === undefined || code === "General" || /\[DBNum\d\]/i.test(code))
|
|
1253
|
+
return { text: plain, kind: "number" };
|
|
1254
|
+
const kind = XLSX.SSF.is_date(code) ? "date" : "number";
|
|
1255
|
+
let shown;
|
|
1256
|
+
try {
|
|
1257
|
+
shown = XLSX.SSF.format(code, value, { date1904 }).trim();
|
|
1258
|
+
} catch {
|
|
1259
|
+
return { text: plain, kind };
|
|
1260
|
+
}
|
|
1261
|
+
if (shown === "")
|
|
1262
|
+
return { text: plain, kind };
|
|
1263
|
+
return { text: kind === "number" && hidesMagnitude(code) ? `${shown} (${plain})` : shown, kind };
|
|
1264
|
+
}
|
|
1265
|
+
function formatGeneral(value) {
|
|
1266
|
+
if (Number.isInteger(value))
|
|
1267
|
+
return String(value);
|
|
1268
|
+
return String(Number(value.toPrecision(15)));
|
|
1269
|
+
}
|
|
1270
|
+
function hidesMagnitude(code) {
|
|
1271
|
+
const bare = code.replace(/"[^"]*"/g, "").replace(/\\./g, "").replace(/\[[^\]]*\]/g, "");
|
|
1272
|
+
return /[0#?],+(?![0#?,])/.test(bare);
|
|
1273
|
+
}
|
|
1274
|
+
var SPREADSHEET_EXTENSIONS, DEFAULT_MAX_ROWS_PER_SHEET = 1e5, ZIP_SIGNATURE, OLE_SIGNATURE, SpreadsheetParser;
|
|
1275
|
+
var init_spreadsheet = __esm(() => {
|
|
1276
|
+
init_errors();
|
|
1277
|
+
init_spreadsheet_render();
|
|
1278
|
+
init_text();
|
|
1279
|
+
SPREADSHEET_EXTENSIONS = [".xlsx", ".xlsm", ".xlsb", ".xls", ".ods"];
|
|
1280
|
+
ZIP_SIGNATURE = [80, 75];
|
|
1281
|
+
OLE_SIGNATURE = [208, 207, 17, 224, 161, 177, 26, 225];
|
|
1282
|
+
SpreadsheetParser = class SpreadsheetParser extends Parser {
|
|
1283
|
+
name = "spreadsheet";
|
|
1284
|
+
extensions = SPREADSHEET_EXTENSIONS;
|
|
1285
|
+
version = `2+sheetjs-${XLSX.version}`;
|
|
1286
|
+
#maxRowsPerSheet;
|
|
1287
|
+
constructor(options = {}) {
|
|
1288
|
+
super();
|
|
1289
|
+
this.#maxRowsPerSheet = options.maxRowsPerSheet ?? DEFAULT_MAX_ROWS_PER_SHEET;
|
|
1290
|
+
}
|
|
1291
|
+
async parse(input) {
|
|
1292
|
+
const format = extname3(input.virtualPath).slice(1).toLowerCase();
|
|
1293
|
+
let workbook;
|
|
1294
|
+
try {
|
|
1295
|
+
assertWorkbookSignature(format, input.bytes);
|
|
1296
|
+
workbook = XLSX.read(input.bytes, {
|
|
1297
|
+
type: "array",
|
|
1298
|
+
dense: true,
|
|
1299
|
+
cellFormula: true,
|
|
1300
|
+
cellNF: true,
|
|
1301
|
+
cellDates: false,
|
|
1302
|
+
sheetRows: this.#maxRowsPerSheet,
|
|
1303
|
+
raw: true
|
|
1304
|
+
});
|
|
1305
|
+
} catch (cause) {
|
|
1306
|
+
throw new ParseError(this.name, input.virtualPath, cause);
|
|
1307
|
+
}
|
|
1308
|
+
const date1904 = workbook.Workbook?.WBProps?.date1904 === true;
|
|
1309
|
+
const diagnostics = [];
|
|
1310
|
+
const grids = workbook.SheetNames.map((name, index) => {
|
|
1311
|
+
const sheet = workbook.Sheets[name];
|
|
1312
|
+
const fullRef = sheet?.["!fullref"];
|
|
1313
|
+
if (fullRef !== undefined) {
|
|
1314
|
+
const full = XLSX.utils.decode_range(fullRef);
|
|
1315
|
+
const total = full.e.r - full.s.r + 1;
|
|
1316
|
+
if (total > this.#maxRowsPerSheet) {
|
|
1317
|
+
diagnostics.push({
|
|
1318
|
+
code: "parser-warning",
|
|
1319
|
+
severity: "warning",
|
|
1320
|
+
message: `sheet "${name}": indexed the first ${this.#maxRowsPerSheet} of ${total} rows`
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
return toGrid(name, sheet, workbook.Workbook?.Sheets?.[index]?.Hidden, date1904);
|
|
1325
|
+
});
|
|
1326
|
+
return {
|
|
1327
|
+
markdown: normalizeMarkdown(renderWorkbook(grids)),
|
|
1328
|
+
metadata: { parser: this.name, format },
|
|
1329
|
+
...diagnostics.length > 0 ? { diagnostics } : {}
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
};
|
|
1333
|
+
});
|
|
1334
|
+
|
|
699
1335
|
// src/parser/defaults.ts
|
|
700
1336
|
import { join as join2 } from "node:path";
|
|
701
1337
|
function tesseractCachePathFor(workspacePath) {
|
|
@@ -726,18 +1362,22 @@ function createDefaultParserRegistry(options = {}) {
|
|
|
726
1362
|
return new ParserRegistry([
|
|
727
1363
|
new PlainTextParser,
|
|
728
1364
|
new KordocParser(kordocOptions),
|
|
1365
|
+
new SpreadsheetParser,
|
|
1366
|
+
new CsvParser,
|
|
729
1367
|
new PptxParser,
|
|
730
1368
|
new EmlParser
|
|
731
1369
|
]);
|
|
732
1370
|
}
|
|
733
1371
|
var init_defaults = __esm(() => {
|
|
734
1372
|
init_language();
|
|
1373
|
+
init_csv();
|
|
735
1374
|
init_eml();
|
|
736
1375
|
init_kordoc();
|
|
737
1376
|
init_ocr_engines();
|
|
738
1377
|
init_office();
|
|
739
1378
|
init_plain_text();
|
|
740
1379
|
init_registry();
|
|
1380
|
+
init_spreadsheet();
|
|
741
1381
|
});
|
|
742
1382
|
|
|
743
1383
|
// src/parser/parse-worker.ts
|