@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,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown Module Constants
|
|
3
|
+
*
|
|
4
|
+
* Shared constants used across the Markdown module.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Pre-compiled regex for line splitting (matches CR, LF, or CRLF)
|
|
8
|
+
*/
|
|
9
|
+
export declare const LINEBREAK_REGEX: RegExp;
|
|
10
|
+
/**
|
|
11
|
+
* Characters that need escaping in Markdown table cells.
|
|
12
|
+
* Also matches CRLF/CR/LF so that escaping + newline conversion
|
|
13
|
+
* can be done in a single `replace()` call.
|
|
14
|
+
* Note: `\r\n` must come before `\r` to match CRLF as a single unit.
|
|
15
|
+
*/
|
|
16
|
+
export declare const ESCAPE_AND_NEWLINE: RegExp;
|
|
17
|
+
/**
|
|
18
|
+
* Regex to unescape Markdown table cell content (`\|` → `|`, `\\` → `\`)
|
|
19
|
+
*/
|
|
20
|
+
export declare const UNESCAPE_REGEX: RegExp;
|
|
21
|
+
/**
|
|
22
|
+
* Regex to match `<br>`, `<br/>`, or `<br />` tags (case-insensitive).
|
|
23
|
+
* Used to convert multiline cell representations back to newlines during parsing.
|
|
24
|
+
*/
|
|
25
|
+
export declare const BR_TAG_REGEX: RegExp;
|
|
26
|
+
/**
|
|
27
|
+
* Regex to match literal newlines (CR, LF, or CRLF) in cell content.
|
|
28
|
+
* Used when escaping is disabled but newline conversion is still needed.
|
|
29
|
+
*/
|
|
30
|
+
export declare const NEWLINE_IN_CELL: RegExp;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown Module Constants
|
|
3
|
+
*
|
|
4
|
+
* Shared constants used across the Markdown module.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Pre-compiled regex for line splitting (matches CR, LF, or CRLF)
|
|
8
|
+
*/
|
|
9
|
+
export const LINEBREAK_REGEX = /\r\n|\r|\n/;
|
|
10
|
+
/**
|
|
11
|
+
* Characters that need escaping in Markdown table cells.
|
|
12
|
+
* Also matches CRLF/CR/LF so that escaping + newline conversion
|
|
13
|
+
* can be done in a single `replace()` call.
|
|
14
|
+
* Note: `\r\n` must come before `\r` to match CRLF as a single unit.
|
|
15
|
+
*/
|
|
16
|
+
export const ESCAPE_AND_NEWLINE = /\r\n|[|\\\r\n]/g;
|
|
17
|
+
/**
|
|
18
|
+
* Regex to unescape Markdown table cell content (`\|` → `|`, `\\` → `\`)
|
|
19
|
+
*/
|
|
20
|
+
export const UNESCAPE_REGEX = /\\([|\\])/g;
|
|
21
|
+
/**
|
|
22
|
+
* Regex to match `<br>`, `<br/>`, or `<br />` tags (case-insensitive).
|
|
23
|
+
* Used to convert multiline cell representations back to newlines during parsing.
|
|
24
|
+
*/
|
|
25
|
+
export const BR_TAG_REGEX = /<br\s*\/?>/gi;
|
|
26
|
+
/**
|
|
27
|
+
* Regex to match literal newlines (CR, LF, or CRLF) in cell content.
|
|
28
|
+
* Used when escaping is disabled but newline conversion is still needed.
|
|
29
|
+
*/
|
|
30
|
+
export const NEWLINE_IN_CELL = /\r\n|\r|\n/g;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown module error types.
|
|
3
|
+
*/
|
|
4
|
+
import { BaseError } from "../../utils/errors.js";
|
|
5
|
+
/**
|
|
6
|
+
* Base class for all Markdown-related errors.
|
|
7
|
+
*/
|
|
8
|
+
export declare class MarkdownError extends BaseError {
|
|
9
|
+
name: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Error thrown when Markdown parsing fails.
|
|
13
|
+
*/
|
|
14
|
+
export declare class MarkdownParseError extends MarkdownError {
|
|
15
|
+
name: string;
|
|
16
|
+
/** 1-based line number where the error occurred */
|
|
17
|
+
readonly line: number;
|
|
18
|
+
constructor(message: string, line: number, options?: {
|
|
19
|
+
cause?: unknown;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown module error types.
|
|
3
|
+
*/
|
|
4
|
+
import { BaseError } from "../../utils/errors.js";
|
|
5
|
+
/**
|
|
6
|
+
* Base class for all Markdown-related errors.
|
|
7
|
+
*/
|
|
8
|
+
export class MarkdownError extends BaseError {
|
|
9
|
+
constructor() {
|
|
10
|
+
super(...arguments);
|
|
11
|
+
this.name = "MarkdownError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Error thrown when Markdown parsing fails.
|
|
16
|
+
*/
|
|
17
|
+
export class MarkdownParseError extends MarkdownError {
|
|
18
|
+
constructor(message, line, options) {
|
|
19
|
+
super(`Line ${line}: ${message}`, options);
|
|
20
|
+
this.name = "MarkdownParseError";
|
|
21
|
+
this.line = line;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown Table Formatter
|
|
3
|
+
*
|
|
4
|
+
* Formats data into well-formed Markdown table strings.
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Auto column width calculation with padding
|
|
8
|
+
* - Column alignment (left, center, right, none)
|
|
9
|
+
* - Proper escaping of pipe characters and backslashes
|
|
10
|
+
* - Compact mode (disable column-width alignment) for minimal output
|
|
11
|
+
* - Configurable column definitions
|
|
12
|
+
* - Multiline cell content (newlines converted to `<br>`)
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* // Simple array data with headers
|
|
17
|
+
* formatMarkdown(["Name", "Age"], [["Alice", "30"], ["Bob", "25"]]);
|
|
18
|
+
* // | Name | Age |
|
|
19
|
+
* // | ----- | --- |
|
|
20
|
+
* // | Alice | 30 |
|
|
21
|
+
* // | Bob | 25 |
|
|
22
|
+
*
|
|
23
|
+
* // With alignment
|
|
24
|
+
* formatMarkdown(["Left", "Center", "Right"], data, {
|
|
25
|
+
* alignment: "left",
|
|
26
|
+
* columns: [
|
|
27
|
+
* { header: "Left", alignment: "left" },
|
|
28
|
+
* { header: "Center", alignment: "center" },
|
|
29
|
+
* { header: "Right", alignment: "right" }
|
|
30
|
+
* ]
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
import type { MarkdownFormatOptions } from "../types.js";
|
|
35
|
+
/**
|
|
36
|
+
* Format data as a Markdown table string.
|
|
37
|
+
*
|
|
38
|
+
* @param headers - Column header strings
|
|
39
|
+
* @param rows - Data rows (each row is an array of cell values)
|
|
40
|
+
* @param options - Formatting options
|
|
41
|
+
* @returns Formatted Markdown table string
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* formatMarkdown(
|
|
46
|
+
* ["Name", "Age", "City"],
|
|
47
|
+
* [
|
|
48
|
+
* ["Alice", 30, "New York"],
|
|
49
|
+
* ["Bob", 25, "London"]
|
|
50
|
+
* ]
|
|
51
|
+
* );
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export declare function formatMarkdown(headers: string[], rows: unknown[][], options?: MarkdownFormatOptions): string;
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown Table Formatter
|
|
3
|
+
*
|
|
4
|
+
* Formats data into well-formed Markdown table strings.
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Auto column width calculation with padding
|
|
8
|
+
* - Column alignment (left, center, right, none)
|
|
9
|
+
* - Proper escaping of pipe characters and backslashes
|
|
10
|
+
* - Compact mode (disable column-width alignment) for minimal output
|
|
11
|
+
* - Configurable column definitions
|
|
12
|
+
* - Multiline cell content (newlines converted to `<br>`)
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* // Simple array data with headers
|
|
17
|
+
* formatMarkdown(["Name", "Age"], [["Alice", "30"], ["Bob", "25"]]);
|
|
18
|
+
* // | Name | Age |
|
|
19
|
+
* // | ----- | --- |
|
|
20
|
+
* // | Alice | 30 |
|
|
21
|
+
* // | Bob | 25 |
|
|
22
|
+
*
|
|
23
|
+
* // With alignment
|
|
24
|
+
* formatMarkdown(["Left", "Center", "Right"], data, {
|
|
25
|
+
* alignment: "left",
|
|
26
|
+
* columns: [
|
|
27
|
+
* { header: "Left", alignment: "left" },
|
|
28
|
+
* { header: "Center", alignment: "center" },
|
|
29
|
+
* { header: "Right", alignment: "right" }
|
|
30
|
+
* ]
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
import { ESCAPE_AND_NEWLINE, NEWLINE_IN_CELL } from "../constants.js";
|
|
35
|
+
// =============================================================================
|
|
36
|
+
// Unicode Display Width
|
|
37
|
+
// =============================================================================
|
|
38
|
+
/**
|
|
39
|
+
* Calculate the display width of a string in a monospace terminal.
|
|
40
|
+
* CJK characters, fullwidth forms, and most emoji are 2 columns wide.
|
|
41
|
+
* This enables proper column alignment in tables containing these characters.
|
|
42
|
+
*/
|
|
43
|
+
function displayWidth(str) {
|
|
44
|
+
let width = 0;
|
|
45
|
+
for (let i = 0; i < str.length; i++) {
|
|
46
|
+
const code = str.charCodeAt(i);
|
|
47
|
+
// Handle surrogate pairs (emoji and supplementary plane characters)
|
|
48
|
+
if (code >= 0xd800 && code <= 0xdbff && i + 1 < str.length) {
|
|
49
|
+
const low = str.charCodeAt(i + 1);
|
|
50
|
+
if (low >= 0xdc00 && low <= 0xdfff) {
|
|
51
|
+
width += 2;
|
|
52
|
+
i++;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Zero-width characters
|
|
57
|
+
if (code === 0x200b || // zero-width space
|
|
58
|
+
code === 0x200c || // zero-width non-joiner
|
|
59
|
+
code === 0x200d || // zero-width joiner
|
|
60
|
+
code === 0xfeff // BOM / zero-width no-break space
|
|
61
|
+
) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
// Combining marks (general categories Mn, Mc, Me)
|
|
65
|
+
if ((code >= 0x0300 && code <= 0x036f) || // Combining Diacritical Marks
|
|
66
|
+
(code >= 0x1ab0 && code <= 0x1aff) || // Combining Diacritical Marks Extended
|
|
67
|
+
(code >= 0x1dc0 && code <= 0x1dff) || // Combining Diacritical Marks Supplement
|
|
68
|
+
(code >= 0x20d0 && code <= 0x20ff) || // Combining Diacritical Marks for Symbols
|
|
69
|
+
(code >= 0xfe20 && code <= 0xfe2f) // Combining Half Marks
|
|
70
|
+
) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
// Fullwidth and wide characters: CJK, Hangul, Katakana/Hiragana, etc.
|
|
74
|
+
if ((code >= 0x1100 && code <= 0x115f) || // Hangul Jamo
|
|
75
|
+
(code >= 0x2e80 && code <= 0x303e) || // CJK Radicals, Kangxi, CJK Symbols
|
|
76
|
+
(code >= 0x3040 && code <= 0x33bf) || // Hiragana, Katakana, Bopomofo, CJK Compat
|
|
77
|
+
(code >= 0x3400 && code <= 0x4dbf) || // CJK Unified Ideographs Extension A
|
|
78
|
+
(code >= 0x4e00 && code <= 0xa4cf) || // CJK Unified Ideographs, Yi
|
|
79
|
+
(code >= 0xa960 && code <= 0xa97f) || // Hangul Jamo Extended-A
|
|
80
|
+
(code >= 0xac00 && code <= 0xd7af) || // Hangul Syllables
|
|
81
|
+
(code >= 0xf900 && code <= 0xfaff) || // CJK Compatibility Ideographs
|
|
82
|
+
(code >= 0xfe10 && code <= 0xfe19) || // Vertical forms
|
|
83
|
+
(code >= 0xfe30 && code <= 0xfe6f) || // CJK Compatibility Forms
|
|
84
|
+
(code >= 0xff01 && code <= 0xff60) || // Fullwidth ASCII/Latin
|
|
85
|
+
(code >= 0xffe0 && code <= 0xffe6) // Fullwidth Signs
|
|
86
|
+
) {
|
|
87
|
+
width += 2;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
width += 1;
|
|
91
|
+
}
|
|
92
|
+
return width;
|
|
93
|
+
}
|
|
94
|
+
// =============================================================================
|
|
95
|
+
// Internal Helpers
|
|
96
|
+
// =============================================================================
|
|
97
|
+
/**
|
|
98
|
+
* Default value-to-string converter.
|
|
99
|
+
*/
|
|
100
|
+
function defaultStringify(value) {
|
|
101
|
+
if (value === null || value === undefined) {
|
|
102
|
+
return "";
|
|
103
|
+
}
|
|
104
|
+
if (value instanceof Date) {
|
|
105
|
+
return value.toISOString();
|
|
106
|
+
}
|
|
107
|
+
if (typeof value === "object") {
|
|
108
|
+
try {
|
|
109
|
+
return JSON.stringify(value);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return "[object Object]";
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return String(value);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Escape pipe characters, backslashes, and convert newlines to `<br>` in a single pass.
|
|
119
|
+
* `|` → `\|`, `\` → `\\`, `\r\n`/`\r`/`\n` → `<br>`
|
|
120
|
+
*/
|
|
121
|
+
function escapeCell(value) {
|
|
122
|
+
return value.replace(ESCAPE_AND_NEWLINE, ch => (ch === "|" || ch === "\\" ? "\\" + ch : "<br>"));
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Convert literal newlines to `<br>` without escaping pipes/backslashes.
|
|
126
|
+
*/
|
|
127
|
+
function convertNewlines(value) {
|
|
128
|
+
if (value.indexOf("\n") !== -1 || value.indexOf("\r") !== -1) {
|
|
129
|
+
return value.replace(NEWLINE_IN_CELL, "<br>");
|
|
130
|
+
}
|
|
131
|
+
return value;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Build the separator cell for a column based on alignment and width.
|
|
135
|
+
*
|
|
136
|
+
* Examples (width=5):
|
|
137
|
+
* - none: `-----`
|
|
138
|
+
* - left: `:----`
|
|
139
|
+
* - right: `----:`
|
|
140
|
+
* - center: `:---:`
|
|
141
|
+
*/
|
|
142
|
+
function buildSeparator(alignment, width) {
|
|
143
|
+
switch (alignment) {
|
|
144
|
+
case "left":
|
|
145
|
+
return ":" + "-".repeat(width - 1);
|
|
146
|
+
case "right":
|
|
147
|
+
return "-".repeat(width - 1) + ":";
|
|
148
|
+
case "center":
|
|
149
|
+
return ":" + "-".repeat(Math.max(width - 2, 1)) + ":";
|
|
150
|
+
default: // "none"
|
|
151
|
+
return "-".repeat(width);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Pad a cell value to the target display width with alignment.
|
|
156
|
+
* Uses displayWidth() for proper CJK/emoji handling.
|
|
157
|
+
*/
|
|
158
|
+
function padCell(value, targetWidth, alignment) {
|
|
159
|
+
const len = displayWidth(value);
|
|
160
|
+
if (len >= targetWidth) {
|
|
161
|
+
return value;
|
|
162
|
+
}
|
|
163
|
+
const diff = targetWidth - len;
|
|
164
|
+
switch (alignment) {
|
|
165
|
+
case "right":
|
|
166
|
+
return " ".repeat(diff) + value;
|
|
167
|
+
case "center": {
|
|
168
|
+
const left = Math.floor(diff / 2);
|
|
169
|
+
const right = diff - left;
|
|
170
|
+
return " ".repeat(left) + value + " ".repeat(right);
|
|
171
|
+
}
|
|
172
|
+
default: // "left" or "none"
|
|
173
|
+
return value + " ".repeat(diff);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Resolve column configuration from options.
|
|
178
|
+
*/
|
|
179
|
+
function resolveColumns(headers, options) {
|
|
180
|
+
const columnCount = headers.length;
|
|
181
|
+
const defaultAlignment = options.alignment ?? "left";
|
|
182
|
+
const displayHeaders = new Array(columnCount);
|
|
183
|
+
const alignments = new Array(columnCount);
|
|
184
|
+
const minWidths = new Array(columnCount);
|
|
185
|
+
if (options.columns && options.columns.length > 0) {
|
|
186
|
+
for (let i = 0; i < columnCount; i++) {
|
|
187
|
+
const col = i < options.columns.length ? options.columns[i] : undefined;
|
|
188
|
+
if (typeof col === "string") {
|
|
189
|
+
displayHeaders[i] = col;
|
|
190
|
+
alignments[i] = defaultAlignment;
|
|
191
|
+
minWidths[i] = 3;
|
|
192
|
+
}
|
|
193
|
+
else if (col) {
|
|
194
|
+
displayHeaders[i] = col.header;
|
|
195
|
+
alignments[i] = col.alignment ?? defaultAlignment;
|
|
196
|
+
minWidths[i] = col.minWidth ?? 3;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
displayHeaders[i] = headers[i] ?? "";
|
|
200
|
+
alignments[i] = defaultAlignment;
|
|
201
|
+
minWidths[i] = 3;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
for (let i = 0; i < columnCount; i++) {
|
|
207
|
+
displayHeaders[i] = headers[i] ?? "";
|
|
208
|
+
alignments[i] = defaultAlignment;
|
|
209
|
+
minWidths[i] = 3;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return { displayHeaders, alignments, minWidths };
|
|
213
|
+
}
|
|
214
|
+
// =============================================================================
|
|
215
|
+
// Main Formatter
|
|
216
|
+
// =============================================================================
|
|
217
|
+
/**
|
|
218
|
+
* Format data as a Markdown table string.
|
|
219
|
+
*
|
|
220
|
+
* @param headers - Column header strings
|
|
221
|
+
* @param rows - Data rows (each row is an array of cell values)
|
|
222
|
+
* @param options - Formatting options
|
|
223
|
+
* @returns Formatted Markdown table string
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```ts
|
|
227
|
+
* formatMarkdown(
|
|
228
|
+
* ["Name", "Age", "City"],
|
|
229
|
+
* [
|
|
230
|
+
* ["Alice", 30, "New York"],
|
|
231
|
+
* ["Bob", 25, "London"]
|
|
232
|
+
* ]
|
|
233
|
+
* );
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
export function formatMarkdown(headers, rows, options = {}) {
|
|
237
|
+
const { padding = true, trailingNewline = true, escapeContent = true, stringify = defaultStringify } = options;
|
|
238
|
+
const columnCount = headers.length;
|
|
239
|
+
if (columnCount === 0) {
|
|
240
|
+
return "";
|
|
241
|
+
}
|
|
242
|
+
// Resolve column configs
|
|
243
|
+
const { displayHeaders, alignments, minWidths } = resolveColumns(headers, options);
|
|
244
|
+
// Single-pass: convert all cell values to strings, apply escaping,
|
|
245
|
+
// and compute column widths simultaneously.
|
|
246
|
+
const headerStrings = new Array(columnCount);
|
|
247
|
+
const widths = new Array(columnCount);
|
|
248
|
+
// Initialize widths from headers
|
|
249
|
+
for (let i = 0; i < columnCount; i++) {
|
|
250
|
+
const h = escapeContent ? escapeCell(displayHeaders[i]) : convertNewlines(displayHeaders[i]);
|
|
251
|
+
headerStrings[i] = h;
|
|
252
|
+
widths[i] = padding ? Math.max(displayWidth(h), minWidths[i]) : Math.max(minWidths[i], 3);
|
|
253
|
+
}
|
|
254
|
+
// Convert rows and update widths in a single pass
|
|
255
|
+
const rowStrings = new Array(rows.length);
|
|
256
|
+
for (let r = 0; r < rows.length; r++) {
|
|
257
|
+
const row = rows[r];
|
|
258
|
+
const cells = new Array(columnCount);
|
|
259
|
+
for (let c = 0; c < columnCount; c++) {
|
|
260
|
+
const raw = c < row.length ? stringify(row[c]) : "";
|
|
261
|
+
const cell = escapeContent ? escapeCell(raw) : convertNewlines(raw);
|
|
262
|
+
cells[c] = cell;
|
|
263
|
+
if (padding) {
|
|
264
|
+
const cellWidth = displayWidth(cell);
|
|
265
|
+
if (cellWidth > widths[c]) {
|
|
266
|
+
widths[c] = cellWidth;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
rowStrings[r] = cells;
|
|
271
|
+
}
|
|
272
|
+
// Build the complete table output
|
|
273
|
+
// Pre-calculate total line count: header + separator + data rows
|
|
274
|
+
const totalLines = 2 + rowStrings.length;
|
|
275
|
+
const lines = new Array(totalLines);
|
|
276
|
+
// Header row
|
|
277
|
+
const headerParts = new Array(columnCount);
|
|
278
|
+
for (let c = 0; c < columnCount; c++) {
|
|
279
|
+
headerParts[c] = padding
|
|
280
|
+
? " " + padCell(headerStrings[c], widths[c], alignments[c]) + " "
|
|
281
|
+
: " " + headerStrings[c] + " ";
|
|
282
|
+
}
|
|
283
|
+
lines[0] = "|" + headerParts.join("|") + "|";
|
|
284
|
+
// Separator row
|
|
285
|
+
// In both modes, cell content has 1 space padding on each side (" value "),
|
|
286
|
+
// so separator width must be widths[c] + 2 to match.
|
|
287
|
+
const sepParts = new Array(columnCount);
|
|
288
|
+
for (let c = 0; c < columnCount; c++) {
|
|
289
|
+
sepParts[c] = buildSeparator(alignments[c], widths[c] + 2);
|
|
290
|
+
}
|
|
291
|
+
lines[1] = "|" + sepParts.join("|") + "|";
|
|
292
|
+
// Data rows
|
|
293
|
+
for (let r = 0; r < rowStrings.length; r++) {
|
|
294
|
+
const rowParts = new Array(columnCount);
|
|
295
|
+
for (let c = 0; c < columnCount; c++) {
|
|
296
|
+
rowParts[c] = padding
|
|
297
|
+
? " " + padCell(rowStrings[r][c], widths[c], alignments[c]) + " "
|
|
298
|
+
: " " + rowStrings[r][c] + " ";
|
|
299
|
+
}
|
|
300
|
+
lines[r + 2] = "|" + rowParts.join("|") + "|";
|
|
301
|
+
}
|
|
302
|
+
let result = lines.join("\n");
|
|
303
|
+
if (trailingNewline) {
|
|
304
|
+
result += "\n";
|
|
305
|
+
}
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown Module - Public API
|
|
3
|
+
*
|
|
4
|
+
* Pure Markdown table parsing/formatting functionality with no Excel dependencies.
|
|
5
|
+
* For Markdown-Worksheet integration, use Workbook.readMarkdown/writeMarkdown methods instead.
|
|
6
|
+
*
|
|
7
|
+
* Design principles:
|
|
8
|
+
* - Only export types and functions that are part of the PUBLIC API
|
|
9
|
+
* - Internal utilities are used internally but not exported
|
|
10
|
+
* - This reduces bundle size and simplifies the public interface
|
|
11
|
+
*/
|
|
12
|
+
export type { MarkdownAlignment, MarkdownParseResult, MarkdownParseOptions, MarkdownColumnConfig, MarkdownFormatOptions, MarkdownOptions } from "./types.js";
|
|
13
|
+
export { parseMarkdown, parseMarkdownAll } from "./parse/index.js";
|
|
14
|
+
export { formatMarkdown } from "./format/index.js";
|
|
15
|
+
export { MarkdownError, MarkdownParseError } from "./errors.js";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown Module - Public API
|
|
3
|
+
*
|
|
4
|
+
* Pure Markdown table parsing/formatting functionality with no Excel dependencies.
|
|
5
|
+
* For Markdown-Worksheet integration, use Workbook.readMarkdown/writeMarkdown methods instead.
|
|
6
|
+
*
|
|
7
|
+
* Design principles:
|
|
8
|
+
* - Only export types and functions that are part of the PUBLIC API
|
|
9
|
+
* - Internal utilities are used internally but not exported
|
|
10
|
+
* - This reduces bundle size and simplifies the public interface
|
|
11
|
+
*/
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// Core Functions
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// Parser
|
|
16
|
+
export { parseMarkdown, parseMarkdownAll } from "./parse/index.js";
|
|
17
|
+
// Formatter
|
|
18
|
+
export { formatMarkdown } from "./format/index.js";
|
|
19
|
+
// =============================================================================
|
|
20
|
+
// Errors
|
|
21
|
+
// =============================================================================
|
|
22
|
+
export { MarkdownError, MarkdownParseError } from "./errors.js";
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown Table Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses Markdown tables into structured data.
|
|
5
|
+
*
|
|
6
|
+
* Supports:
|
|
7
|
+
* - Standard GFM (GitHub Flavored Markdown) table syntax
|
|
8
|
+
* - Column alignment detection via separator row
|
|
9
|
+
* - Escaped pipes (`\|`) in cell content
|
|
10
|
+
* - Tables with or without leading/trailing pipes
|
|
11
|
+
* - Tolerant parsing (mismatched column counts, extra whitespace)
|
|
12
|
+
* - Multiline cell content via `<br>` / `<br/>` / `<br />` tags
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* const result = parseMarkdown("| Name | Age |\n| --- | --- |\n| Alice | 30 |");
|
|
17
|
+
* // result.headers = ["Name", "Age"]
|
|
18
|
+
* // result.rows = [["Alice", "30"]]
|
|
19
|
+
* // result.alignments = ["none", "none"]
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
import type { MarkdownParseOptions, MarkdownParseResult } from "../types.js";
|
|
23
|
+
/**
|
|
24
|
+
* Parse a Markdown table string into structured data.
|
|
25
|
+
*
|
|
26
|
+
* The parser looks for the GFM table pattern:
|
|
27
|
+
* 1. A header row (pipe-delimited cells)
|
|
28
|
+
* 2. A separator row (dashes with optional colons for alignment)
|
|
29
|
+
* 3. Zero or more data rows
|
|
30
|
+
*
|
|
31
|
+
* Non-table content before and after the table is ignored.
|
|
32
|
+
*
|
|
33
|
+
* @param input - Markdown string containing a table
|
|
34
|
+
* @param options - Parse options
|
|
35
|
+
* @returns Parsed table data with headers, rows, and alignments
|
|
36
|
+
*
|
|
37
|
+
* @throws {MarkdownParseError} When no valid table is found in the input
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* // Basic table
|
|
42
|
+
* const result = parseMarkdown("| Name | Age |\n| --- | --- |\n| Alice | 30 |");
|
|
43
|
+
*
|
|
44
|
+
* // With alignment
|
|
45
|
+
* const result = parseMarkdown("| Left | Center | Right |\n|:---|:---:|---:|\n|a|b|c|");
|
|
46
|
+
* // result.alignments = ["left", "center", "right"]
|
|
47
|
+
*
|
|
48
|
+
* // From a larger Markdown document
|
|
49
|
+
* const result = parseMarkdown(markdownDoc); // Finds the first table
|
|
50
|
+
*
|
|
51
|
+
* // With options
|
|
52
|
+
* const result = parseMarkdown(input, { trim: false, maxRows: 100 });
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function parseMarkdown(input: string, options?: MarkdownParseOptions): MarkdownParseResult;
|
|
56
|
+
/**
|
|
57
|
+
* Parse all Markdown tables from a document.
|
|
58
|
+
*
|
|
59
|
+
* @param input - Markdown string containing one or more tables
|
|
60
|
+
* @param options - Parse options (maxRows applies per table)
|
|
61
|
+
* @returns Array of parsed tables
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* const tables = parseMarkdownAll(markdownDoc);
|
|
66
|
+
* console.log(`Found ${tables.length} tables`);
|
|
67
|
+
* tables.forEach((t, i) => console.log(`Table ${i}: ${t.headers.join(", ")}`));
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function parseMarkdownAll(input: string, options?: MarkdownParseOptions): MarkdownParseResult[];
|