@adobe/helix-markdown-support 3.1.8 → 4.0.2
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/.circleci/config.yml +8 -19
- package/.eslintrc.cjs +1 -0
- package/CHANGELOG.md +26 -0
- package/package.json +16 -7
- package/src/gridtable/README.md +207 -0
- package/src/gridtable/from-markdown.js +273 -0
- package/src/gridtable/index.js +91 -0
- package/src/gridtable/mdast2hast-handler.js +119 -0
- package/src/gridtable/remark-plugin.js +36 -0
- package/src/gridtable/syntax.js +352 -0
- package/src/gridtable/to-markdown.js +538 -0
- package/src/gridtable/types.js +17 -0
- package/src/index.js +2 -1
- package/src/{remark-matter → matter}/from-markdown.js +4 -3
- package/src/{remark-matter → matter}/index.js +2 -19
- package/src/matter/remark-plugin.js +31 -0
- package/src/{remark-matter → matter}/syntax.js +3 -2
- package/src/{remark-matter → matter}/to-markdown.js +3 -1
- package/src/matter/types.js +12 -0
- package/src/mdast-dereference.js +65 -0
- package/src/mdast-image-references.js +55 -0
- package/src/mdast-robust-tables.js +1 -1
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
/* eslint-disable no-unused-vars,no-param-reassign */
|
|
13
|
+
import { text as textHandler } from 'mdast-util-to-markdown/lib/handle/text.js';
|
|
14
|
+
import { inlineCode } from 'mdast-util-to-markdown/lib/handle/inline-code.js';
|
|
15
|
+
import { code } from 'mdast-util-to-markdown/lib/handle/code.js';
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
TYPE_BODY, TYPE_CELL, TYPE_HEADER, TYPE_FOOTER, TYPE_ROW, TYPE_TABLE,
|
|
19
|
+
} from './types.js';
|
|
20
|
+
|
|
21
|
+
function* distribute(size, times) {
|
|
22
|
+
const delta = size / times;
|
|
23
|
+
let len = delta;
|
|
24
|
+
let prevLen = 0;
|
|
25
|
+
for (let i = 0; i < times - 1; i += 1) {
|
|
26
|
+
yield [Math.round(len - prevLen), i];
|
|
27
|
+
prevLen = Math.round(len);
|
|
28
|
+
len += delta;
|
|
29
|
+
}
|
|
30
|
+
yield [Math.round(size - prevLen), times - 1];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function spanWidth(cols, idx, cell) {
|
|
34
|
+
let width = 0;
|
|
35
|
+
for (let i = 0; i < cell.colSpan; i += 1) {
|
|
36
|
+
width += cols[idx + i].width;
|
|
37
|
+
}
|
|
38
|
+
return width;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function lineWrapTextHandler(node, parent, context, safeOptions) {
|
|
42
|
+
const textNode = {
|
|
43
|
+
...node,
|
|
44
|
+
value: node.value.replace(/\s/g, ' '),
|
|
45
|
+
};
|
|
46
|
+
let value = textHandler(textNode, parent, context, safeOptions);
|
|
47
|
+
const { lineWidth } = context.options;
|
|
48
|
+
if (lineWidth && value.length > lineWidth) {
|
|
49
|
+
// check if in heading
|
|
50
|
+
if (context.stack.includes('headingAtx')) {
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
const lines = [];
|
|
54
|
+
const words = value.split(' ');
|
|
55
|
+
let len = safeOptions.now.column - 1;
|
|
56
|
+
let line = [];
|
|
57
|
+
for (const word of words) {
|
|
58
|
+
const wordLen = word.length;
|
|
59
|
+
if (len + wordLen > lineWidth && line.length > 0) {
|
|
60
|
+
lines.push(line.join(' '));
|
|
61
|
+
line = [];
|
|
62
|
+
len = 0;
|
|
63
|
+
}
|
|
64
|
+
line.push(word);
|
|
65
|
+
len += wordLen + 1;
|
|
66
|
+
}
|
|
67
|
+
if (line.length) {
|
|
68
|
+
lines.push(line.join(' '));
|
|
69
|
+
}
|
|
70
|
+
value = lines.join('\n');
|
|
71
|
+
}
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
// don't wrap for peek operations
|
|
75
|
+
lineWrapTextHandler.peek = textHandler;
|
|
76
|
+
|
|
77
|
+
class Table {
|
|
78
|
+
constructor() {
|
|
79
|
+
Object.assign(this, {
|
|
80
|
+
lastRow: null,
|
|
81
|
+
rows: [],
|
|
82
|
+
headerSize: 0,
|
|
83
|
+
footerSize: 0,
|
|
84
|
+
opts: {
|
|
85
|
+
// default desired width of a table (including delimiters)
|
|
86
|
+
width: 120,
|
|
87
|
+
// minimum cell content width (excluding delimiters)
|
|
88
|
+
minCellWidth: 12,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
addHeaderRow(row) {
|
|
94
|
+
this.addRow(row, this.headerSize);
|
|
95
|
+
this.headerSize += 1;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
addRow(cells, idx = this.rows.length - this.footerSize) {
|
|
99
|
+
const row = {
|
|
100
|
+
height: 0,
|
|
101
|
+
cells: [],
|
|
102
|
+
};
|
|
103
|
+
this.rows.splice(idx, 0, row);
|
|
104
|
+
this.lastRow = this.rows[this.rows.length - 1];
|
|
105
|
+
for (const cell of cells) {
|
|
106
|
+
this.addCell(cell, row);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
addFooterRow(row) {
|
|
111
|
+
this.addRow(row, this.rows.length);
|
|
112
|
+
this.footerSize += 1;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
addCell(cell, row) {
|
|
116
|
+
if (!this.lastRow) {
|
|
117
|
+
this.lastRow = {
|
|
118
|
+
height: 0,
|
|
119
|
+
cells: [],
|
|
120
|
+
};
|
|
121
|
+
this.rows.push(this.lastRow);
|
|
122
|
+
}
|
|
123
|
+
row = row || this.lastRow;
|
|
124
|
+
row.cells.push(cell);
|
|
125
|
+
for (let i = 1; i < cell.colSpan; i += 1) {
|
|
126
|
+
row.cells.push({});
|
|
127
|
+
}
|
|
128
|
+
// remember align for last span
|
|
129
|
+
if (cell.colSpan > 1) {
|
|
130
|
+
row.cells[row.cells.length - 1].align = cell.align;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
renderCell(cell, context, maxWidth) {
|
|
135
|
+
// set line wrap to width
|
|
136
|
+
const oldWidth = context.options.lineWidth;
|
|
137
|
+
// it's easier to calculate in the padding (+2) and border (+1) here than everywhere else.
|
|
138
|
+
// so the column width is equal to the cell.width
|
|
139
|
+
context.options.lineWidth = maxWidth - 3;
|
|
140
|
+
context.options.minLineWidth = this.opts.minCellWidth;
|
|
141
|
+
|
|
142
|
+
// enter cell construct in order to escape unsafe characters
|
|
143
|
+
const exit = context.enter(TYPE_CELL);
|
|
144
|
+
|
|
145
|
+
cell.value = context.handle(cell.tree, null, context, {
|
|
146
|
+
before: '\n',
|
|
147
|
+
after: '\n',
|
|
148
|
+
now: { line: 1, column: 1 },
|
|
149
|
+
lineShift: 0,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
exit();
|
|
153
|
+
|
|
154
|
+
context.options.lineWidth = oldWidth;
|
|
155
|
+
// calculate actual width and height of cell
|
|
156
|
+
cell.lines = cell.value.split('\n');
|
|
157
|
+
cell.height = cell.lines.length;
|
|
158
|
+
cell.width = 0;
|
|
159
|
+
for (const line of cell.lines) {
|
|
160
|
+
cell.width = Math.max(cell.width, line.length);
|
|
161
|
+
}
|
|
162
|
+
cell.width += 3;
|
|
163
|
+
return cell;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
toMarkdown(context) {
|
|
167
|
+
// populate the matrix with the rowspans and compute max width
|
|
168
|
+
// (the empty cells for the colspans are already created during insert).
|
|
169
|
+
const cols = [];
|
|
170
|
+
for (let y = 0; y < this.rows.length; y += 1) {
|
|
171
|
+
const row = this.rows[y];
|
|
172
|
+
for (let x = 0; x < row.cells.length; x += 1) {
|
|
173
|
+
let col = cols[x];
|
|
174
|
+
if (!col) {
|
|
175
|
+
col = {
|
|
176
|
+
width: 3,
|
|
177
|
+
};
|
|
178
|
+
cols[x] = col;
|
|
179
|
+
}
|
|
180
|
+
const cell = row.cells[x];
|
|
181
|
+
if (cell.rowSpan > 1) {
|
|
182
|
+
// insert colspan amount of null cells below
|
|
183
|
+
for (let i = 1; i < cell.rowSpan; i += 1) {
|
|
184
|
+
const yy = i + y;
|
|
185
|
+
// create empty linked cells for the rows, so that it can render the lines correctly.
|
|
186
|
+
const empty = new Array(cell.colSpan).fill({});
|
|
187
|
+
empty[0] = { linked: cell };
|
|
188
|
+
this.rows[yy].cells.splice(x, 0, ...empty);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const numCols = cols.length;
|
|
194
|
+
|
|
195
|
+
// add empty cells if needed
|
|
196
|
+
for (const row of this.rows) {
|
|
197
|
+
for (let i = row.cells.length; i < numCols; i += 1) {
|
|
198
|
+
row.cells.push({ tree: { type: 'root' }, colSpan: 1, rowSpan: 1 });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// populate the columns with default max widths
|
|
203
|
+
for (const [d, idx] of distribute(this.opts.width, numCols)) {
|
|
204
|
+
cols[idx].maxWidth = d;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// render cells
|
|
208
|
+
for (const row of this.rows) {
|
|
209
|
+
for (let x = 0; x < row.cells.length; x += 1) {
|
|
210
|
+
const cell = row.cells[x];
|
|
211
|
+
if (cell.tree) {
|
|
212
|
+
// get the max width from the columns it spans
|
|
213
|
+
let maxWidth = 0;
|
|
214
|
+
for (let i = 0; i < cell.colSpan; i += 1) {
|
|
215
|
+
maxWidth += cols[x + i].maxWidth;
|
|
216
|
+
}
|
|
217
|
+
this.renderCell(cell, context, maxWidth);
|
|
218
|
+
// distribute effective cell.width among the columns it spans
|
|
219
|
+
for (const [avgColWidth, idx] of distribute(cell.width, cell.colSpan)) {
|
|
220
|
+
const col = cols[x + idx];
|
|
221
|
+
col.width = Math.max(col.width, avgColWidth);
|
|
222
|
+
}
|
|
223
|
+
// if valign, the col needs to be at least 4 (3 + delim) wide
|
|
224
|
+
if (cell.valign) {
|
|
225
|
+
cols[x].width = Math.max(4, cols[x].width);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// re-render cells where elements dictated the min-width (eg, large headings)
|
|
231
|
+
for (const row of this.rows) {
|
|
232
|
+
row.minHeight = 0;
|
|
233
|
+
row.height = 0;
|
|
234
|
+
for (let x = 0; x < row.cells.length; x += 1) {
|
|
235
|
+
const cell = row.cells[x];
|
|
236
|
+
if (cell.tree) {
|
|
237
|
+
// get the max width from the columns it spans
|
|
238
|
+
const width = spanWidth(cols, x, cell);
|
|
239
|
+
if (width >= cell.width) {
|
|
240
|
+
this.renderCell(cell, context, width);
|
|
241
|
+
// if the new cell width is bigger now (most probably due to a problem in the line
|
|
242
|
+
// break renderer), fix the columns.
|
|
243
|
+
if (cell.width > width) {
|
|
244
|
+
for (const [avgColWidth, idx] of distribute(cell.width, cell.colSpan)) {
|
|
245
|
+
const col = cols[x + idx];
|
|
246
|
+
col.width = Math.max(col.width, avgColWidth);
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
cell.width = width;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (cell.rowSpan === 1) {
|
|
253
|
+
row.height = Math.max(row.height, cell.height);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// distribute row spans
|
|
260
|
+
for (let y = 0; y < this.rows.length; y += 1) {
|
|
261
|
+
const row = this.rows[y];
|
|
262
|
+
for (let x = 0; x < row.cells.length; x += 1) {
|
|
263
|
+
const cell = row.cells[x];
|
|
264
|
+
if (cell.rowSpan > 1) {
|
|
265
|
+
const distHeight = Math.max(cell.rowSpan, cell.height - cell.rowSpan + 1);
|
|
266
|
+
for (const [d, idx] of distribute(distHeight, cell.rowSpan)) {
|
|
267
|
+
this.rows[y + idx].height = Math.max(this.rows[y + idx].height, d);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// create grid and table
|
|
274
|
+
const gtVLineEnds = '+';
|
|
275
|
+
const gtHLineEnds = '+';
|
|
276
|
+
const align = {
|
|
277
|
+
left: { b: ':', e: '', len: 1 },
|
|
278
|
+
right: { b: '', e: ':', len: 1 },
|
|
279
|
+
center: { b: ':', e: ':', len: 2 },
|
|
280
|
+
justify: { b: '>', e: '<', len: 2 },
|
|
281
|
+
top: '^',
|
|
282
|
+
bottom: 'v',
|
|
283
|
+
middle: 'x',
|
|
284
|
+
};
|
|
285
|
+
const lines = [];
|
|
286
|
+
// eslint-disable-next-line no-nested-ternary
|
|
287
|
+
const headerIdx = this.headerSize
|
|
288
|
+
? this.headerSize
|
|
289
|
+
: (this.footerSize ? 0 : -1);
|
|
290
|
+
const footerIdx = this.rows.length - this.footerSize;
|
|
291
|
+
for (let y = 0; y < this.rows.length; y += 1) {
|
|
292
|
+
const row = this.rows[y];
|
|
293
|
+
|
|
294
|
+
// first, draw the grid line
|
|
295
|
+
const grid = [];
|
|
296
|
+
const c = y === headerIdx || y === footerIdx ? '=' : '-';
|
|
297
|
+
let prevCell;
|
|
298
|
+
let pendingGrid = 0;
|
|
299
|
+
let pendingAlign = null;
|
|
300
|
+
let pendingVAlign = null;
|
|
301
|
+
|
|
302
|
+
const commitInnerGridLine = () => {
|
|
303
|
+
if (pendingVAlign) {
|
|
304
|
+
const middle = Math.floor((pendingGrid - 1) / 2);
|
|
305
|
+
grid.push(c.repeat(middle));
|
|
306
|
+
grid.push(pendingVAlign);
|
|
307
|
+
grid.push(c.repeat(pendingGrid - middle - 1));
|
|
308
|
+
} else {
|
|
309
|
+
grid.push(c.repeat(pendingGrid));
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const commitGridLine = () => {
|
|
314
|
+
if (pendingGrid) {
|
|
315
|
+
if (pendingAlign) {
|
|
316
|
+
pendingGrid -= pendingAlign.len;
|
|
317
|
+
grid.push(pendingAlign.b);
|
|
318
|
+
commitInnerGridLine();
|
|
319
|
+
grid.push(pendingAlign.e);
|
|
320
|
+
} else {
|
|
321
|
+
commitInnerGridLine();
|
|
322
|
+
}
|
|
323
|
+
pendingGrid = 0;
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
for (let x = 0; x < row.cells.length; x += 1) {
|
|
328
|
+
let d0 = '+';
|
|
329
|
+
if (x === 0 && y > 0) {
|
|
330
|
+
d0 = gtHLineEnds;
|
|
331
|
+
}
|
|
332
|
+
if (y === 0 && x > 0) {
|
|
333
|
+
d0 = gtVLineEnds;
|
|
334
|
+
}
|
|
335
|
+
const cell = row.cells[x];
|
|
336
|
+
const col = cols[x];
|
|
337
|
+
if (cell.tree) {
|
|
338
|
+
commitGridLine();
|
|
339
|
+
grid.push(d0);
|
|
340
|
+
pendingGrid = col.width - 1;
|
|
341
|
+
pendingAlign = align[cell.align];
|
|
342
|
+
pendingVAlign = align[cell.valign];
|
|
343
|
+
} else if (cell.linked) {
|
|
344
|
+
commitGridLine();
|
|
345
|
+
const width = spanWidth(cols, x, cell.linked);
|
|
346
|
+
const text = cell.linked.lines.shift() || '';
|
|
347
|
+
grid.push(`| ${text.padEnd(width - 3, ' ')} `);
|
|
348
|
+
x += cell.linked.colSpan - 1;
|
|
349
|
+
} else {
|
|
350
|
+
pendingGrid += col.width;
|
|
351
|
+
}
|
|
352
|
+
prevCell = cell;
|
|
353
|
+
}
|
|
354
|
+
commitGridLine();
|
|
355
|
+
|
|
356
|
+
// if last col was a rowspan, draw a |
|
|
357
|
+
let d3 = prevCell?.linked ? '|' : gtHLineEnds;
|
|
358
|
+
if (y === 0) {
|
|
359
|
+
d3 = '+';
|
|
360
|
+
}
|
|
361
|
+
lines.push(`${grid.join('')}${d3}`);
|
|
362
|
+
|
|
363
|
+
// then draw the cells
|
|
364
|
+
for (let yy = 0; yy < row.height; yy += 1) {
|
|
365
|
+
const line = [];
|
|
366
|
+
for (let x = 0; x < row.cells.length; x += 1) {
|
|
367
|
+
let cell = row.cells[x];
|
|
368
|
+
if (cell.linked) {
|
|
369
|
+
cell = cell.linked;
|
|
370
|
+
}
|
|
371
|
+
if (cell.tree) {
|
|
372
|
+
const width = spanWidth(cols, x, cell);
|
|
373
|
+
let text = '';
|
|
374
|
+
if (!cell.valign
|
|
375
|
+
|| cell.valign === 'top'
|
|
376
|
+
|| (cell.valign === 'middle' && yy >= Math.floor(row.height - cell.height) / 2)
|
|
377
|
+
|| (cell.valign === 'bottom' && yy >= row.height - cell.height)) {
|
|
378
|
+
text = cell.lines.shift() || '';
|
|
379
|
+
}
|
|
380
|
+
line.push(`| ${text.padEnd(width - 3, ' ')} `);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
lines.push(`${line.join('')}|`);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// add last grid line
|
|
388
|
+
const grid = [];
|
|
389
|
+
const lastRow = this.rows[this.rows.length - 1];
|
|
390
|
+
for (let x = 0; x < cols.length; x += 1) {
|
|
391
|
+
const col = cols[x];
|
|
392
|
+
// if the cell above was a colspan, and we are on the last line, don't draw the `+`
|
|
393
|
+
const aboveCell = lastRow.cells[x];
|
|
394
|
+
let c = aboveCell.tree || aboveCell.linked ? gtVLineEnds : '-';
|
|
395
|
+
if (x === 0) {
|
|
396
|
+
c = '+';
|
|
397
|
+
}
|
|
398
|
+
grid.push(`${c}${'-'.repeat(col.width - 1)}`);
|
|
399
|
+
}
|
|
400
|
+
lines.push(`${grid.join('')}+`);
|
|
401
|
+
|
|
402
|
+
return lines.join('\n');
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function pushTable(context, table) {
|
|
407
|
+
if (!context.gridTables) {
|
|
408
|
+
context.gridTables = [];
|
|
409
|
+
}
|
|
410
|
+
context.gridTables.push(table);
|
|
411
|
+
return table;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function popTable(context) {
|
|
415
|
+
return context.gridTables.pop();
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function peekTable(context) {
|
|
419
|
+
return context.gridTables[context.gridTables.length - 1];
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function handleCell(node, parent, context, safeOptions) {
|
|
423
|
+
return {
|
|
424
|
+
tree: {
|
|
425
|
+
type: 'root',
|
|
426
|
+
children: node.children,
|
|
427
|
+
},
|
|
428
|
+
colSpan: node.colSpan || 1,
|
|
429
|
+
rowSpan: node.rowSpan || 1,
|
|
430
|
+
align: node.align,
|
|
431
|
+
valign: node.valign,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function handleRow(node, parent, context, safeOptions) {
|
|
436
|
+
const row = [];
|
|
437
|
+
for (const child of node.children) {
|
|
438
|
+
if (child.type === TYPE_CELL) {
|
|
439
|
+
row.push(handleCell(child, node, context, safeOptions));
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return row;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function handleHeader(node, parent, context, safeOptions) {
|
|
446
|
+
const table = peekTable(context);
|
|
447
|
+
for (const child of node.children) {
|
|
448
|
+
if (child.type === TYPE_ROW) {
|
|
449
|
+
table.addHeaderRow(handleRow(child, node, context, safeOptions));
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function handleBody(node, parent, context, safeOptions) {
|
|
455
|
+
const table = peekTable(context);
|
|
456
|
+
for (const child of node.children) {
|
|
457
|
+
if (child.type === TYPE_ROW) {
|
|
458
|
+
table.addRow(handleRow(child, node, context, safeOptions));
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function handleFooter(node, parent, context, safeOptions) {
|
|
464
|
+
const table = peekTable(context);
|
|
465
|
+
for (const child of node.children) {
|
|
466
|
+
if (child.type === TYPE_ROW) {
|
|
467
|
+
table.addFooterRow(handleRow(child, node, context, safeOptions));
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function gridTable(node, parent, context, safeOptions) {
|
|
473
|
+
const exit = context.enter(TYPE_TABLE);
|
|
474
|
+
|
|
475
|
+
const table = pushTable(context, new Table());
|
|
476
|
+
|
|
477
|
+
for (const child of node.children) {
|
|
478
|
+
if (child.type === TYPE_HEADER) {
|
|
479
|
+
handleHeader(child, node, context, safeOptions);
|
|
480
|
+
} else if (child.type === TYPE_BODY) {
|
|
481
|
+
handleBody(child, node, context, safeOptions);
|
|
482
|
+
} else if (child.type === TYPE_FOOTER) {
|
|
483
|
+
handleFooter(child, node, context, safeOptions);
|
|
484
|
+
} else if (child.type === TYPE_ROW) {
|
|
485
|
+
table.addRow(handleRow(child, node, context, safeOptions));
|
|
486
|
+
} else if (child.type === TYPE_CELL) {
|
|
487
|
+
table.addCell(handleCell(child, node, context, safeOptions));
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
exit();
|
|
492
|
+
|
|
493
|
+
return popTable(context).toMarkdown(context);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Escapes cell delimiters in (block)) code
|
|
498
|
+
*/
|
|
499
|
+
function blockCodeWithTable(node, parent, context) {
|
|
500
|
+
let value = code(node, parent, context);
|
|
501
|
+
|
|
502
|
+
if (context.stack.includes(TYPE_CELL)) {
|
|
503
|
+
value = value.replace(/[|+]/mg, '\\$&');
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
return value;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Escapes cell delimiters in inline code
|
|
511
|
+
*/
|
|
512
|
+
function inlineCodeWithTable(node, parent, context) {
|
|
513
|
+
let value = inlineCode(node, parent, context);
|
|
514
|
+
|
|
515
|
+
if (context.stack.includes(TYPE_CELL)) {
|
|
516
|
+
value = value.replace(/[|+]/g, '\\$&');
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
return value;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
export default function toMarkdown() {
|
|
523
|
+
return {
|
|
524
|
+
unsafe: [
|
|
525
|
+
// A pipe or a + in a cell must be encoded.
|
|
526
|
+
{ character: '|', inConstruct: TYPE_CELL },
|
|
527
|
+
{ character: '+', inConstruct: TYPE_CELL },
|
|
528
|
+
],
|
|
529
|
+
handlers: {
|
|
530
|
+
// for now, we only line wrap 'text' nodes. all other would need more support in
|
|
531
|
+
// the default mdast-to-markdown handlers
|
|
532
|
+
text: lineWrapTextHandler,
|
|
533
|
+
gridTable,
|
|
534
|
+
inlineCode: inlineCodeWithTable,
|
|
535
|
+
code: blockCodeWithTable,
|
|
536
|
+
},
|
|
537
|
+
};
|
|
538
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
export const TYPE_TABLE = 'gridTable';
|
|
13
|
+
export const TYPE_HEADER = 'gtHeader';
|
|
14
|
+
export const TYPE_BODY = 'gtBody';
|
|
15
|
+
export const TYPE_FOOTER = 'gtFooter';
|
|
16
|
+
export const TYPE_ROW = 'gtRow';
|
|
17
|
+
export const TYPE_CELL = 'gtCell';
|
package/src/index.js
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
export { default as remarkMatter } from './remark-matter/index.js';
|
|
14
13
|
export { default as robustTables } from './mdast-robust-tables.js';
|
|
15
14
|
export { default as breaksAsSpaces } from './remark-breaks-as-spaces.js';
|
|
16
15
|
export { default as sanitizeHeading } from './mdast-sanitize-heading.js';
|
|
@@ -19,3 +18,5 @@ export { default as sanitizeFormats } from './mdast-sanitize-formats.js';
|
|
|
19
18
|
export { default as fixCodeFlow } from './mdast-fix-code-flow.js';
|
|
20
19
|
export { default as sanitizeLinks } from './mdast-sanitize-links.js';
|
|
21
20
|
export { default as sanitizeText } from './mdast-sanitize-text.js';
|
|
21
|
+
export { default as imageReferences } from './mdast-image-references.js';
|
|
22
|
+
export { default as dereference } from './mdast-dereference.js';
|
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
import jsYaml from 'js-yaml';
|
|
13
|
+
import { TYPE_YAML } from './types.js';
|
|
13
14
|
|
|
14
15
|
function open(token) {
|
|
15
|
-
this.enter({ type:
|
|
16
|
+
this.enter({ type: TYPE_YAML, value: '', payload: {} }, token);
|
|
16
17
|
this.buffer();
|
|
17
18
|
}
|
|
18
19
|
|
|
@@ -41,10 +42,10 @@ function value(token) {
|
|
|
41
42
|
export default function fromMarkdown(options = {}) {
|
|
42
43
|
return {
|
|
43
44
|
enter: {
|
|
44
|
-
|
|
45
|
+
[TYPE_YAML]: open,
|
|
45
46
|
},
|
|
46
47
|
exit: {
|
|
47
|
-
|
|
48
|
+
[TYPE_YAML]: createClose(options),
|
|
48
49
|
yamlValue: value,
|
|
49
50
|
},
|
|
50
51
|
};
|
|
@@ -9,9 +9,6 @@
|
|
|
9
9
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
-
import fromMarkdown from './from-markdown.js';
|
|
13
|
-
import toMarkdown from './to-markdown.js';
|
|
14
|
-
import syntax from './syntax.js';
|
|
15
12
|
|
|
16
13
|
/**
|
|
17
14
|
* Front- and mid-matter remark plugin.
|
|
@@ -83,19 +80,5 @@ import syntax from './syntax.js';
|
|
|
83
80
|
* @param {object} options Plugin options
|
|
84
81
|
* @param {Function} options.errorHandler Function that is invoked on yaml parsing errors.
|
|
85
82
|
*/
|
|
86
|
-
export
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
function add(field, value) {
|
|
90
|
-
/* c8 ignore next 2 */
|
|
91
|
-
if (data[field]) {
|
|
92
|
-
data[field].push(value);
|
|
93
|
-
} else {
|
|
94
|
-
data[field] = [value];
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
add('micromarkExtensions', syntax(options));
|
|
99
|
-
add('fromMarkdownExtensions', fromMarkdown(options));
|
|
100
|
-
add('toMarkdownExtensions', toMarkdown(options));
|
|
101
|
-
}
|
|
83
|
+
export * from './types.js';
|
|
84
|
+
export { default as remarkMatter } from './remark-plugin.js';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2018 Adobe. All rights reserved.
|
|
3
|
+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
*
|
|
7
|
+
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
* governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
import fromMarkdown from './from-markdown.js';
|
|
13
|
+
import toMarkdown from './to-markdown.js';
|
|
14
|
+
import syntax from './syntax.js';
|
|
15
|
+
|
|
16
|
+
export default function remarkPlugin(options) {
|
|
17
|
+
const data = this.data();
|
|
18
|
+
|
|
19
|
+
function add(field, value) {
|
|
20
|
+
/* c8 ignore next 2 */
|
|
21
|
+
if (data[field]) {
|
|
22
|
+
data[field].push(value);
|
|
23
|
+
} else {
|
|
24
|
+
data[field] = [value];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
add('micromarkExtensions', syntax(options));
|
|
29
|
+
add('fromMarkdownExtensions', fromMarkdown(options));
|
|
30
|
+
add('toMarkdownExtensions', toMarkdown(options));
|
|
31
|
+
}
|
|
@@ -14,6 +14,7 @@ import jsYaml from 'js-yaml';
|
|
|
14
14
|
import { codes } from 'micromark-util-symbol/codes.js';
|
|
15
15
|
import { types } from 'micromark-util-symbol/types.js';
|
|
16
16
|
import { markdownLineEnding, markdownSpace } from 'micromark-util-character';
|
|
17
|
+
import { TYPE_YAML } from './types.js';
|
|
17
18
|
|
|
18
19
|
const type = (v) => ((v !== undefined && v !== null) ? v.constructor : v);
|
|
19
20
|
|
|
@@ -94,7 +95,7 @@ function parse(options) {
|
|
|
94
95
|
}
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
effects.enter(
|
|
98
|
+
effects.enter(TYPE_YAML);
|
|
98
99
|
|
|
99
100
|
// after the fence `---` is detected, we are at the end of the line
|
|
100
101
|
return effects.attempt(fenceConstruct, lineEnd, nok)(code);
|
|
@@ -127,7 +128,7 @@ function parse(options) {
|
|
|
127
128
|
|
|
128
129
|
function closedFence(code) {
|
|
129
130
|
// check if valid yaml
|
|
130
|
-
const token = effects.exit(
|
|
131
|
+
const token = effects.exit(TYPE_YAML);
|
|
131
132
|
let yamlString = self.sliceSerialize(token).trim();
|
|
132
133
|
// remove fences
|
|
133
134
|
yamlString = yamlString.substring(4, yamlString.length - 3).trim();
|
|
@@ -9,10 +9,12 @@
|
|
|
9
9
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
+
import { TYPE_YAML } from './types.js';
|
|
13
|
+
|
|
12
14
|
export default function toMarkdown() {
|
|
13
15
|
return {
|
|
14
16
|
handlers: {
|
|
15
|
-
|
|
17
|
+
[TYPE_YAML]: (node) => `---\n${node.value.trim()}\n---`,
|
|
16
18
|
},
|
|
17
19
|
};
|
|
18
20
|
}
|