@cj-tech-master/excelts 7.6.0 → 8.0.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 +99 -577
- package/README_zh.md +101 -577
- package/dist/browser/index.browser.d.ts +3 -0
- package/dist/browser/index.browser.js +2 -0
- package/dist/browser/index.d.ts +3 -0
- package/dist/browser/index.js +2 -0
- package/dist/browser/modules/archive/compression/compress.browser.js +4 -4
- package/dist/browser/modules/archive/compression/deflate-fallback.d.ts +24 -22
- package/dist/browser/modules/archive/compression/deflate-fallback.js +664 -360
- package/dist/browser/modules/archive/compression/streaming-compress.browser.d.ts +7 -0
- package/dist/browser/modules/archive/compression/streaming-compress.browser.js +15 -3
- package/dist/browser/modules/archive/compression/streaming-compress.d.ts +5 -0
- package/dist/browser/modules/archive/compression/streaming-compress.js +7 -0
- package/dist/browser/modules/archive/zip/stream.js +27 -3
- package/dist/browser/modules/excel/workbook.browser.d.ts +72 -0
- package/dist/browser/modules/excel/workbook.browser.js +226 -0
- package/dist/browser/modules/excel/workbook.d.ts +32 -1
- package/dist/browser/modules/excel/workbook.js +47 -2
- package/dist/browser/modules/excel/xlsx/xlsx.browser.js +42 -4
- package/dist/browser/modules/markdown/constants.d.ts +30 -0
- package/dist/browser/modules/markdown/constants.js +30 -0
- package/dist/browser/modules/markdown/errors.d.ts +21 -0
- package/dist/browser/modules/markdown/errors.js +23 -0
- package/dist/browser/modules/markdown/format/index.d.ts +54 -0
- package/dist/browser/modules/markdown/format/index.js +307 -0
- package/dist/browser/modules/markdown/index.d.ts +15 -0
- package/dist/browser/modules/markdown/index.js +22 -0
- package/dist/browser/modules/markdown/parse/index.d.ts +70 -0
- package/dist/browser/modules/markdown/parse/index.js +428 -0
- package/dist/browser/modules/markdown/types.d.ts +130 -0
- package/dist/browser/modules/markdown/types.js +6 -0
- package/dist/cjs/index.js +5 -1
- package/dist/cjs/modules/archive/compression/compress.browser.js +4 -4
- package/dist/cjs/modules/archive/compression/deflate-fallback.js +664 -360
- package/dist/cjs/modules/archive/compression/streaming-compress.browser.js +15 -2
- package/dist/cjs/modules/archive/compression/streaming-compress.js +8 -0
- package/dist/cjs/modules/archive/zip/stream.js +26 -2
- package/dist/cjs/modules/excel/workbook.browser.js +226 -0
- package/dist/cjs/modules/excel/workbook.js +46 -1
- package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +42 -4
- package/dist/cjs/modules/markdown/constants.js +33 -0
- package/dist/cjs/modules/markdown/errors.js +28 -0
- package/dist/cjs/modules/markdown/format/index.js +310 -0
- package/dist/cjs/modules/markdown/index.js +30 -0
- package/dist/cjs/modules/markdown/parse/index.js +432 -0
- package/dist/cjs/modules/markdown/types.js +7 -0
- package/dist/esm/index.browser.js +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/modules/archive/compression/compress.browser.js +4 -4
- package/dist/esm/modules/archive/compression/deflate-fallback.js +664 -360
- package/dist/esm/modules/archive/compression/streaming-compress.browser.js +15 -3
- package/dist/esm/modules/archive/compression/streaming-compress.js +7 -0
- package/dist/esm/modules/archive/zip/stream.js +27 -3
- package/dist/esm/modules/excel/workbook.browser.js +226 -0
- package/dist/esm/modules/excel/workbook.js +47 -2
- package/dist/esm/modules/excel/xlsx/xlsx.browser.js +42 -4
- package/dist/esm/modules/markdown/constants.js +30 -0
- package/dist/esm/modules/markdown/errors.js +23 -0
- package/dist/esm/modules/markdown/format/index.js +307 -0
- package/dist/esm/modules/markdown/index.js +22 -0
- package/dist/esm/modules/markdown/parse/index.js +428 -0
- package/dist/esm/modules/markdown/types.js +6 -0
- package/dist/iife/excelts.iife.js +1342 -283
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +38 -34
- package/dist/types/index.browser.d.ts +3 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/modules/archive/compression/deflate-fallback.d.ts +24 -22
- package/dist/types/modules/archive/compression/streaming-compress.browser.d.ts +7 -0
- package/dist/types/modules/archive/compression/streaming-compress.d.ts +5 -0
- package/dist/types/modules/excel/workbook.browser.d.ts +72 -0
- package/dist/types/modules/excel/workbook.d.ts +32 -1
- package/dist/types/modules/markdown/constants.d.ts +30 -0
- package/dist/types/modules/markdown/errors.d.ts +21 -0
- package/dist/types/modules/markdown/format/index.d.ts +54 -0
- package/dist/types/modules/markdown/index.d.ts +15 -0
- package/dist/types/modules/markdown/parse/index.d.ts +70 -0
- package/dist/types/modules/markdown/types.d.ts +130 -0
- package/package.json +56 -32
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Markdown Table Parser
|
|
4
|
+
*
|
|
5
|
+
* Parses Markdown tables into structured data.
|
|
6
|
+
*
|
|
7
|
+
* Supports:
|
|
8
|
+
* - Standard GFM (GitHub Flavored Markdown) table syntax
|
|
9
|
+
* - Column alignment detection via separator row
|
|
10
|
+
* - Escaped pipes (`\|`) in cell content
|
|
11
|
+
* - Tables with or without leading/trailing pipes
|
|
12
|
+
* - Tolerant parsing (mismatched column counts, extra whitespace)
|
|
13
|
+
* - Multiline cell content via `<br>` / `<br/>` / `<br />` tags
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const result = parseMarkdown("| Name | Age |\n| --- | --- |\n| Alice | 30 |");
|
|
18
|
+
* // result.headers = ["Name", "Age"]
|
|
19
|
+
* // result.rows = [["Alice", "30"]]
|
|
20
|
+
* // result.alignments = ["none", "none"]
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.parseMarkdown = parseMarkdown;
|
|
25
|
+
exports.parseMarkdownAll = parseMarkdownAll;
|
|
26
|
+
const constants_1 = require("../constants");
|
|
27
|
+
const errors_1 = require("../errors");
|
|
28
|
+
// =============================================================================
|
|
29
|
+
// Character Codes (avoid repeated charCodeAt comparisons with magic numbers)
|
|
30
|
+
// =============================================================================
|
|
31
|
+
const CH_PIPE = 0x7c; // |
|
|
32
|
+
const CH_BACKSLASH = 0x5c; // \
|
|
33
|
+
const CH_COLON = 0x3a; // :
|
|
34
|
+
const CH_DASH = 0x2d; // -
|
|
35
|
+
const CH_SPACE = 0x20; // space
|
|
36
|
+
const CH_TAB = 0x09; // tab
|
|
37
|
+
function resolveParseOpts(options) {
|
|
38
|
+
return {
|
|
39
|
+
trim: options.trim !== false,
|
|
40
|
+
unescape: options.unescape !== false,
|
|
41
|
+
skipEmpty: options.skipEmptyRows !== false,
|
|
42
|
+
maxRows: options.maxRows,
|
|
43
|
+
convertBr: options.convertBr === true
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// =============================================================================
|
|
47
|
+
// Internal Helpers
|
|
48
|
+
// =============================================================================
|
|
49
|
+
/**
|
|
50
|
+
* Split a Markdown table row into cell values.
|
|
51
|
+
* Handles escaped pipes (`\|`) correctly by scanning character by character.
|
|
52
|
+
*
|
|
53
|
+
* Optimized: uses start/end index tracking with `slice()` instead of
|
|
54
|
+
* character-by-character string concatenation to avoid O(n²) worst case.
|
|
55
|
+
*/
|
|
56
|
+
function splitRow(line) {
|
|
57
|
+
const cells = [];
|
|
58
|
+
const len = line.length;
|
|
59
|
+
// Skip leading pipe
|
|
60
|
+
let i = len > 0 && line.charCodeAt(0) === CH_PIPE ? 1 : 0;
|
|
61
|
+
// Check for trailing pipe (to exclude it from the last cell)
|
|
62
|
+
// Must count consecutive backslashes before the pipe:
|
|
63
|
+
// even count (0, 2, 4...) → backslashes are all escaped, pipe is real
|
|
64
|
+
// odd count (1, 3, 5...) → last backslash escapes the pipe
|
|
65
|
+
let end = len;
|
|
66
|
+
if (len > 1 && line.charCodeAt(len - 1) === CH_PIPE) {
|
|
67
|
+
let backslashCount = 0;
|
|
68
|
+
let k = len - 2;
|
|
69
|
+
while (k >= 0 && line.charCodeAt(k) === CH_BACKSLASH) {
|
|
70
|
+
backslashCount++;
|
|
71
|
+
k--;
|
|
72
|
+
}
|
|
73
|
+
if (backslashCount % 2 === 0) {
|
|
74
|
+
end = len - 1;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Track the start of the current cell segment
|
|
78
|
+
// We collect segments (between escape sequences) to minimize allocations
|
|
79
|
+
let segStart = i;
|
|
80
|
+
let current = "";
|
|
81
|
+
let hasEscape = false;
|
|
82
|
+
while (i < end) {
|
|
83
|
+
const ch = line.charCodeAt(i);
|
|
84
|
+
if (ch === CH_BACKSLASH && i + 1 < end) {
|
|
85
|
+
// Escape sequence: flush preceding segment, add escape pair
|
|
86
|
+
hasEscape = true;
|
|
87
|
+
if (i > segStart) {
|
|
88
|
+
current += line.slice(segStart, i);
|
|
89
|
+
}
|
|
90
|
+
current += line.slice(i, i + 2);
|
|
91
|
+
i += 2;
|
|
92
|
+
segStart = i;
|
|
93
|
+
}
|
|
94
|
+
else if (ch === CH_PIPE) {
|
|
95
|
+
// Cell boundary: flush and push
|
|
96
|
+
if (hasEscape) {
|
|
97
|
+
if (i > segStart) {
|
|
98
|
+
current += line.slice(segStart, i);
|
|
99
|
+
}
|
|
100
|
+
cells.push(current);
|
|
101
|
+
current = "";
|
|
102
|
+
hasEscape = false;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
cells.push(line.slice(segStart, i));
|
|
106
|
+
}
|
|
107
|
+
i++;
|
|
108
|
+
segStart = i;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
i++;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Push the last cell
|
|
115
|
+
if (hasEscape) {
|
|
116
|
+
if (end > segStart) {
|
|
117
|
+
current += line.slice(segStart, end);
|
|
118
|
+
}
|
|
119
|
+
cells.push(current);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
cells.push(line.slice(segStart, end));
|
|
123
|
+
}
|
|
124
|
+
return cells;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Determine column alignment from a separator cell.
|
|
128
|
+
*
|
|
129
|
+
* - `:---:` → center
|
|
130
|
+
* - `:---` → left
|
|
131
|
+
* - `---:` → right
|
|
132
|
+
* - `---` → none
|
|
133
|
+
*/
|
|
134
|
+
function parseAlignment(cell) {
|
|
135
|
+
const trimmed = cell.trim();
|
|
136
|
+
const tLen = trimmed.length;
|
|
137
|
+
if (tLen === 0) {
|
|
138
|
+
return "none";
|
|
139
|
+
}
|
|
140
|
+
const leftColon = trimmed.charCodeAt(0) === CH_COLON;
|
|
141
|
+
const rightColon = trimmed.charCodeAt(tLen - 1) === CH_COLON;
|
|
142
|
+
if (leftColon && rightColon) {
|
|
143
|
+
return "center";
|
|
144
|
+
}
|
|
145
|
+
if (leftColon) {
|
|
146
|
+
return "left";
|
|
147
|
+
}
|
|
148
|
+
if (rightColon) {
|
|
149
|
+
return "right";
|
|
150
|
+
}
|
|
151
|
+
return "none";
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Check if a cell string is a valid separator cell.
|
|
155
|
+
* Hand-rolled check replacing regex for better performance.
|
|
156
|
+
* Pattern: optional whitespace, optional colon, one or more dashes, optional colon, optional whitespace.
|
|
157
|
+
*/
|
|
158
|
+
function isSeparatorCell(cell) {
|
|
159
|
+
const len = cell.length;
|
|
160
|
+
let i = 0;
|
|
161
|
+
// Skip leading whitespace
|
|
162
|
+
while (i < len) {
|
|
163
|
+
const ch = cell.charCodeAt(i);
|
|
164
|
+
if (ch !== CH_SPACE && ch !== CH_TAB) {
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
i++;
|
|
168
|
+
}
|
|
169
|
+
// Optional leading colon
|
|
170
|
+
if (i < len && cell.charCodeAt(i) === CH_COLON) {
|
|
171
|
+
i++;
|
|
172
|
+
}
|
|
173
|
+
// At least one dash required
|
|
174
|
+
const dashStart = i;
|
|
175
|
+
while (i < len && cell.charCodeAt(i) === CH_DASH) {
|
|
176
|
+
i++;
|
|
177
|
+
}
|
|
178
|
+
if (i === dashStart) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
// Optional trailing colon
|
|
182
|
+
if (i < len && cell.charCodeAt(i) === CH_COLON) {
|
|
183
|
+
i++;
|
|
184
|
+
}
|
|
185
|
+
// Skip trailing whitespace
|
|
186
|
+
while (i < len) {
|
|
187
|
+
const ch = cell.charCodeAt(i);
|
|
188
|
+
if (ch !== CH_SPACE && ch !== CH_TAB) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
i++;
|
|
192
|
+
}
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Check if a line is a valid separator row.
|
|
197
|
+
* A separator row consists entirely of cells matching the pattern `:?-+:?`.
|
|
198
|
+
*/
|
|
199
|
+
function isSeparatorRow(cells) {
|
|
200
|
+
if (cells.length === 0) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
for (let i = 0; i < cells.length; i++) {
|
|
204
|
+
if (!isSeparatorCell(cells[i])) {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Process cell content: trim, optionally unescape, and optionally convert `<br>` to newlines.
|
|
212
|
+
*/
|
|
213
|
+
function processCell(value, opts) {
|
|
214
|
+
let result = opts.trim ? value.trim() : value;
|
|
215
|
+
if (opts.unescape) {
|
|
216
|
+
result = result.replace(constants_1.UNESCAPE_REGEX, "$1");
|
|
217
|
+
}
|
|
218
|
+
if (opts.convertBr) {
|
|
219
|
+
result = result.replace(constants_1.BR_TAG_REGEX, "\n");
|
|
220
|
+
}
|
|
221
|
+
return result;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Normalize a row to the expected column count.
|
|
225
|
+
* - If row has fewer cells, pad with empty strings
|
|
226
|
+
* - If row has more cells, truncate
|
|
227
|
+
*/
|
|
228
|
+
function normalizeRow(cells, columnCount, opts) {
|
|
229
|
+
const row = new Array(columnCount);
|
|
230
|
+
for (let i = 0; i < columnCount; i++) {
|
|
231
|
+
row[i] = i < cells.length ? processCell(cells[i], opts) : "";
|
|
232
|
+
}
|
|
233
|
+
return row;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Check if a row is empty (all cells are empty strings).
|
|
237
|
+
*/
|
|
238
|
+
function isEmptyRow(row) {
|
|
239
|
+
for (let i = 0; i < row.length; i++) {
|
|
240
|
+
if (row[i] !== "") {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Check if a line could be part of a table (contains a pipe character).
|
|
248
|
+
*/
|
|
249
|
+
function isTableLine(line) {
|
|
250
|
+
return line.indexOf("|") !== -1;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Check if a line starts with a pipe (after optional leading whitespace).
|
|
254
|
+
* Used to determine the table's "piped" style for data row validation.
|
|
255
|
+
*/
|
|
256
|
+
function startsWithPipe(line) {
|
|
257
|
+
const len = line.length;
|
|
258
|
+
let i = 0;
|
|
259
|
+
while (i < len) {
|
|
260
|
+
const ch = line.charCodeAt(i);
|
|
261
|
+
if (ch !== CH_SPACE && ch !== CH_TAB) {
|
|
262
|
+
return ch === CH_PIPE;
|
|
263
|
+
}
|
|
264
|
+
i++;
|
|
265
|
+
}
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Check if a line could be a separator candidate (contains a dash).
|
|
270
|
+
*/
|
|
271
|
+
function hasDash(line) {
|
|
272
|
+
return line.indexOf("-") !== -1;
|
|
273
|
+
}
|
|
274
|
+
// =============================================================================
|
|
275
|
+
// Core Table Parser (shared between parseMarkdown and parseMarkdownAll)
|
|
276
|
+
// =============================================================================
|
|
277
|
+
/**
|
|
278
|
+
* Attempt to parse a table starting at line index `startLine`.
|
|
279
|
+
*
|
|
280
|
+
* Returns `{ result, endLine }` if a valid table starts here, or `null` otherwise.
|
|
281
|
+
*/
|
|
282
|
+
function parseTableAt(lines, startLine, lineCount, opts) {
|
|
283
|
+
if (startLine >= lineCount - 1) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
const line = lines[startLine].trim();
|
|
287
|
+
// Skip empty lines and non-table content
|
|
288
|
+
if (line === "" || !isTableLine(line)) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
// Candidate header row
|
|
292
|
+
const headerCells = splitRow(line);
|
|
293
|
+
if (headerCells.length < 1) {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
// Check if the next line is a valid separator row
|
|
297
|
+
const separatorLine = lines[startLine + 1].trim();
|
|
298
|
+
if (separatorLine === "" || !hasDash(separatorLine)) {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
const separatorCells = splitRow(separatorLine);
|
|
302
|
+
if (!isSeparatorRow(separatorCells)) {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
// Valid table found — extract headers and alignments
|
|
306
|
+
const columnCount = headerCells.length;
|
|
307
|
+
const headers = new Array(columnCount);
|
|
308
|
+
const alignments = new Array(columnCount);
|
|
309
|
+
for (let c = 0; c < columnCount; c++) {
|
|
310
|
+
headers[c] = processCell(headerCells[c], opts);
|
|
311
|
+
alignments[c] = c < separatorCells.length ? parseAlignment(separatorCells[c]) : "none";
|
|
312
|
+
}
|
|
313
|
+
// Determine if this is a "piped" table (header starts with `|`).
|
|
314
|
+
// When the header has a leading pipe, data rows must also start with `|`.
|
|
315
|
+
// This prevents prose like "This has a | pipe" from being swallowed as data.
|
|
316
|
+
const piped = startsWithPipe(line);
|
|
317
|
+
// Parse data rows
|
|
318
|
+
const rows = [];
|
|
319
|
+
let j = startLine + 2;
|
|
320
|
+
for (; j < lineCount; j++) {
|
|
321
|
+
const dataLine = lines[j].trim();
|
|
322
|
+
// Stop at empty line or non-table content (end of table)
|
|
323
|
+
if (dataLine === "" || !isTableLine(dataLine)) {
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
// For piped tables, data rows must also start with `|`
|
|
327
|
+
if (piped && !startsWithPipe(dataLine)) {
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
// Check maxRows limit
|
|
331
|
+
if (opts.maxRows !== undefined && rows.length >= opts.maxRows) {
|
|
332
|
+
// Skip remaining table rows for parseMarkdownAll to correctly advance
|
|
333
|
+
while (j < lineCount) {
|
|
334
|
+
const remaining = lines[j].trim();
|
|
335
|
+
if (remaining === "" || !isTableLine(remaining)) {
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
if (piped && !startsWithPipe(remaining)) {
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
j++;
|
|
342
|
+
}
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
const dataCells = splitRow(dataLine);
|
|
346
|
+
const row = normalizeRow(dataCells, columnCount, opts);
|
|
347
|
+
if (opts.skipEmpty && isEmptyRow(row)) {
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
rows.push(row);
|
|
351
|
+
}
|
|
352
|
+
return { result: { headers, rows, alignments }, endLine: j };
|
|
353
|
+
}
|
|
354
|
+
// =============================================================================
|
|
355
|
+
// Main Parser
|
|
356
|
+
// =============================================================================
|
|
357
|
+
/**
|
|
358
|
+
* Parse a Markdown table string into structured data.
|
|
359
|
+
*
|
|
360
|
+
* The parser looks for the GFM table pattern:
|
|
361
|
+
* 1. A header row (pipe-delimited cells)
|
|
362
|
+
* 2. A separator row (dashes with optional colons for alignment)
|
|
363
|
+
* 3. Zero or more data rows
|
|
364
|
+
*
|
|
365
|
+
* Non-table content before and after the table is ignored.
|
|
366
|
+
*
|
|
367
|
+
* @param input - Markdown string containing a table
|
|
368
|
+
* @param options - Parse options
|
|
369
|
+
* @returns Parsed table data with headers, rows, and alignments
|
|
370
|
+
*
|
|
371
|
+
* @throws {MarkdownParseError} When no valid table is found in the input
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* ```ts
|
|
375
|
+
* // Basic table
|
|
376
|
+
* const result = parseMarkdown("| Name | Age |\n| --- | --- |\n| Alice | 30 |");
|
|
377
|
+
*
|
|
378
|
+
* // With alignment
|
|
379
|
+
* const result = parseMarkdown("| Left | Center | Right |\n|:---|:---:|---:|\n|a|b|c|");
|
|
380
|
+
* // result.alignments = ["left", "center", "right"]
|
|
381
|
+
*
|
|
382
|
+
* // From a larger Markdown document
|
|
383
|
+
* const result = parseMarkdown(markdownDoc); // Finds the first table
|
|
384
|
+
*
|
|
385
|
+
* // With options
|
|
386
|
+
* const result = parseMarkdown(input, { trim: false, maxRows: 100 });
|
|
387
|
+
* ```
|
|
388
|
+
*/
|
|
389
|
+
function parseMarkdown(input, options = {}) {
|
|
390
|
+
const opts = resolveParseOpts(options);
|
|
391
|
+
const lines = input.split(constants_1.LINEBREAK_REGEX);
|
|
392
|
+
const lineCount = lines.length;
|
|
393
|
+
for (let i = 0; i < lineCount - 1; i++) {
|
|
394
|
+
const parsed = parseTableAt(lines, i, lineCount, opts);
|
|
395
|
+
if (parsed) {
|
|
396
|
+
return parsed.result;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
throw new errors_1.MarkdownParseError("No valid Markdown table found in input", lineCount > 0 ? lineCount : 1);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Parse all Markdown tables from a document.
|
|
403
|
+
*
|
|
404
|
+
* @param input - Markdown string containing one or more tables
|
|
405
|
+
* @param options - Parse options (maxRows applies per table)
|
|
406
|
+
* @returns Array of parsed tables
|
|
407
|
+
*
|
|
408
|
+
* @example
|
|
409
|
+
* ```ts
|
|
410
|
+
* const tables = parseMarkdownAll(markdownDoc);
|
|
411
|
+
* console.log(`Found ${tables.length} tables`);
|
|
412
|
+
* tables.forEach((t, i) => console.log(`Table ${i}: ${t.headers.join(", ")}`));
|
|
413
|
+
* ```
|
|
414
|
+
*/
|
|
415
|
+
function parseMarkdownAll(input, options = {}) {
|
|
416
|
+
const opts = resolveParseOpts(options);
|
|
417
|
+
const lines = input.split(constants_1.LINEBREAK_REGEX);
|
|
418
|
+
const lineCount = lines.length;
|
|
419
|
+
const tables = [];
|
|
420
|
+
let i = 0;
|
|
421
|
+
while (i < lineCount - 1) {
|
|
422
|
+
const parsed = parseTableAt(lines, i, lineCount, opts);
|
|
423
|
+
if (parsed) {
|
|
424
|
+
tables.push(parsed.result);
|
|
425
|
+
i = parsed.endLine;
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
i++;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return tables;
|
|
432
|
+
}
|
|
@@ -63,3 +63,5 @@ export { pdf, excelToPdf, PageSizes, PdfError, PdfRenderError, PdfFontError, Pdf
|
|
|
63
63
|
// Errors
|
|
64
64
|
// =============================================================================
|
|
65
65
|
export { ExcelError, isExcelError, ExcelFileError, ExcelDownloadError, ExcelNotSupportedError, ExcelStreamStateError, InvalidAddressError, ColumnOutOfBoundsError, RowOutOfBoundsError, MergeConflictError, InvalidValueTypeError, XmlParseError, WorksheetNameError, PivotTableError, TableError, ImageError, MaxItemsExceededError } from "./modules/excel/errors.js";
|
|
66
|
+
// Markdown errors
|
|
67
|
+
export { MarkdownError, MarkdownParseError } from "./modules/markdown/errors.js";
|
package/dist/esm/index.js
CHANGED
|
@@ -59,3 +59,5 @@ export { pdf, excelToPdf, PageSizes, PdfError, PdfRenderError, PdfFontError, Pdf
|
|
|
59
59
|
// Errors
|
|
60
60
|
// =============================================================================
|
|
61
61
|
export { ExcelError, isExcelError, ExcelFileError, ExcelDownloadError, ExcelNotSupportedError, ExcelStreamStateError, InvalidAddressError, ColumnOutOfBoundsError, RowOutOfBoundsError, MergeConflictError, InvalidValueTypeError, XmlParseError, WorksheetNameError, PivotTableError, TableError, ImageError, MaxItemsExceededError } from "./modules/excel/errors.js";
|
|
62
|
+
// Markdown errors
|
|
63
|
+
export { MarkdownError, MarkdownParseError } from "./modules/markdown/errors.js";
|
|
@@ -110,7 +110,7 @@ async function processWithStrategy(strategy, data, options) {
|
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
112
|
// Fallback to pure JS implementation.
|
|
113
|
-
return strategy.jsFallback(data);
|
|
113
|
+
return strategy.jsFallback(data, options.level);
|
|
114
114
|
}
|
|
115
115
|
// =============================================================================
|
|
116
116
|
// Public API
|
|
@@ -135,7 +135,7 @@ export function compressSync(data, options = {}) {
|
|
|
135
135
|
if (level === 0) {
|
|
136
136
|
return data;
|
|
137
137
|
}
|
|
138
|
-
return deflateRawCompressed(data);
|
|
138
|
+
return deflateRawCompressed(data, level);
|
|
139
139
|
}
|
|
140
140
|
/**
|
|
141
141
|
* Decompress data using browser's native DecompressionStream or JS fallback
|
|
@@ -248,7 +248,7 @@ export async function gzip(data, options = {}) {
|
|
|
248
248
|
*/
|
|
249
249
|
export function gzipSync(data, options = {}) {
|
|
250
250
|
const level = options.level ?? DEFAULT_COMPRESS_LEVEL;
|
|
251
|
-
const deflated = level === 0 ? deflateRawStore(data) : deflateRawCompressed(data);
|
|
251
|
+
const deflated = level === 0 ? deflateRawStore(data) : deflateRawCompressed(data, level);
|
|
252
252
|
return wrapGzip(deflated, data);
|
|
253
253
|
}
|
|
254
254
|
/**
|
|
@@ -324,7 +324,7 @@ export async function zlib(data, options = {}) {
|
|
|
324
324
|
*/
|
|
325
325
|
export function zlibSync(data, options = {}) {
|
|
326
326
|
const level = options.level ?? DEFAULT_COMPRESS_LEVEL;
|
|
327
|
-
const deflated = level === 0 ? deflateRawStore(data) : deflateRawCompressed(data);
|
|
327
|
+
const deflated = level === 0 ? deflateRawStore(data) : deflateRawCompressed(data, level);
|
|
328
328
|
return wrapZlib(deflated, data, level);
|
|
329
329
|
}
|
|
330
330
|
/**
|