@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,91 @@
|
|
|
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
|
+
|
|
13
|
+
/**
|
|
14
|
+
* GridTables remark plugin and micromark extension.
|
|
15
|
+
*
|
|
16
|
+
* GridTables look like this:
|
|
17
|
+
*
|
|
18
|
+
* ```
|
|
19
|
+
* +-------------------+------+
|
|
20
|
+
* | Table Headings | Here |
|
|
21
|
+
* +--------+----------+------+
|
|
22
|
+
* | Sub | Headings | Too |
|
|
23
|
+
* +========+=================+
|
|
24
|
+
* | cell | column spanning |
|
|
25
|
+
* | spans +---------:+------+
|
|
26
|
+
* | rows | normal | cell |
|
|
27
|
+
* +---v----+:---------------:+
|
|
28
|
+
* | | cells can be |
|
|
29
|
+
* | | *formatted* |
|
|
30
|
+
* | | **paragraphs** |
|
|
31
|
+
* | | ``` |
|
|
32
|
+
* | multi | and contain |
|
|
33
|
+
* | line | blocks |
|
|
34
|
+
* | cells | ``` |
|
|
35
|
+
* +========+=========<+======+
|
|
36
|
+
* | footer | cells | |
|
|
37
|
+
* +--------+----------+------+
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* - the top of a cell must be indicated by `+-` followed by some `-` or `+` and finished by `-+`.
|
|
41
|
+
* - if the table contains a footer but no header, the top row should use `=` as grid line.
|
|
42
|
+
* - col spans are indicated by missing column (`|`) delimiters
|
|
43
|
+
* - row spans are indicated by missing row (`-`) delimiters
|
|
44
|
+
* - cells can be left, center, right, or justify aligned; indicated by the placement of `:` or `><`
|
|
45
|
+
* - cells can be top, middle, or bottom v-aligned;
|
|
46
|
+
* indicated by the placement of arrows (`v` `^` `x`)
|
|
47
|
+
* - the header and footer sections are delimited by section delimiters (`=`).
|
|
48
|
+
* - if no section delimiters are present, all cells are placed in the table body.
|
|
49
|
+
* - if only 1 section delimiter is present, it delimits header from body.
|
|
50
|
+
* - the content in cells can be a full Markdown document again.
|
|
51
|
+
* note, that the cell boundaries (`|`)
|
|
52
|
+
* need to exactly match with the column markers (`+`) in the row delimiters, if the cell content
|
|
53
|
+
* contains `|`, otherwise the correct layout of the table can't be guaranteed.
|
|
54
|
+
*
|
|
55
|
+
* Layout
|
|
56
|
+
* ======
|
|
57
|
+
*
|
|
58
|
+
* The table layout tries to keep the table within a certain width (default 120). For example,
|
|
59
|
+
* if the table has 3 columns, each column will be max 40 characters wide. If all text in a column
|
|
60
|
+
* is smaller, it will shrink the columns. However, cells have a minimum width (default 10) when
|
|
61
|
+
* text needs to be broken. If the cell contents need more space, e.g. with a nested table or
|
|
62
|
+
* code block, it will grow accordingly.
|
|
63
|
+
*
|
|
64
|
+
* Align
|
|
65
|
+
* =====
|
|
66
|
+
*
|
|
67
|
+
* Horizontal align is indicated by placing markers at the grid line above the cell:
|
|
68
|
+
*
|
|
69
|
+
* ```
|
|
70
|
+
* Justify Center Left Right
|
|
71
|
+
* +>-----<+ +:-----:+ +:------+ +------:+
|
|
72
|
+
* | A b C | | ABC | | ABC | | ABC |
|
|
73
|
+
* +-------+ +-------+ +-------+ +-------+
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* Vertical align is indicated by placing markers at the center of the grid line above the cell:
|
|
77
|
+
*
|
|
78
|
+
* ```
|
|
79
|
+
* Top Middle Bottom
|
|
80
|
+
* +---^---+ +---x---+ +---v---+
|
|
81
|
+
* | Larum | | | | |
|
|
82
|
+
* | Ipsum | | Larum | | |
|
|
83
|
+
* | | | Ipsum | | Larum |
|
|
84
|
+
* | | | | | Ipsum |
|
|
85
|
+
* +-------+ +-------+ +-------+
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
*/
|
|
89
|
+
export * from './types.js';
|
|
90
|
+
export { default as remarkGridTable } from './remark-plugin.js';
|
|
91
|
+
export { default as mdast2hastGridTableHandler } from './mdast2hast-handler.js';
|
|
@@ -0,0 +1,119 @@
|
|
|
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
|
+
import { all } from 'mdast-util-to-hast';
|
|
13
|
+
import { CONTINUE, SKIP, visit } from 'unist-util-visit';
|
|
14
|
+
import {
|
|
15
|
+
TYPE_BODY, TYPE_CELL, TYPE_FOOTER, TYPE_HEADER, TYPE_ROW,
|
|
16
|
+
} from './types.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @typedef GridTableHandlerOptions
|
|
20
|
+
* @property {boolean} noHeader if true, <thead> and <tbody> elements are suppressed.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Handles a row (i.e. the `gtRow` node)
|
|
25
|
+
* @return {HastNode} the 'tr' node
|
|
26
|
+
*/
|
|
27
|
+
function handleRow(h, node, cellElementName) {
|
|
28
|
+
const cells = [];
|
|
29
|
+
for (const child of node.children) {
|
|
30
|
+
if (child.type === TYPE_CELL) {
|
|
31
|
+
const props = {};
|
|
32
|
+
for (const p of ['colSpan', 'rowSpan', 'align', 'valign']) {
|
|
33
|
+
if (p in child) {
|
|
34
|
+
props[p] = child[p];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// if cell contains only 1 single paragraph, unwrap it
|
|
38
|
+
if (child.children?.length === 1 && child.children[0].type === 'paragraph') {
|
|
39
|
+
child.children = child.children[0].children;
|
|
40
|
+
}
|
|
41
|
+
const cell = h(child, cellElementName, props, all(h, child));
|
|
42
|
+
cells.push(cell);
|
|
43
|
+
|
|
44
|
+
// clean text elements
|
|
45
|
+
visit(cell, (n) => {
|
|
46
|
+
if (n.tagName === 'code') {
|
|
47
|
+
return SKIP;
|
|
48
|
+
}
|
|
49
|
+
if (n.type === 'text') {
|
|
50
|
+
// eslint-disable-next-line no-param-reassign
|
|
51
|
+
n.value = n.value.replace(/\r?\n/mg, ' ');
|
|
52
|
+
}
|
|
53
|
+
return CONTINUE;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return h(node, 'tr', cells);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Handles a group (array) of rows. eg the children of a `gtBody`.
|
|
63
|
+
* @return {HastNode[]} the array of rows
|
|
64
|
+
*/
|
|
65
|
+
function createRows(h, node, cellElementName) {
|
|
66
|
+
const rows = [];
|
|
67
|
+
for (const child of node.children) {
|
|
68
|
+
if (child.type === TYPE_ROW) {
|
|
69
|
+
rows.push(handleRow(h, child, cellElementName));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return rows;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Transforms the gridTable to a hast table
|
|
77
|
+
*
|
|
78
|
+
* @param {GridTableHandlerOptions} opts
|
|
79
|
+
* @return {function} A mdast-to-hast handler.
|
|
80
|
+
*/
|
|
81
|
+
export default function gridTableHandler(opts = {}) {
|
|
82
|
+
const { noHeader } = opts;
|
|
83
|
+
|
|
84
|
+
return function handleTable(h, node) {
|
|
85
|
+
let headerRows = [];
|
|
86
|
+
let bodyRows = [];
|
|
87
|
+
let footerRows = [];
|
|
88
|
+
|
|
89
|
+
for (const child of node.children) {
|
|
90
|
+
if (child.type === TYPE_HEADER) {
|
|
91
|
+
headerRows = createRows(h, child, 'th');
|
|
92
|
+
} else if (child.type === TYPE_BODY) {
|
|
93
|
+
bodyRows = createRows(h, child, 'td');
|
|
94
|
+
} else if (child.type === TYPE_FOOTER) {
|
|
95
|
+
footerRows = createRows(h, child, 'td');
|
|
96
|
+
} else if (child.type === TYPE_ROW) {
|
|
97
|
+
bodyRows.push(handleRow(h, child, 'td'));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let inner;
|
|
102
|
+
if (noHeader && footerRows.length === 0) {
|
|
103
|
+
inner = [...headerRows, ...bodyRows];
|
|
104
|
+
} else {
|
|
105
|
+
inner = [];
|
|
106
|
+
if (headerRows.length) {
|
|
107
|
+
inner.push(h(null, 'thead', headerRows));
|
|
108
|
+
}
|
|
109
|
+
if (bodyRows.length) {
|
|
110
|
+
inner.push(h(null, 'tbody', bodyRows));
|
|
111
|
+
}
|
|
112
|
+
if (footerRows.length) {
|
|
113
|
+
inner.push(h(null, 'tfoot', footerRows));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return h(node, 'table', inner);
|
|
118
|
+
};
|
|
119
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
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
|
+
const opts = {
|
|
29
|
+
processor: this,
|
|
30
|
+
...options,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
add('micromarkExtensions', syntax(options));
|
|
34
|
+
add('fromMarkdownExtensions', fromMarkdown(opts));
|
|
35
|
+
add('toMarkdownExtensions', toMarkdown(options));
|
|
36
|
+
}
|
|
@@ -0,0 +1,352 @@
|
|
|
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-use-before-define,no-underscore-dangle,no-param-reassign */
|
|
13
|
+
import { codes } from 'micromark-util-symbol/codes.js';
|
|
14
|
+
import { types } from 'micromark-util-symbol/types.js';
|
|
15
|
+
import {
|
|
16
|
+
markdownLineEnding,
|
|
17
|
+
markdownSpace,
|
|
18
|
+
} from 'micromark-util-character';
|
|
19
|
+
import {
|
|
20
|
+
TYPE_BODY, TYPE_CELL, TYPE_HEADER, TYPE_FOOTER, TYPE_TABLE,
|
|
21
|
+
} from './types.js';
|
|
22
|
+
|
|
23
|
+
// the cell divider: | or +
|
|
24
|
+
const TYPE_CELL_DIVIDER = 'cellDivider';
|
|
25
|
+
|
|
26
|
+
// a line within a row. can have cells or dividers or both, in case of row spans
|
|
27
|
+
const TYPE_ROW_LINE = 'rowLine';
|
|
28
|
+
|
|
29
|
+
// the grid divider: - / =
|
|
30
|
+
const TYPE_GRID_DIVIDER = 'gridDivider';
|
|
31
|
+
|
|
32
|
+
const V_ALIGN_CODES = {
|
|
33
|
+
[codes.lowercaseV]: 'bottom',
|
|
34
|
+
[codes.lowercaseX]: 'middle',
|
|
35
|
+
[codes.caret]: 'top',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function parse() {
|
|
39
|
+
return {
|
|
40
|
+
tokenize: tokenizeTable,
|
|
41
|
+
resolve: resolveTable,
|
|
42
|
+
resolveAll: resolveAllTable,
|
|
43
|
+
concrete: true,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
function tokenizeTable(effects, ok, nok) {
|
|
47
|
+
// positions of columns
|
|
48
|
+
const cols = [0];
|
|
49
|
+
let numRows = 0;
|
|
50
|
+
let numCols = 0;
|
|
51
|
+
let colPos = 0;
|
|
52
|
+
let rowLine = null;
|
|
53
|
+
let align = '';
|
|
54
|
+
let valign = '';
|
|
55
|
+
return start;
|
|
56
|
+
|
|
57
|
+
function start(code) {
|
|
58
|
+
effects.enter(TYPE_TABLE)._cols = cols;
|
|
59
|
+
effects.enter(TYPE_BODY);
|
|
60
|
+
return lineStart(code);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function lineStart(code) {
|
|
64
|
+
if (code === codes.plusSign || code === codes.verticalBar) {
|
|
65
|
+
rowLine = effects.enter(TYPE_ROW_LINE);
|
|
66
|
+
effects.enter(TYPE_CELL_DIVIDER);
|
|
67
|
+
effects.consume(code);
|
|
68
|
+
effects.exit(TYPE_CELL_DIVIDER);
|
|
69
|
+
colPos = 0;
|
|
70
|
+
numCols = 0;
|
|
71
|
+
return cellOrGridStart;
|
|
72
|
+
}
|
|
73
|
+
if (numRows < 3) {
|
|
74
|
+
return nok(code);
|
|
75
|
+
}
|
|
76
|
+
effects.exit(TYPE_BODY);
|
|
77
|
+
effects.exit(TYPE_TABLE);
|
|
78
|
+
return ok(code);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function cellOrGridStart(code) {
|
|
82
|
+
align = '';
|
|
83
|
+
valign = '';
|
|
84
|
+
if (code === codes.dash || code === codes.equalsTo
|
|
85
|
+
|| code === codes.colon || code === codes.greaterThan) {
|
|
86
|
+
effects.enter(TYPE_GRID_DIVIDER)._colStart = colPos;
|
|
87
|
+
colPos += 1;
|
|
88
|
+
if (code === codes.colon) {
|
|
89
|
+
align = 'left';
|
|
90
|
+
} else if (code === codes.greaterThan) {
|
|
91
|
+
align = 'justify';
|
|
92
|
+
}
|
|
93
|
+
effects.consume(code);
|
|
94
|
+
return gridDivider;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (code === codes.eof || markdownLineEnding(code)) {
|
|
98
|
+
return lineEnd(code);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
effects.enter(TYPE_CELL)._colStart = colPos;
|
|
102
|
+
colPos += 1;
|
|
103
|
+
effects.consume(code);
|
|
104
|
+
|
|
105
|
+
if (markdownSpace(code)) {
|
|
106
|
+
return cellSpace;
|
|
107
|
+
}
|
|
108
|
+
return cell;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function cellSpace(code) {
|
|
112
|
+
if (code === codes.eof || markdownLineEnding(code)) {
|
|
113
|
+
// mark as discarded, will be filtered out in transform
|
|
114
|
+
effects.exit(TYPE_CELL)._discard = true;
|
|
115
|
+
return lineEnd(code);
|
|
116
|
+
}
|
|
117
|
+
if (markdownSpace(code)) {
|
|
118
|
+
colPos += 1;
|
|
119
|
+
effects.consume(code);
|
|
120
|
+
return cellSpace;
|
|
121
|
+
}
|
|
122
|
+
return cell(code);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function lineEnd(code) {
|
|
126
|
+
if (numCols === 0) {
|
|
127
|
+
return nok(code);
|
|
128
|
+
}
|
|
129
|
+
if (markdownLineEnding(code)) {
|
|
130
|
+
effects.enter(types.lineEnding);
|
|
131
|
+
effects.consume(code);
|
|
132
|
+
effects.exit(types.lineEnding);
|
|
133
|
+
}
|
|
134
|
+
effects.exit(TYPE_ROW_LINE);
|
|
135
|
+
if (code === codes.eof) {
|
|
136
|
+
effects.exit(TYPE_BODY);
|
|
137
|
+
effects.exit(TYPE_TABLE);
|
|
138
|
+
return ok(code);
|
|
139
|
+
}
|
|
140
|
+
numRows += 1;
|
|
141
|
+
return lineStart;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function gridDivider(code) {
|
|
145
|
+
colPos += 1;
|
|
146
|
+
if (code === codes.dash || code === codes.equalsTo) {
|
|
147
|
+
if (!rowLine._type) {
|
|
148
|
+
rowLine._type = code;
|
|
149
|
+
}
|
|
150
|
+
effects.consume(code);
|
|
151
|
+
return gridDivider;
|
|
152
|
+
}
|
|
153
|
+
if (code === codes.colon) {
|
|
154
|
+
if (!align) {
|
|
155
|
+
align = 'right';
|
|
156
|
+
} else if (align === 'left') {
|
|
157
|
+
align = 'center';
|
|
158
|
+
} else {
|
|
159
|
+
return nok(code);
|
|
160
|
+
}
|
|
161
|
+
effects.consume(code);
|
|
162
|
+
return gridDividerEnd;
|
|
163
|
+
}
|
|
164
|
+
if (code === codes.lessThan) {
|
|
165
|
+
if (align !== 'justify') {
|
|
166
|
+
return nok(code);
|
|
167
|
+
}
|
|
168
|
+
effects.consume(code);
|
|
169
|
+
return gridDividerEnd;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (V_ALIGN_CODES[code]) {
|
|
173
|
+
if (valign) {
|
|
174
|
+
return nok(code);
|
|
175
|
+
}
|
|
176
|
+
valign = V_ALIGN_CODES[code];
|
|
177
|
+
effects.consume(code);
|
|
178
|
+
return gridDivider;
|
|
179
|
+
}
|
|
180
|
+
if (code === codes.plusSign || code === codes.verticalBar) {
|
|
181
|
+
colPos -= 1;
|
|
182
|
+
return gridDividerEnd(code);
|
|
183
|
+
}
|
|
184
|
+
return nok(code);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function gridDividerEnd(code) {
|
|
188
|
+
if (code !== codes.plusSign && code !== codes.verticalBar) {
|
|
189
|
+
return nok(code);
|
|
190
|
+
}
|
|
191
|
+
// for a super small column, assume dash
|
|
192
|
+
if (!rowLine._type) {
|
|
193
|
+
rowLine._type = code.dash;
|
|
194
|
+
}
|
|
195
|
+
colPos += 1;
|
|
196
|
+
// remember cols
|
|
197
|
+
const idx = cols.indexOf(colPos);
|
|
198
|
+
if (idx < 0) {
|
|
199
|
+
cols.push(colPos);
|
|
200
|
+
cols.sort((c0, c1) => c0 - c1);
|
|
201
|
+
}
|
|
202
|
+
const token = effects.exit(TYPE_GRID_DIVIDER);
|
|
203
|
+
token._colEnd = colPos;
|
|
204
|
+
token._align = align;
|
|
205
|
+
token._valign = valign;
|
|
206
|
+
effects.enter(TYPE_CELL_DIVIDER);
|
|
207
|
+
effects.consume(code);
|
|
208
|
+
effects.exit(TYPE_CELL_DIVIDER);
|
|
209
|
+
numCols += 1;
|
|
210
|
+
return cellOrGridStart;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function cell(code) {
|
|
214
|
+
colPos += 1;
|
|
215
|
+
// find existing col
|
|
216
|
+
if (code === codes.verticalBar || code === codes.plusSign) {
|
|
217
|
+
const idx = cols.indexOf(colPos);
|
|
218
|
+
if (idx >= 0) {
|
|
219
|
+
effects.exit(TYPE_CELL)._colEnd = colPos;
|
|
220
|
+
effects.enter(TYPE_CELL_DIVIDER);
|
|
221
|
+
effects.consume(code);
|
|
222
|
+
effects.exit(TYPE_CELL_DIVIDER);
|
|
223
|
+
numCols += 1;
|
|
224
|
+
return cellOrGridStart;
|
|
225
|
+
}
|
|
226
|
+
effects.consume(code);
|
|
227
|
+
return cell;
|
|
228
|
+
}
|
|
229
|
+
if (code === codes.eof) {
|
|
230
|
+
// row with cells never terminate eof
|
|
231
|
+
return nok(code);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
effects.consume(code);
|
|
235
|
+
return (code === codes.backslash)
|
|
236
|
+
? cellEscaped
|
|
237
|
+
: cell;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function cellEscaped(code) {
|
|
241
|
+
if (code === codes.backslash || code === codes.verticalBar || code === codes.plusSign) {
|
|
242
|
+
colPos += 1;
|
|
243
|
+
effects.consume(code);
|
|
244
|
+
return cell;
|
|
245
|
+
}
|
|
246
|
+
return cell(code);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function resolveHeaderAndFooter(events, context) {
|
|
251
|
+
// detect headers:
|
|
252
|
+
// no `=` lines -> only body
|
|
253
|
+
// 1 `=` line -> header + body
|
|
254
|
+
// 2 `=` lines -> header + body + footer
|
|
255
|
+
const fatLines = [];
|
|
256
|
+
let bodyStart = -1; // should default to 1. but just be sure
|
|
257
|
+
|
|
258
|
+
for (let idx = 0; idx < events.length; idx += 1) {
|
|
259
|
+
const [e, node] = events[idx];
|
|
260
|
+
const { type } = node;
|
|
261
|
+
if (type === TYPE_BODY) {
|
|
262
|
+
if (e === 'enter') {
|
|
263
|
+
bodyStart = idx;
|
|
264
|
+
} else {
|
|
265
|
+
// eslint-disable-next-line prefer-const
|
|
266
|
+
let [hdrIdx, ftrIdx] = fatLines;
|
|
267
|
+
const bdy = node;
|
|
268
|
+
if (hdrIdx > bodyStart + 1) {
|
|
269
|
+
// insert header above body
|
|
270
|
+
const hdr = {
|
|
271
|
+
type: TYPE_HEADER,
|
|
272
|
+
start: bdy.start,
|
|
273
|
+
end: events[hdrIdx][1].end,
|
|
274
|
+
};
|
|
275
|
+
bdy.start = hdr.end;
|
|
276
|
+
events[bodyStart][1] = hdr;
|
|
277
|
+
events.splice(
|
|
278
|
+
hdrIdx,
|
|
279
|
+
0,
|
|
280
|
+
['exit', hdr, context],
|
|
281
|
+
['enter', bdy, context],
|
|
282
|
+
);
|
|
283
|
+
idx += 2;
|
|
284
|
+
ftrIdx += 2;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (ftrIdx) {
|
|
288
|
+
// insert footer below body
|
|
289
|
+
const ftr = {
|
|
290
|
+
type: TYPE_FOOTER,
|
|
291
|
+
start: events[ftrIdx][1].start,
|
|
292
|
+
end: bdy.end,
|
|
293
|
+
};
|
|
294
|
+
bdy.end = ftr.start;
|
|
295
|
+
events.splice(
|
|
296
|
+
ftrIdx,
|
|
297
|
+
0,
|
|
298
|
+
['exit', bdy, context],
|
|
299
|
+
['enter', ftr, context],
|
|
300
|
+
);
|
|
301
|
+
idx += 2;
|
|
302
|
+
events[idx][1] = ftr;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
} else if (type === TYPE_ROW_LINE && e === 'enter' && node._type === codes.equalsTo) {
|
|
306
|
+
fatLines.push(idx);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return events;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function resolveTable(events, context) {
|
|
313
|
+
// remove discarded
|
|
314
|
+
events = events.filter(([, node]) => !node._discard);
|
|
315
|
+
|
|
316
|
+
events = resolveHeaderAndFooter(events, context);
|
|
317
|
+
// let i = 0;
|
|
318
|
+
// for (const [d, { type }] of events) {
|
|
319
|
+
// if (d === 'exit') {
|
|
320
|
+
// i -= 2;
|
|
321
|
+
// }
|
|
322
|
+
// console.log(' '.repeat(i), d, type);
|
|
323
|
+
// if (d === 'enter') {
|
|
324
|
+
// i += 2;
|
|
325
|
+
// }
|
|
326
|
+
// }
|
|
327
|
+
return events;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function resolveAllTable(events, context) {
|
|
331
|
+
// since we create a detached parser for each cell content later (in from-markdown.js)
|
|
332
|
+
// we need to remember the definitions of the overall document. otherwise the cell parsers
|
|
333
|
+
// would not detect the image and link references.
|
|
334
|
+
const { defined } = context.parser;
|
|
335
|
+
|
|
336
|
+
// find all grid tables and remember the definitions
|
|
337
|
+
for (const [evt, node] of events) {
|
|
338
|
+
if (evt === 'enter' && node.type === TYPE_TABLE) {
|
|
339
|
+
node._definitions = defined;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return events;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export default function create(options = {}) {
|
|
347
|
+
return {
|
|
348
|
+
flow: {
|
|
349
|
+
[codes.plusSign]: parse(options),
|
|
350
|
+
},
|
|
351
|
+
};
|
|
352
|
+
}
|