@jianwen-lang/parser 0.1.1 → 0.1.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/README.md +16 -1
- package/dist/core/block/rules/attribute-line.d.ts +13 -0
- package/dist/core/block/rules/attribute-line.js +227 -0
- package/dist/core/block/rules/code-block.d.ts +2 -0
- package/dist/core/block/rules/code-block.js +73 -0
- package/dist/core/block/rules/code-fence.d.ts +15 -0
- package/dist/core/block/rules/code-fence.js +37 -0
- package/dist/core/block/rules/content-title.d.ts +12 -0
- package/dist/core/block/rules/content-title.js +70 -0
- package/dist/core/block/rules/footnotes.d.ts +9 -0
- package/dist/core/block/rules/footnotes.js +105 -0
- package/dist/core/block/rules/html.d.ts +7 -0
- package/dist/core/block/rules/html.js +48 -0
- package/dist/core/block/rules/image.d.ts +9 -0
- package/dist/core/block/rules/image.js +78 -0
- package/dist/core/block/rules/list.d.ts +3 -0
- package/dist/core/block/rules/list.js +275 -0
- package/dist/core/block/rules/paragraph.d.ts +6 -0
- package/dist/core/block/rules/paragraph.js +55 -0
- package/dist/core/block/rules/quote.d.ts +13 -0
- package/dist/core/block/rules/quote.js +104 -0
- package/dist/core/block/rules/table.d.ts +2 -0
- package/dist/core/block/rules/table.js +199 -0
- package/dist/core/block/runtime.d.ts +25 -0
- package/dist/core/block/runtime.js +116 -0
- package/dist/core/block-parser.js +183 -1322
- package/dist/html/convert.d.ts +8 -0
- package/dist/html/convert.js +22 -0
- package/dist/html/render/blocks.d.ts +15 -0
- package/dist/html/render/blocks.js +50 -6
- package/dist/html/render/html.d.ts +16 -0
- package/dist/html/render/html.js +48 -14
- package/dist/html/render/utils.d.ts +1 -0
- package/package.json +5 -1
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tryParseTableBlock = tryParseTableBlock;
|
|
4
|
+
const diagnostics_1 = require("../../diagnostics");
|
|
5
|
+
const location_1 = require("../../location");
|
|
6
|
+
const lexer_1 = require("../../../lexer/lexer");
|
|
7
|
+
const attribute_line_1 = require("./attribute-line");
|
|
8
|
+
function tryParseTableBlock(ctx) {
|
|
9
|
+
if (!ctx.pending.isSheet || !isTableRow(ctx.lineInfo.content)) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const rawLines = [ctx.lineInfo.raw];
|
|
13
|
+
const rowContents = [
|
|
14
|
+
{ text: ctx.lineInfo.content, raw: ctx.lineInfo.raw, line: ctx.index + 1 },
|
|
15
|
+
];
|
|
16
|
+
let jTable = ctx.index + 1;
|
|
17
|
+
while (jTable < ctx.lines.length) {
|
|
18
|
+
const nextRaw = ctx.lines[jTable];
|
|
19
|
+
if (nextRaw === undefined) {
|
|
20
|
+
jTable += 1;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const nextInfo = (0, lexer_1.getLineInfo)(nextRaw);
|
|
24
|
+
const nextTrimmed = nextInfo.content.trim();
|
|
25
|
+
if (nextTrimmed.length === 0) {
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
if ((0, attribute_line_1.isAttributeOnlyLine)(nextTrimmed)) {
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
if (!isTableRow(nextInfo.content)) {
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
rawLines.push(nextInfo.raw);
|
|
35
|
+
rowContents.push({ text: nextInfo.content, raw: nextInfo.raw, line: jTable + 1 });
|
|
36
|
+
jTable += 1;
|
|
37
|
+
}
|
|
38
|
+
const { rows, align } = parseTableRows(rowContents, ctx.errors);
|
|
39
|
+
const blockAttrs = ctx.buildBlockAttrs(ctx.lineInfo.tabCount);
|
|
40
|
+
let tableAlign = align;
|
|
41
|
+
if (!tableAlign && blockAttrs?.align && blockAttrs.align !== 'left') {
|
|
42
|
+
const columnCount = getMaxTableColumnCount(rows);
|
|
43
|
+
if (columnCount > 0) {
|
|
44
|
+
tableAlign = Array.from({ length: columnCount }, () => blockAttrs.align);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
let block;
|
|
48
|
+
if (ctx.pending.isDisabled) {
|
|
49
|
+
const disabled = {
|
|
50
|
+
type: 'disabledBlock',
|
|
51
|
+
raw: rawLines.join('\n'),
|
|
52
|
+
blockAttrs,
|
|
53
|
+
};
|
|
54
|
+
(0, location_1.setNodeLocation)(disabled, ctx.lineLocation);
|
|
55
|
+
block = disabled;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
const tableBlock = {
|
|
59
|
+
type: 'table',
|
|
60
|
+
rows,
|
|
61
|
+
align: tableAlign,
|
|
62
|
+
blockAttrs,
|
|
63
|
+
};
|
|
64
|
+
(0, location_1.setNodeLocation)(tableBlock, ctx.lineLocation);
|
|
65
|
+
block = tableBlock;
|
|
66
|
+
}
|
|
67
|
+
ctx.commitBlock(block, blockAttrs);
|
|
68
|
+
return jTable;
|
|
69
|
+
}
|
|
70
|
+
function isTableRow(content) {
|
|
71
|
+
const trimmed = content.trim();
|
|
72
|
+
if (!trimmed.startsWith('|')) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
return trimmed.indexOf('|', 1) !== -1;
|
|
76
|
+
}
|
|
77
|
+
function parseTableRows(lines, errors) {
|
|
78
|
+
if (lines.length === 0) {
|
|
79
|
+
return { rows: [], align: undefined };
|
|
80
|
+
}
|
|
81
|
+
for (const line of lines) {
|
|
82
|
+
const trimmed = line.text.trim();
|
|
83
|
+
if (isTableRow(trimmed) && !trimmed.endsWith('|')) {
|
|
84
|
+
const contentStart = line.raw.length - line.text.length;
|
|
85
|
+
const trimmedContent = line.text.replace(/\s+$/, '');
|
|
86
|
+
const column = contentStart + trimmedContent.length + 1;
|
|
87
|
+
(0, diagnostics_1.reportParseError)(errors, {
|
|
88
|
+
message: 'Table row is missing closing "|" border',
|
|
89
|
+
line: line.line,
|
|
90
|
+
column,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const remaining = [...lines];
|
|
95
|
+
let align;
|
|
96
|
+
const firstLine = remaining[0];
|
|
97
|
+
if (firstLine !== undefined) {
|
|
98
|
+
const firstTrimmed = firstLine.text.trim();
|
|
99
|
+
if (isAlignmentRow(firstTrimmed)) {
|
|
100
|
+
align = parseAlignmentLine(firstTrimmed);
|
|
101
|
+
remaining.shift();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (align === undefined && remaining.length >= 2) {
|
|
105
|
+
const secondLine = remaining[1];
|
|
106
|
+
if (secondLine !== undefined) {
|
|
107
|
+
const secondTrimmed = secondLine.text.trim();
|
|
108
|
+
if (isAlignmentRow(secondTrimmed)) {
|
|
109
|
+
align = parseAlignmentLine(secondTrimmed);
|
|
110
|
+
remaining.splice(1, 1);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const rows = [];
|
|
115
|
+
for (const line of remaining) {
|
|
116
|
+
const trimmed = line.text.trim();
|
|
117
|
+
if (!isTableRow(trimmed)) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const rawCells = trimmed.split('|').slice(1, -1);
|
|
121
|
+
const cells = [];
|
|
122
|
+
for (let ci = 0; ci < rawCells.length; ci += 1) {
|
|
123
|
+
const rawCell = rawCells[ci];
|
|
124
|
+
if (rawCell === undefined) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
let cellText = rawCell.trim();
|
|
128
|
+
let cellAlign;
|
|
129
|
+
if (cellText.startsWith('[r]')) {
|
|
130
|
+
cellAlign = 'right';
|
|
131
|
+
cellText = cellText.slice(3).trim();
|
|
132
|
+
}
|
|
133
|
+
else if (cellText.startsWith('[c]')) {
|
|
134
|
+
cellAlign = 'center';
|
|
135
|
+
cellText = cellText.slice(3).trim();
|
|
136
|
+
}
|
|
137
|
+
else if (align && ci < align.length) {
|
|
138
|
+
cellAlign = align[ci];
|
|
139
|
+
}
|
|
140
|
+
const cell = {
|
|
141
|
+
type: 'tableCell',
|
|
142
|
+
children: cellText.length > 0 ? [{ type: 'text', value: cellText }] : [],
|
|
143
|
+
align: cellAlign,
|
|
144
|
+
};
|
|
145
|
+
(0, location_1.setNodeLocation)(cell, { line: line.line, column: 1 });
|
|
146
|
+
cells.push(cell);
|
|
147
|
+
}
|
|
148
|
+
const row = {
|
|
149
|
+
type: 'tableRow',
|
|
150
|
+
cells,
|
|
151
|
+
};
|
|
152
|
+
rows.push(row);
|
|
153
|
+
}
|
|
154
|
+
return { rows, align };
|
|
155
|
+
}
|
|
156
|
+
function isAlignmentRow(trimmed) {
|
|
157
|
+
if (!isTableRow(trimmed)) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
const segments = trimmed.split('|').slice(1, -1);
|
|
161
|
+
if (segments.length === 0) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
for (const seg of segments) {
|
|
165
|
+
const t = seg.trim();
|
|
166
|
+
if (!/^:?-+:?$/.test(t)) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
function parseAlignmentLine(trimmed) {
|
|
173
|
+
const segments = trimmed.split('|').slice(1, -1);
|
|
174
|
+
const result = [];
|
|
175
|
+
for (const seg of segments) {
|
|
176
|
+
const t = seg.trim();
|
|
177
|
+
const left = t.startsWith(':');
|
|
178
|
+
const right = t.endsWith(':');
|
|
179
|
+
if (left && right) {
|
|
180
|
+
result.push('center');
|
|
181
|
+
}
|
|
182
|
+
else if (right) {
|
|
183
|
+
result.push('right');
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
result.push('left');
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
function getMaxTableColumnCount(rows) {
|
|
192
|
+
let max = 0;
|
|
193
|
+
for (const row of rows) {
|
|
194
|
+
if (row.cells.length > max) {
|
|
195
|
+
max = row.cells.length;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return max;
|
|
199
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BlockAttributes, BlockNode } from '../ast';
|
|
2
|
+
import { SourceLocation } from '../location';
|
|
3
|
+
import { CommitBlockOptions } from './rules/types';
|
|
4
|
+
import { PendingBlockContext } from './types';
|
|
5
|
+
interface LineInfoLike {
|
|
6
|
+
tabCount: number;
|
|
7
|
+
}
|
|
8
|
+
export interface BlockParseRuntime {
|
|
9
|
+
pending: PendingBlockContext;
|
|
10
|
+
lastBlockPosition: BlockAttributes['position'];
|
|
11
|
+
}
|
|
12
|
+
interface CommitParsedBlockParams {
|
|
13
|
+
runtime: BlockParseRuntime;
|
|
14
|
+
blocks: BlockNode[];
|
|
15
|
+
block: BlockNode;
|
|
16
|
+
blockAttrs: BlockAttributes | undefined;
|
|
17
|
+
lineInfo: LineInfoLike;
|
|
18
|
+
lineLocation: SourceLocation;
|
|
19
|
+
options?: CommitBlockOptions;
|
|
20
|
+
}
|
|
21
|
+
export declare function createBlockParseRuntime(): BlockParseRuntime;
|
|
22
|
+
export declare function buildBlockAttrs(runtime: BlockParseRuntime, tabCount: number): BlockAttributes | undefined;
|
|
23
|
+
export declare function resetPending(pending: PendingBlockContext): void;
|
|
24
|
+
export declare function commitParsedBlock(params: CommitParsedBlockParams): void;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createBlockParseRuntime = createBlockParseRuntime;
|
|
4
|
+
exports.buildBlockAttrs = buildBlockAttrs;
|
|
5
|
+
exports.resetPending = resetPending;
|
|
6
|
+
exports.commitParsedBlock = commitParsedBlock;
|
|
7
|
+
const location_1 = require("../location");
|
|
8
|
+
function createBlockParseRuntime() {
|
|
9
|
+
return {
|
|
10
|
+
pending: {
|
|
11
|
+
attrs: undefined,
|
|
12
|
+
foldNext: false,
|
|
13
|
+
tagName: undefined,
|
|
14
|
+
isComment: false,
|
|
15
|
+
isDisabled: false,
|
|
16
|
+
isSheet: false,
|
|
17
|
+
isHtml: false,
|
|
18
|
+
},
|
|
19
|
+
lastBlockPosition: 'L',
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function buildBlockAttrs(runtime, tabCount) {
|
|
23
|
+
const baseAttrs = runtime.pending.attrs ? { ...runtime.pending.attrs } : undefined;
|
|
24
|
+
const positionFromTabs = mapTabsToPosition(tabCount);
|
|
25
|
+
let blockAttrs = baseAttrs;
|
|
26
|
+
if (positionFromTabs) {
|
|
27
|
+
if (!blockAttrs) {
|
|
28
|
+
blockAttrs = {};
|
|
29
|
+
}
|
|
30
|
+
if (!blockAttrs.position) {
|
|
31
|
+
blockAttrs.position = positionFromTabs;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (runtime.pending.foldNext) {
|
|
35
|
+
if (!blockAttrs) {
|
|
36
|
+
blockAttrs = {};
|
|
37
|
+
}
|
|
38
|
+
blockAttrs.fold = true;
|
|
39
|
+
}
|
|
40
|
+
return blockAttrs;
|
|
41
|
+
}
|
|
42
|
+
function resetPending(pending) {
|
|
43
|
+
pending.attrs = undefined;
|
|
44
|
+
pending.foldNext = false;
|
|
45
|
+
pending.tagName = undefined;
|
|
46
|
+
pending.isComment = false;
|
|
47
|
+
pending.isDisabled = false;
|
|
48
|
+
pending.isSheet = false;
|
|
49
|
+
pending.isHtml = false;
|
|
50
|
+
}
|
|
51
|
+
function commitParsedBlock(params) {
|
|
52
|
+
const { runtime, blocks, block, blockAttrs, lineInfo, lineLocation, options } = params;
|
|
53
|
+
const allowTag = options?.allowTag !== false;
|
|
54
|
+
const taggedOrOriginal = allowTag
|
|
55
|
+
? wrapTaggedIfNeeded(block, runtime.pending, blockAttrs, lineLocation)
|
|
56
|
+
: block;
|
|
57
|
+
const finalBlock = wrapCommentIfNeeded(taggedOrOriginal, runtime.pending, lineLocation);
|
|
58
|
+
blocks.push(finalBlock);
|
|
59
|
+
runtime.lastBlockPosition = resolveNextPosition(getBlockAttributes(finalBlock), lineInfo.tabCount, runtime.lastBlockPosition);
|
|
60
|
+
resetPending(runtime.pending);
|
|
61
|
+
options?.postResetPending?.(runtime.pending);
|
|
62
|
+
}
|
|
63
|
+
function wrapTaggedIfNeeded(block, pending, blockAttrs, lineLocation) {
|
|
64
|
+
if (!pending.tagName) {
|
|
65
|
+
return block;
|
|
66
|
+
}
|
|
67
|
+
const tagged = {
|
|
68
|
+
type: 'taggedBlock',
|
|
69
|
+
name: pending.tagName,
|
|
70
|
+
child: block,
|
|
71
|
+
blockAttrs,
|
|
72
|
+
};
|
|
73
|
+
(0, location_1.setNodeLocation)(tagged, lineLocation);
|
|
74
|
+
return tagged;
|
|
75
|
+
}
|
|
76
|
+
function wrapCommentIfNeeded(block, pending, lineLocation) {
|
|
77
|
+
if (!pending.isComment) {
|
|
78
|
+
return block;
|
|
79
|
+
}
|
|
80
|
+
const comment = {
|
|
81
|
+
type: 'commentBlock',
|
|
82
|
+
children: [block],
|
|
83
|
+
blockAttrs: undefined,
|
|
84
|
+
};
|
|
85
|
+
(0, location_1.setNodeLocation)(comment, lineLocation);
|
|
86
|
+
return comment;
|
|
87
|
+
}
|
|
88
|
+
function getBlockAttributes(block) {
|
|
89
|
+
if ('blockAttrs' in block) {
|
|
90
|
+
const candidate = block.blockAttrs;
|
|
91
|
+
return candidate;
|
|
92
|
+
}
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
function resolveNextPosition(attrs, tabCount, fallback) {
|
|
96
|
+
if (attrs?.position) {
|
|
97
|
+
return attrs.position;
|
|
98
|
+
}
|
|
99
|
+
const tabPosition = mapTabsToPosition(tabCount);
|
|
100
|
+
if (tabPosition) {
|
|
101
|
+
return tabPosition;
|
|
102
|
+
}
|
|
103
|
+
return fallback;
|
|
104
|
+
}
|
|
105
|
+
function mapTabsToPosition(tabCount) {
|
|
106
|
+
if (tabCount === 0) {
|
|
107
|
+
return 'L';
|
|
108
|
+
}
|
|
109
|
+
if (tabCount === 1) {
|
|
110
|
+
return 'C';
|
|
111
|
+
}
|
|
112
|
+
if (tabCount >= 2) {
|
|
113
|
+
return 'R';
|
|
114
|
+
}
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|