markdown-it-adv-table 0.1.2 → 0.2.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 +174 -12
- package/lib/fence.js +12 -4
- package/lib/flat-table.js +3 -2
- package/lib/index.d.ts +5 -13
- package/lib/index.js +33 -49
- package/lib/table-builder.d.ts +1 -0
- package/lib/table-builder.js +14 -3
- package/lib/table.d.ts +10 -3
- package/lib/table.js +55 -15
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
|
|
2
2
|
# markdown-it-adv-table
|
|
3
3
|
|
|
4
|
-
A [markdown-it](https://www.npmjs.com/package/markdown-it) plugin
|
|
4
|
+
A [markdown-it](https://www.npmjs.com/package/markdown-it) plugin for advanced table rendering.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
- Custom column widths
|
|
8
|
-
- Horizontal cell alignment
|
|
9
|
-
- Table styling with css classes
|
|
10
|
-
- Header rows and columns (using `<th>`)
|
|
11
|
-
- Multiple blocks and nested markdown within cells
|
|
6
|
+
This plugin adds custom table syntaxes to render complex tables easier.
|
|
12
7
|
|
|
13
|
-
|
|
8
|
+
- "flat-table" syntax
|
|
9
|
+
- "csv-table" syntax
|
|
10
|
+
- "tsv-table" syntax
|
|
14
11
|
|
|
15
|
-
|
|
12
|
+
The "flat-table" syntax allows to:
|
|
13
|
+
|
|
14
|
+
- Set Rowspan and colspan for spanning cells
|
|
15
|
+
- Set column width
|
|
16
|
+
- Set horizontal text alignment
|
|
17
|
+
- Set css classes for table styling
|
|
18
|
+
- Define Header rows and columns
|
|
19
|
+
- Allow writing markdown inside the cells (nested document)
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```sh
|
|
16
24
|
npm install markdown-it-adv-table
|
|
17
25
|
```
|
|
18
26
|
|
|
@@ -25,11 +33,37 @@ md.use(advTable);
|
|
|
25
33
|
const html = md.render("text...");
|
|
26
34
|
```
|
|
27
35
|
|
|
28
|
-
|
|
36
|
+
<table>
|
|
37
|
+
<tr>
|
|
38
|
+
<th>Plugin</th>
|
|
39
|
+
<th>LangName</th>
|
|
40
|
+
<th>Behavior</th>
|
|
41
|
+
</tr>
|
|
42
|
+
<tr>
|
|
43
|
+
<td><code>advTable</code></td>
|
|
44
|
+
<td>table*</td>
|
|
45
|
+
<td>Installs an all-unified plugin</td>
|
|
46
|
+
</tr>
|
|
47
|
+
<tr>
|
|
48
|
+
<td><code>flatTable</code></td>
|
|
49
|
+
<td>flat-table</td>
|
|
50
|
+
<td>parse flat-table syntax</td>
|
|
51
|
+
</tr>
|
|
52
|
+
<tr>
|
|
53
|
+
<td><code>csvTable</code></td>
|
|
54
|
+
<td>csv-table</td>
|
|
55
|
+
<td>render csv as table</td>
|
|
56
|
+
</tr>
|
|
57
|
+
<tr>
|
|
58
|
+
<td><code>tsvTable</code></td>
|
|
59
|
+
<td>tsv-table</td>
|
|
60
|
+
<td>render tsv as table</td>
|
|
61
|
+
</tr>
|
|
62
|
+
</table>
|
|
29
63
|
|
|
30
|
-
|
|
64
|
+
## Usage
|
|
31
65
|
|
|
32
|
-
|
|
66
|
+
Use fenced code block for the table data.
|
|
33
67
|
|
|
34
68
|
``````
|
|
35
69
|
```table cols=4 header-rows=2 header-cols=1
|
|
@@ -54,6 +88,7 @@ c3| Q1 Sales
|
|
|
54
88
|
| $3,500
|
|
55
89
|
| $4,000
|
|
56
90
|
| $4,200
|
|
91
|
+
```
|
|
57
92
|
``````
|
|
58
93
|
|
|
59
94
|
<table>
|
|
@@ -90,7 +125,134 @@ c3| Q1 Sales
|
|
|
90
125
|
</tbody>
|
|
91
126
|
</table>
|
|
92
127
|
|
|
128
|
+
## Documentation
|
|
129
|
+
|
|
130
|
+
The table is expressed in a fenced code block.
|
|
131
|
+
|
|
132
|
+
- A line that starts with `|` starts a new cell.
|
|
133
|
+
- The cell content is parsed as Markdown.
|
|
134
|
+
- The cell content spans until the next cell marker.
|
|
135
|
+
|
|
136
|
+
A cell marker can include directives that control the cell’s properties.
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
### TableSpec (Table Definition)
|
|
140
|
+
|
|
141
|
+
The [info-string](https://spec.commonmark.org/0.31.2/#info-string) of the fenced code block is parsed as TableSpec.
|
|
142
|
+
|
|
143
|
+
<table>
|
|
144
|
+
<tr>
|
|
145
|
+
<th>Key</th>
|
|
146
|
+
<th>Type</th>
|
|
147
|
+
<th>Value</th>
|
|
148
|
+
</tr>
|
|
149
|
+
<tr>
|
|
150
|
+
<td>cols</td>
|
|
151
|
+
<td>number | string</td>
|
|
152
|
+
<td>
|
|
153
|
+
<p>Define number of columns.</p>
|
|
154
|
+
<p>If the value is a string literal, it is a <a href="#colspec"><code>ColSpec</code></a>.</p>
|
|
155
|
+
<pre>cols=3 // 3 columns
|
|
156
|
+
cols="1,1,2" // 3 columns, 1:1:2 ratio</pre>
|
|
157
|
+
</td>
|
|
158
|
+
</tr>
|
|
159
|
+
<tr>
|
|
160
|
+
<td>header-cols</td>
|
|
161
|
+
<td>number</td>
|
|
162
|
+
<td>Number of header columns (rendered as <th>)</td>
|
|
163
|
+
</tr>
|
|
164
|
+
<tr>
|
|
165
|
+
<td>header-rows</td>
|
|
166
|
+
<td>number</td>
|
|
167
|
+
<td>Number of header rows (rendered as <thead> with <th>)</td>
|
|
168
|
+
</tr>
|
|
169
|
+
<tr>
|
|
170
|
+
<td>class</td>
|
|
171
|
+
<td>string</td>
|
|
172
|
+
<td>Table class names (space- or comma-separated)</td>
|
|
173
|
+
</tr>
|
|
174
|
+
<tr>
|
|
175
|
+
<td>width</td>
|
|
176
|
+
<td>number | string</td>
|
|
177
|
+
<td>Table width.</td>
|
|
178
|
+
</tr>
|
|
179
|
+
<tr>
|
|
180
|
+
<td>format</td>
|
|
181
|
+
<td>string</td>
|
|
182
|
+
<td>
|
|
183
|
+
<p>Use alternative table syntax. </p>
|
|
184
|
+
<ul>
|
|
185
|
+
<li><code>csv</code> : parse text as csv</li>
|
|
186
|
+
<li><code>tsv</code> : parse text as tsv</li>
|
|
187
|
+
</ul>
|
|
188
|
+
</td>
|
|
189
|
+
</tr>
|
|
190
|
+
</table>
|
|
191
|
+
|
|
192
|
+
<h3 id="colspec">ColSpec (Column Definition)</h3>
|
|
193
|
+
|
|
194
|
+
<code>ColSpec</code> is a comma-separated set-of-directives to control the column's properties.
|
|
195
|
+
|
|
196
|
+
"1,1,1" 3 columns, 1:1:1 ratio
|
|
197
|
+
"30%,15,30,60" 4 columns, 3:1:2:4 ratio
|
|
198
|
+
"<100px,,>25%" 3 columns, 100px-auto-25% with alignment directives
|
|
199
|
+
|
|
200
|
+
<table>
|
|
201
|
+
<tr>
|
|
202
|
+
<th>Directive</th>
|
|
203
|
+
<th>Description</th>
|
|
204
|
+
</tr>
|
|
205
|
+
<tr>
|
|
206
|
+
<td>size[unit]</td>
|
|
207
|
+
<td>
|
|
208
|
+
<p>Set column width. Any css units can be used.</p>
|
|
209
|
+
<p>If the unit is omitted, the value represents the weight of the column. The plugin calculates the column width by dividing up the remaining space, based on its weight.</p>
|
|
210
|
+
<pre>"1,1,2" = "25%,25%,50%" (Eq = calc(100% * x / 4))
|
|
211
|
+
"20%,1,1,2" = "20%,20%,20%,40%" (Eq = calc( 80% * x / 4))</pre>
|
|
212
|
+
<p>If the size is empty or invalid, the width is unset. The weight of the unsized(auto) column defaults to 1.</p>
|
|
213
|
+
<p><small>NOTE: The actual width is calculated by the HTML engine, respecting the column's minimum content width.</small></p>
|
|
214
|
+
</td>
|
|
215
|
+
</tr>
|
|
216
|
+
<tr>
|
|
217
|
+
<td><<br>^<br>></td>
|
|
218
|
+
<td>
|
|
219
|
+
Left-aligned<br>
|
|
220
|
+
Center-aligned<br>
|
|
221
|
+
Right-aligned<br>
|
|
222
|
+
</td>
|
|
223
|
+
</tr>
|
|
224
|
+
</table>
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
### Cell Directives (Cell Definition)
|
|
229
|
+
|
|
230
|
+
<table>
|
|
231
|
+
<tr>
|
|
232
|
+
<th>Syntax</th>
|
|
233
|
+
<th>Description</th>
|
|
234
|
+
</tr>
|
|
235
|
+
<tr>
|
|
236
|
+
<td>c2, c{\d+}</td>
|
|
237
|
+
<td>Set colspan</td>
|
|
238
|
+
</tr>
|
|
239
|
+
<tr>
|
|
240
|
+
<td>r2, r{\d+}</td>
|
|
241
|
+
<td>Set rowspan</td>
|
|
242
|
+
</tr>
|
|
243
|
+
<tr>
|
|
244
|
+
<td><<br>^<br>></td>
|
|
245
|
+
<td>Left align<br>Center align<br>Right align</td>
|
|
246
|
+
</tr>
|
|
247
|
+
<tr>
|
|
248
|
+
<td>h</td>
|
|
249
|
+
<td>Use <th> instead of <td></td>
|
|
250
|
+
</tr>
|
|
251
|
+
</table>
|
|
252
|
+
|
|
253
|
+
|
|
93
254
|
|
|
255
|
+
## More Examples
|
|
94
256
|
|
|
95
257
|
|
|
96
258
|
``````
|
package/lib/fence.js
CHANGED
|
@@ -65,15 +65,23 @@ export function fence_custom(names, parser) {
|
|
|
65
65
|
}
|
|
66
66
|
len = state.sCount[startLine];
|
|
67
67
|
state.line = nextLine + (haveEndMarker ? 1 : 0);
|
|
68
|
-
|
|
69
|
-
parser(params, state, startLine, nextLine);
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
68
|
+
const parseDefault = () => {
|
|
72
69
|
const token = state.push("fence", "code", 0);
|
|
73
70
|
token.info = params;
|
|
74
71
|
token.content = state.getLines(startLine + 1, nextLine, len, true);
|
|
75
72
|
token.markup = markup;
|
|
76
73
|
token.map = [startLine, state.line];
|
|
74
|
+
};
|
|
75
|
+
if (parser !== undefined) {
|
|
76
|
+
try {
|
|
77
|
+
parser(params, state, startLine, nextLine);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
parseDefault();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
parseDefault();
|
|
77
85
|
}
|
|
78
86
|
return true;
|
|
79
87
|
};
|
package/lib/flat-table.js
CHANGED
|
@@ -14,7 +14,8 @@ export class FlatTableParser {
|
|
|
14
14
|
return new FlatTableParser(tableSpec);
|
|
15
15
|
}
|
|
16
16
|
parse(state, startLine, endLine) {
|
|
17
|
-
const
|
|
17
|
+
const md = state.md;
|
|
18
|
+
const builder = TableBuilder.newLocal(state, this._tableSpec);
|
|
18
19
|
builder.startTable();
|
|
19
20
|
let currentLine = startLine;
|
|
20
21
|
while (currentLine < endLine) {
|
|
@@ -29,7 +30,6 @@ export class FlatTableParser {
|
|
|
29
30
|
currentLine++;
|
|
30
31
|
}
|
|
31
32
|
const cellEnd = currentLine;
|
|
32
|
-
const md = state.md;
|
|
33
33
|
const cellIndent = FlatTableParser.getCellIndent(state, line);
|
|
34
34
|
const cellSpec = FlatTableParser.cellspec(line);
|
|
35
35
|
const cellAttr = FlatTableParser.parseCellspec(cellSpec);
|
|
@@ -54,6 +54,7 @@ export class FlatTableParser {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
builder.endTable();
|
|
57
|
+
state.tokens.push(...builder.state.tokens);
|
|
57
58
|
}
|
|
58
59
|
getline(state, lineNumber) {
|
|
59
60
|
return state.getLines(lineNumber, lineNumber + 1, state.blkIndent, false);
|
package/lib/index.d.ts
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
import { PluginWithOptions } from "markdown-it";
|
|
1
|
+
import { PluginSimple, PluginWithOptions } from "markdown-it";
|
|
2
2
|
import { Parser } from "./fence.js";
|
|
3
3
|
export interface PluginOption {
|
|
4
|
-
names: {
|
|
5
|
-
adv: string;
|
|
6
|
-
flat: string;
|
|
7
|
-
csv: string;
|
|
8
|
-
tsv: string;
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
export interface PluginOptionSingle {
|
|
12
4
|
name: string;
|
|
13
5
|
}
|
|
14
|
-
export declare function
|
|
6
|
+
export declare function unifiedParser(option: PluginOption): Parser;
|
|
15
7
|
export declare const advTable: PluginWithOptions<PluginOption>;
|
|
16
|
-
export declare const flatTable:
|
|
17
|
-
export declare const csvTable:
|
|
18
|
-
export declare const tsvTable:
|
|
8
|
+
export declare const flatTable: PluginSimple;
|
|
9
|
+
export declare const csvTable: PluginSimple;
|
|
10
|
+
export declare const tsvTable: PluginSimple;
|
|
19
11
|
export default advTable;
|
package/lib/index.js
CHANGED
|
@@ -4,29 +4,16 @@ import { debug } from "./debug.js";
|
|
|
4
4
|
import { fence_custom } from "./fence.js";
|
|
5
5
|
import { FlatTableParser } from "./flat-table.js";
|
|
6
6
|
import { merge } from "./merge.js";
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
tsv: "tsv-table"
|
|
13
|
-
}
|
|
7
|
+
const langNames = {
|
|
8
|
+
adv: "table",
|
|
9
|
+
flat: "flat-table",
|
|
10
|
+
csv: "csv-table",
|
|
11
|
+
tsv: "tsv-table",
|
|
14
12
|
};
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
flat: "",
|
|
18
|
-
csv: "",
|
|
19
|
-
tsv: "",
|
|
13
|
+
const defaultOption = {
|
|
14
|
+
name: langNames.adv,
|
|
20
15
|
};
|
|
21
|
-
function
|
|
22
|
-
return [
|
|
23
|
-
option.names.adv,
|
|
24
|
-
option.names.flat,
|
|
25
|
-
option.names.csv,
|
|
26
|
-
option.names.tsv
|
|
27
|
-
];
|
|
28
|
-
}
|
|
29
|
-
export function createParser(option) {
|
|
16
|
+
export function unifiedParser(option) {
|
|
30
17
|
return (info, state, startLine, endLine) => {
|
|
31
18
|
if (debug.isEnabled()) {
|
|
32
19
|
debug(">> table parse start");
|
|
@@ -49,52 +36,49 @@ export function createParser(option) {
|
|
|
49
36
|
}
|
|
50
37
|
const lang = info.slice(0, info.search(/\s|$/));
|
|
51
38
|
const params = info.slice(lang.length + 1);
|
|
52
|
-
if (lang === option.
|
|
39
|
+
if (lang === option.name) {
|
|
53
40
|
const parser = new AdvTableParser(params);
|
|
54
41
|
parser.parse(state, startLine + 1, endLine);
|
|
55
42
|
}
|
|
56
|
-
else if (lang ===
|
|
57
|
-
const parser = FlatTableParser.new(
|
|
43
|
+
else if (lang === langNames.flat) {
|
|
44
|
+
const parser = FlatTableParser.new(params, state, startLine + 1, endLine);
|
|
58
45
|
parser.parse(state, startLine + 1, endLine);
|
|
59
46
|
}
|
|
60
|
-
else if (lang ===
|
|
47
|
+
else if (lang === langNames.csv) {
|
|
61
48
|
const parser = CsvTableParser.new(params, ",");
|
|
62
49
|
parser.parse(state, startLine + 1, endLine);
|
|
63
50
|
}
|
|
64
|
-
else if (lang ===
|
|
51
|
+
else if (lang === langNames.tsv) {
|
|
65
52
|
const parser = CsvTableParser.new(params, "\t");
|
|
66
53
|
parser.parse(state, startLine + 1, endLine);
|
|
67
54
|
}
|
|
68
55
|
};
|
|
69
56
|
}
|
|
70
57
|
export const advTable = (md, option) => {
|
|
71
|
-
const opts = merge(
|
|
72
|
-
const
|
|
73
|
-
|
|
58
|
+
const opts = merge(defaultOption, option);
|
|
59
|
+
const awareNames = [
|
|
60
|
+
option?.name ?? langNames.adv,
|
|
61
|
+
langNames.flat,
|
|
62
|
+
langNames.csv,
|
|
63
|
+
langNames.tsv
|
|
64
|
+
];
|
|
65
|
+
const parser = unifiedParser(opts);
|
|
66
|
+
const rule = fence_custom(awareNames, parser);
|
|
74
67
|
md.block.ruler.before("fence", "adv_table", rule);
|
|
75
68
|
};
|
|
76
|
-
export const flatTable = (md
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
const parser = createParser(opts);
|
|
81
|
-
const rule = fence_custom(getAllNames(opts), parser);
|
|
82
|
-
md.block.ruler.before("fence", "csv_table", rule);
|
|
69
|
+
export const flatTable = (md) => {
|
|
70
|
+
const parser = unifiedParser(defaultOption);
|
|
71
|
+
const rule = fence_custom(langNames.flat, parser);
|
|
72
|
+
md.block.ruler.before("fence", "flat_table", rule);
|
|
83
73
|
};
|
|
84
|
-
export const csvTable = (md
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
const opts = merge(defaultOptions, { names });
|
|
88
|
-
const parser = createParser(opts);
|
|
89
|
-
const rule = fence_custom(getAllNames(opts), parser);
|
|
74
|
+
export const csvTable = (md) => {
|
|
75
|
+
const parser = unifiedParser(defaultOption);
|
|
76
|
+
const rule = fence_custom(langNames.csv, parser);
|
|
90
77
|
md.block.ruler.before("fence", "csv_table", rule);
|
|
91
78
|
};
|
|
92
|
-
export const tsvTable = (md
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
const parser = createParser(opts);
|
|
97
|
-
const rule = fence_custom(getAllNames(opts), parser);
|
|
98
|
-
md.block.ruler.before("fence", "csv_table", rule);
|
|
79
|
+
export const tsvTable = (md) => {
|
|
80
|
+
const parser = unifiedParser(defaultOption);
|
|
81
|
+
const rule = fence_custom(langNames.tsv, parser);
|
|
82
|
+
md.block.ruler.before("fence", "tsv_table", rule);
|
|
99
83
|
};
|
|
100
84
|
export default advTable;
|
package/lib/table-builder.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export declare class TableBuilder implements ITableBuilder {
|
|
|
11
11
|
readonly tableSpec: TableSpec;
|
|
12
12
|
readonly _cells: CellState;
|
|
13
13
|
constructor(state: StateBlock, tableSpec: TableSpec);
|
|
14
|
+
static newLocal(state: StateBlock, tableSpec: TableSpec): TableBuilder;
|
|
14
15
|
private get useColgroup();
|
|
15
16
|
private get useTHead();
|
|
16
17
|
private get useTBody();
|
package/lib/table-builder.js
CHANGED
|
@@ -9,6 +9,9 @@ export class TableBuilder {
|
|
|
9
9
|
this.tableSpec = tableSpec;
|
|
10
10
|
this._cells = new CellState(tableSpec);
|
|
11
11
|
}
|
|
12
|
+
static newLocal(state, tableSpec) {
|
|
13
|
+
return new TableBuilder(new state.md.block.State("", state.md, state.env, []), tableSpec);
|
|
14
|
+
}
|
|
12
15
|
get useColgroup() {
|
|
13
16
|
return this.tableSpec.attr.cols?.startsWith("\"");
|
|
14
17
|
}
|
|
@@ -23,6 +26,15 @@ export class TableBuilder {
|
|
|
23
26
|
this.tableSpec.classes.forEach(name => {
|
|
24
27
|
token.attrJoin("class", name);
|
|
25
28
|
});
|
|
29
|
+
if (this.tableSpec.attr["width"] !== undefined) {
|
|
30
|
+
const width = this.tableSpec.attr["width"];
|
|
31
|
+
if (/^\d+$/.test(width)) {
|
|
32
|
+
token.attrSet("width", width);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
token.attrSet("style", `width: ${width}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
26
38
|
if (this.tableSpec.attr["caption"] !== undefined) {
|
|
27
39
|
this.setCaption(this.tableSpec.attr["caption"]);
|
|
28
40
|
}
|
|
@@ -86,10 +98,9 @@ export class TableBuilder {
|
|
|
86
98
|
setColgroup(numCols) {
|
|
87
99
|
this.state.push("colgroup_open", "colgroup", 1);
|
|
88
100
|
for (let c = 0; c < numCols; c++) {
|
|
89
|
-
const
|
|
90
|
-
const colWidth = `${Math.round(colWidthRatio * 100).toFixed(0)}%`;
|
|
101
|
+
const widthProp = this.tableSpec.colspecs.colWidthPropValue(c);
|
|
91
102
|
const token = this.state.push("col", "col", 0);
|
|
92
|
-
token.attrSet("style", `width: ${
|
|
103
|
+
token.attrSet("style", `width: ${widthProp}`);
|
|
93
104
|
}
|
|
94
105
|
this.state.push("colgroup_close", "colgroup", -1);
|
|
95
106
|
}
|
package/lib/table.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export type TableAttr = {
|
|
|
7
7
|
};
|
|
8
8
|
export interface ColumnAttr {
|
|
9
9
|
align?: HAlign;
|
|
10
|
-
width?:
|
|
10
|
+
width?: ColWidth;
|
|
11
11
|
}
|
|
12
12
|
export type CellAttr = {
|
|
13
13
|
align?: HAlign;
|
|
@@ -15,6 +15,13 @@ export type CellAttr = {
|
|
|
15
15
|
rowspan?: number;
|
|
16
16
|
header?: boolean;
|
|
17
17
|
};
|
|
18
|
+
export declare class ColWidth {
|
|
19
|
+
text: string;
|
|
20
|
+
constructor(text: string);
|
|
21
|
+
get hasUnit(): boolean;
|
|
22
|
+
get relSize(): number;
|
|
23
|
+
static widthPropertyValue(c: ColWidth, all: ColWidth[]): string;
|
|
24
|
+
}
|
|
18
25
|
export declare class TableSpec {
|
|
19
26
|
readonly attr: TableAttr;
|
|
20
27
|
readonly classes: string[];
|
|
@@ -32,8 +39,8 @@ export declare class ColSpecs {
|
|
|
32
39
|
readonly specs: readonly ColumnAttr[];
|
|
33
40
|
constructor(colspec: string);
|
|
34
41
|
colSpec(col: number): ColumnAttr;
|
|
35
|
-
colWidth(col: number):
|
|
36
|
-
|
|
42
|
+
colWidth(col: number): ColWidth;
|
|
43
|
+
colWidthPropValue(col: number): string;
|
|
37
44
|
lazyInit(cols: number): void;
|
|
38
45
|
static parseColSpec(spec: string): ColumnAttr;
|
|
39
46
|
}
|
package/lib/table.js
CHANGED
|
@@ -1,4 +1,43 @@
|
|
|
1
1
|
import { Lexer, unwrapLiteral } from "./lexer.js";
|
|
2
|
+
const cssUnits = [
|
|
3
|
+
"px", "%", "em", "rem",
|
|
4
|
+
"ex", "rex", "cap", "rcap",
|
|
5
|
+
"cm", "mm", "Q", "in", "pt", "pc",
|
|
6
|
+
"ch", "rch", "ic", "ric", "lh", "rlh",
|
|
7
|
+
"vw", "vh", "vi", "vb", "vmin", "vmax",
|
|
8
|
+
"svw", "svh", "svi", "svb", "svmin", "svmax",
|
|
9
|
+
"lvw", "lvh", "lvi", "lvb", "lvmin", "lvmax",
|
|
10
|
+
"dvw", "dvh", "dvi", "dvb", "dvmin", "dvmax",
|
|
11
|
+
"cqw", "cqh", "cqi", "cqb", "cqmin", "cqmax"
|
|
12
|
+
];
|
|
13
|
+
export class ColWidth {
|
|
14
|
+
text;
|
|
15
|
+
constructor(text) {
|
|
16
|
+
this.text = text;
|
|
17
|
+
}
|
|
18
|
+
get hasUnit() {
|
|
19
|
+
return !/^\d+$/.test(this.text);
|
|
20
|
+
}
|
|
21
|
+
get relSize() {
|
|
22
|
+
return this.hasUnit ? 0 : parseInt(this.text, 10);
|
|
23
|
+
}
|
|
24
|
+
static widthPropertyValue(c, all) {
|
|
25
|
+
if (c.hasUnit) {
|
|
26
|
+
return c.text;
|
|
27
|
+
}
|
|
28
|
+
const total = all
|
|
29
|
+
.filter(cw => !cw.hasUnit)
|
|
30
|
+
.reduce((sum, cw) => sum + cw.relSize, 0);
|
|
31
|
+
const exclude = all.filter(cw => cw.hasUnit);
|
|
32
|
+
if (exclude.length === 0) {
|
|
33
|
+
return `calc(100% * ${c.relSize} / ${total})`;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
const sum = exclude.map(cw => cw.text).join(" + ");
|
|
37
|
+
return `calc((100% - (${sum})) * ${c.relSize} / ${total})`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
2
41
|
export class TableSpec {
|
|
3
42
|
attr;
|
|
4
43
|
classes;
|
|
@@ -16,8 +55,8 @@ export class TableSpec {
|
|
|
16
55
|
return this.colspecs.numCols;
|
|
17
56
|
}
|
|
18
57
|
static parseClass(classnames) {
|
|
19
|
-
return classnames
|
|
20
|
-
.split(
|
|
58
|
+
return unwrapLiteral(classnames, "\"")
|
|
59
|
+
.split(/[\s,]/)
|
|
21
60
|
.map((s) => s.trim())
|
|
22
61
|
.filter(s => s.length > 0)
|
|
23
62
|
.filter((s, i, arr) => arr.indexOf(s) === i);
|
|
@@ -79,6 +118,7 @@ export class TableSpec {
|
|
|
79
118
|
"header-cols": "",
|
|
80
119
|
"header-rows": "",
|
|
81
120
|
class: "",
|
|
121
|
+
width: "",
|
|
82
122
|
format: ""
|
|
83
123
|
};
|
|
84
124
|
return Object.keys(k);
|
|
@@ -108,16 +148,14 @@ export class ColSpecs {
|
|
|
108
148
|
colWidth(col) {
|
|
109
149
|
const spec = this.colSpec(col);
|
|
110
150
|
if (spec.width) {
|
|
111
|
-
return
|
|
151
|
+
return spec.width;
|
|
112
152
|
}
|
|
113
|
-
return 1;
|
|
153
|
+
return new ColWidth("1");
|
|
114
154
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
return this.colWidth(col) / totalWidth;
|
|
155
|
+
colWidthPropValue(col) {
|
|
156
|
+
const c = this.colWidth(col);
|
|
157
|
+
const all = this.specs.map(s => s.width || new ColWidth("1"));
|
|
158
|
+
return ColWidth.widthPropertyValue(c, all);
|
|
121
159
|
}
|
|
122
160
|
lazyInit(cols) {
|
|
123
161
|
this.numCols = cols;
|
|
@@ -141,7 +179,7 @@ export class ColSpecs {
|
|
|
141
179
|
attr.align = "right";
|
|
142
180
|
}
|
|
143
181
|
else if (char >= "0" && char <= "9") {
|
|
144
|
-
attr.width =
|
|
182
|
+
attr.width = consumeColWidth();
|
|
145
183
|
break;
|
|
146
184
|
}
|
|
147
185
|
else {
|
|
@@ -152,11 +190,13 @@ export class ColSpecs {
|
|
|
152
190
|
function consume() {
|
|
153
191
|
return spec[pos++];
|
|
154
192
|
}
|
|
155
|
-
function
|
|
156
|
-
const
|
|
193
|
+
function consumeColWidth() {
|
|
194
|
+
const regex = new RegExp(`^\\d+(${cssUnits.join("|")})?`);
|
|
195
|
+
const match = spec.slice(pos).match(regex);
|
|
157
196
|
if (!match)
|
|
158
|
-
throw new Error("cannot consume
|
|
159
|
-
|
|
197
|
+
throw new Error("cannot consume col width");
|
|
198
|
+
pos += match[0].length;
|
|
199
|
+
return new ColWidth(match[0]);
|
|
160
200
|
}
|
|
161
201
|
}
|
|
162
202
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "markdown-it-adv-table",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Markdown syntax extension for better table support",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|
|
@@ -34,13 +34,13 @@
|
|
|
34
34
|
"lint:fix": "eslint src --fix"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@cobapen/eslint-config": "^0.
|
|
37
|
+
"@cobapen/eslint-config": "^0.5.0",
|
|
38
38
|
"@types/markdown-it": "^14.1.2",
|
|
39
|
-
"@types/node": "^
|
|
40
|
-
"@vitest/coverage-v8": "^
|
|
41
|
-
"eslint": "^9.
|
|
39
|
+
"@types/node": "^25.2.1",
|
|
40
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
41
|
+
"eslint": "^9.39.2",
|
|
42
42
|
"markdown-it": "^14.1.0",
|
|
43
|
-
"typescript": "^5.
|
|
44
|
-
"vitest": "^
|
|
43
|
+
"typescript": "^5.9.3",
|
|
44
|
+
"vitest": "^4.0.18"
|
|
45
45
|
}
|
|
46
46
|
}
|