@orkestrel/markdown 0.0.1 → 0.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/dist/src/core/Markdown.d.ts +1 -1
- package/dist/src/core/factories.d.ts +2 -2
- package/dist/src/core/helpers.d.ts +90 -1
- package/dist/src/core/index.cjs +2056 -0
- package/dist/src/core/index.cjs.map +1 -0
- package/dist/src/core/index.d.cts +8 -0
- package/dist/src/core/index.js +209 -1051
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/core/parsers.d.ts +16 -1
- package/dist/src/core/shapers.d.ts +20 -19
- package/dist/src/core/validators.d.ts +106 -9
- package/package.json +25 -15
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { BlockNode, InlineNode, ListNode, MarkdownDocument, TableNode } from './types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Parses a run of markdown lines into a block AST, recursing into nested
|
|
4
4
|
* blockquotes, list items, and depth-capped degrade paragraphs.
|
|
@@ -6,6 +6,11 @@ import type { BlockNode, InlineNode, ListNode, MarkdownDocument, TableNode } fro
|
|
|
6
6
|
* @param lines - The markdown lines to parse.
|
|
7
7
|
* @param depth - The current recursion depth (blockquotes/lists increment it).
|
|
8
8
|
* @returns The parsed block nodes.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* parseBlocks(['# Hi'], 0) // [{ element: 'heading', level: 1, children: [...] }]
|
|
13
|
+
* ```
|
|
9
14
|
*/
|
|
10
15
|
export declare function parseBlocks(lines: readonly string[], depth: number): readonly BlockNode[];
|
|
11
16
|
/**
|
|
@@ -15,6 +20,11 @@ export declare function parseBlocks(lines: readonly string[], depth: number): re
|
|
|
15
20
|
* @param lines - The markdown lines to scan.
|
|
16
21
|
* @param start - The index of the header row.
|
|
17
22
|
* @returns The parsed table node and the index of the first line after it.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* collectTable(['| a |', '| - |'], 0) // { node: { element: 'table', ... }, next: 2 }
|
|
27
|
+
* ```
|
|
18
28
|
*/
|
|
19
29
|
export declare function collectTable(lines: readonly string[], start: number): {
|
|
20
30
|
readonly node: TableNode;
|
|
@@ -28,6 +38,11 @@ export declare function collectTable(lines: readonly string[], start: number): {
|
|
|
28
38
|
* @param start - The index of the first list item.
|
|
29
39
|
* @param depth - The current recursion depth (each item recurses at `depth + 1`).
|
|
30
40
|
* @returns The parsed list node and the index of the first line after it.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* collectList(['- item'], 0, 0) // { node: { element: 'list', ... }, next: 1 }
|
|
45
|
+
* ```
|
|
31
46
|
*/
|
|
32
47
|
export declare function collectList(lines: readonly string[], start: number, depth: number): {
|
|
33
48
|
readonly node: ListNode;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ObjectShape, LiteralShape, StringShape, OptionalShape, BooleanShape, NumberShape } from '@orkestrel/contract';
|
|
1
2
|
/**
|
|
2
3
|
* The shape of a {@link TextNode} - a plain-text leaf inline run.
|
|
3
4
|
*
|
|
@@ -10,9 +11,9 @@
|
|
|
10
11
|
* text.is({ element: 'text', value: 'hi' }) // true
|
|
11
12
|
* ```
|
|
12
13
|
*/
|
|
13
|
-
export declare const textShape:
|
|
14
|
-
element:
|
|
15
|
-
value:
|
|
14
|
+
export declare const textShape: ObjectShape<{
|
|
15
|
+
element: LiteralShape<readonly ["text"]>;
|
|
16
|
+
value: StringShape;
|
|
16
17
|
}>;
|
|
17
18
|
/**
|
|
18
19
|
* The shape of a {@link CodeSpanNode} - an inline code span (`` `code` ``).
|
|
@@ -26,9 +27,9 @@ export declare const textShape: import("@orkestrel/contract").ObjectShape<{
|
|
|
26
27
|
* codeSpan.is({ element: 'codeSpan', value: 'const x = 1' }) // true
|
|
27
28
|
* ```
|
|
28
29
|
*/
|
|
29
|
-
export declare const codeSpanShape:
|
|
30
|
-
element:
|
|
31
|
-
value:
|
|
30
|
+
export declare const codeSpanShape: ObjectShape<{
|
|
31
|
+
element: LiteralShape<readonly ["codeSpan"]>;
|
|
32
|
+
value: StringShape;
|
|
32
33
|
}>;
|
|
33
34
|
/**
|
|
34
35
|
* The shape of a {@link CodeBlockNode} - a fenced code block. `lang` is
|
|
@@ -44,10 +45,10 @@ export declare const codeSpanShape: import("@orkestrel/contract").ObjectShape<{
|
|
|
44
45
|
* codeBlock.is({ element: 'codeBlock', code: 'x', lang: 'ts' }) // true
|
|
45
46
|
* ```
|
|
46
47
|
*/
|
|
47
|
-
export declare const codeBlockShape:
|
|
48
|
-
element:
|
|
49
|
-
lang:
|
|
50
|
-
code:
|
|
48
|
+
export declare const codeBlockShape: ObjectShape<{
|
|
49
|
+
element: LiteralShape<readonly ["codeBlock"]>;
|
|
50
|
+
lang: OptionalShape<StringShape>;
|
|
51
|
+
code: StringShape;
|
|
51
52
|
}>;
|
|
52
53
|
/**
|
|
53
54
|
* The shape of a {@link ThematicBreakNode} - a horizontal rule. Carries no
|
|
@@ -62,8 +63,8 @@ export declare const codeBlockShape: import("@orkestrel/contract").ObjectShape<{
|
|
|
62
63
|
* thematicBreak.is({ element: 'thematicBreak' }) // true
|
|
63
64
|
* ```
|
|
64
65
|
*/
|
|
65
|
-
export declare const thematicBreakShape:
|
|
66
|
-
element:
|
|
66
|
+
export declare const thematicBreakShape: ObjectShape<{
|
|
67
|
+
element: LiteralShape<readonly ["thematicBreak"]>;
|
|
67
68
|
}>;
|
|
68
69
|
/**
|
|
69
70
|
* The shape of a {@link TableAlign} - the per-column GFM table alignment
|
|
@@ -80,7 +81,7 @@ export declare const thematicBreakShape: import("@orkestrel/contract").ObjectSha
|
|
|
80
81
|
* tableAlign.is('top') // false
|
|
81
82
|
* ```
|
|
82
83
|
*/
|
|
83
|
-
export declare const tableAlignShape:
|
|
84
|
+
export declare const tableAlignShape: LiteralShape<readonly ["none", "left", "right", "center"]>;
|
|
84
85
|
/**
|
|
85
86
|
* The shape of {@link ListItemParts} - the parsed parts of a single list-item
|
|
86
87
|
* line the block phase's list detector returns. Fully non-recursive (no
|
|
@@ -95,10 +96,10 @@ export declare const tableAlignShape: import("@orkestrel/contract").LiteralShape
|
|
|
95
96
|
* listItemParts.is({ ordered: false, start: 1, content: 'hi', indent: 0, marker: 2 }) // true
|
|
96
97
|
* ```
|
|
97
98
|
*/
|
|
98
|
-
export declare const listItemPartsShape:
|
|
99
|
-
ordered:
|
|
100
|
-
start:
|
|
101
|
-
content:
|
|
102
|
-
indent:
|
|
103
|
-
marker:
|
|
99
|
+
export declare const listItemPartsShape: ObjectShape<{
|
|
100
|
+
ordered: BooleanShape;
|
|
101
|
+
start: NumberShape;
|
|
102
|
+
content: StringShape;
|
|
103
|
+
indent: NumberShape;
|
|
104
|
+
marker: NumberShape;
|
|
104
105
|
}>;
|
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { Guard } from '@orkestrel/contract';
|
|
2
|
+
import { BlockNode, BlockquoteNode, CodeBlockNode, CodeSpanNode, EmphasisNode, HeadingNode, InlineNode, LinkNode, ListNode, MarkdownDocument, MarkdownNode, ParagraphNode, TableNode, TextNode, ThematicBreakNode } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Whether `character` is an inline whitespace character (space / tab / newline) - the
|
|
5
5
|
* emphasis flanking rule's space test.
|
|
6
6
|
*
|
|
7
7
|
* @param character - The character to test
|
|
8
8
|
* @returns `true` when it is inline whitespace
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* isWhitespace(' ') // true
|
|
13
|
+
* isWhitespace('a') // false
|
|
14
|
+
* ```
|
|
9
15
|
*/
|
|
10
16
|
export declare function isWhitespace(character: string): boolean;
|
|
11
17
|
/**
|
|
@@ -14,6 +20,12 @@ export declare function isWhitespace(character: string): boolean;
|
|
|
14
20
|
*
|
|
15
21
|
* @param character - The single character after a backslash
|
|
16
22
|
* @returns `true` when a backslash before it is an escape
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* isEscapable('*') // true
|
|
27
|
+
* isEscapable('a') // false
|
|
28
|
+
* ```
|
|
17
29
|
*/
|
|
18
30
|
export declare function isEscapable(character: string): boolean;
|
|
19
31
|
/**
|
|
@@ -23,6 +35,11 @@ export declare function isEscapable(character: string): boolean;
|
|
|
23
35
|
*
|
|
24
36
|
* @param line - The candidate line
|
|
25
37
|
* @returns `true` when the line is blank
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* isBlankLine(' ') // true
|
|
42
|
+
* ```
|
|
26
43
|
*/
|
|
27
44
|
export declare function isBlankLine(line: string): boolean;
|
|
28
45
|
/**
|
|
@@ -31,6 +48,11 @@ export declare function isBlankLine(line: string): boolean;
|
|
|
31
48
|
*
|
|
32
49
|
* @param line - The candidate line
|
|
33
50
|
* @returns `true` when the line begins a blockquote
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* isQuote('> quoted') // true
|
|
55
|
+
* ```
|
|
34
56
|
*/
|
|
35
57
|
export declare function isQuote(line: string): boolean;
|
|
36
58
|
/**
|
|
@@ -40,6 +62,11 @@ export declare function isQuote(line: string): boolean;
|
|
|
40
62
|
* @param line - The candidate closing line
|
|
41
63
|
* @param marker - The opening fence's marker run (from {@link extractFence})
|
|
42
64
|
* @returns `true` when `line` closes the fence
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* isFenceClose('```', '```') // true
|
|
69
|
+
* ```
|
|
43
70
|
*/
|
|
44
71
|
export declare function isFenceClose(line: string, marker: string): boolean;
|
|
45
72
|
/**
|
|
@@ -48,6 +75,12 @@ export declare function isFenceClose(line: string, marker: string): boolean;
|
|
|
48
75
|
*
|
|
49
76
|
* @param character - The single character to test, or `undefined` past the end of a line
|
|
50
77
|
* @returns `true` when it is whitespace
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* isFenceWhitespace(' ') // true
|
|
82
|
+
* isFenceWhitespace(undefined) // false
|
|
83
|
+
* ```
|
|
51
84
|
*/
|
|
52
85
|
export declare function isFenceWhitespace(character: string | undefined): boolean;
|
|
53
86
|
/**
|
|
@@ -57,6 +90,11 @@ export declare function isFenceWhitespace(character: string | undefined): boolea
|
|
|
57
90
|
*
|
|
58
91
|
* @param line - The candidate line
|
|
59
92
|
* @returns `true` when the line is a thematic break
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* isThematicBreak('---') // true
|
|
97
|
+
* ```
|
|
60
98
|
*/
|
|
61
99
|
export declare function isThematicBreak(line: string): boolean;
|
|
62
100
|
/**
|
|
@@ -67,25 +105,79 @@ export declare function isThematicBreak(line: string): boolean;
|
|
|
67
105
|
* @param header - The candidate header line
|
|
68
106
|
* @param delimiter - The line after it (the candidate delimiter)
|
|
69
107
|
* @returns `true` when the two lines open a table
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* isTableStart('| a |', '| - |') // true
|
|
112
|
+
* ```
|
|
70
113
|
*/
|
|
71
114
|
export declare function isTableStart(header: string, delimiter: string | undefined): boolean;
|
|
72
115
|
/** Determine whether a node is a heading block. */
|
|
73
116
|
export declare function isHeadingNode(node: MarkdownNode): node is HeadingNode;
|
|
74
|
-
/**
|
|
117
|
+
/**
|
|
118
|
+
* Determine whether a node is a paragraph block.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* isParagraphNode({ element: 'paragraph', children: [] }) // true
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
75
125
|
export declare function isParagraphNode(node: MarkdownNode): node is ParagraphNode;
|
|
76
|
-
/**
|
|
126
|
+
/**
|
|
127
|
+
* Determine whether a node is a list block.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* isListNode({ element: 'list', ordered: false, start: 1, items: [] }) // true
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
77
134
|
export declare function isListNode(node: MarkdownNode): node is ListNode;
|
|
78
135
|
/** Determine whether a node is a GFM table block. */
|
|
79
136
|
export declare function isTableNode(node: MarkdownNode): node is TableNode;
|
|
80
|
-
/**
|
|
137
|
+
/**
|
|
138
|
+
* Determine whether a node is a fenced code block.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* isCodeBlockNode({ element: 'codeBlock', code: 'x' }) // true
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
81
145
|
export declare function isCodeBlockNode(node: MarkdownNode): node is CodeBlockNode;
|
|
82
|
-
/**
|
|
146
|
+
/**
|
|
147
|
+
* Determine whether a node is a blockquote block.
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```ts
|
|
151
|
+
* isBlockquoteNode({ element: 'blockquote', children: [] }) // true
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
83
154
|
export declare function isBlockquoteNode(node: MarkdownNode): node is BlockquoteNode;
|
|
84
|
-
/**
|
|
155
|
+
/**
|
|
156
|
+
* Determine whether a node is a thematic break (horizontal rule) block.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```ts
|
|
160
|
+
* isThematicBreakNode({ element: 'thematicBreak' }) // true
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
85
163
|
export declare function isThematicBreakNode(node: MarkdownNode): node is ThematicBreakNode;
|
|
86
|
-
/**
|
|
164
|
+
/**
|
|
165
|
+
* Determine whether a node is a plain text run.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```ts
|
|
169
|
+
* isTextNode({ element: 'text', value: 'hi' }) // true
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
87
172
|
export declare function isTextNode(node: MarkdownNode): node is TextNode;
|
|
88
|
-
/**
|
|
173
|
+
/**
|
|
174
|
+
* Determine whether a node is an emphasis run (`*em*` / `**strong**`).
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```ts
|
|
178
|
+
* isEmphasisNode({ element: 'emphasis', strong: false, children: [] }) // true
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
89
181
|
export declare function isEmphasisNode(node: MarkdownNode): node is EmphasisNode;
|
|
90
182
|
/**
|
|
91
183
|
* Determine whether a node is an inline code span.
|
|
@@ -93,6 +185,11 @@ export declare function isEmphasisNode(node: MarkdownNode): node is EmphasisNode
|
|
|
93
185
|
* @remarks
|
|
94
186
|
* Narrows to {@link CodeSpanNode} - the node whose `element` discriminant is
|
|
95
187
|
* `'codeSpan'`.
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```ts
|
|
191
|
+
* isCodeSpanNode({ element: 'codeSpan', value: 'x' }) // true
|
|
192
|
+
* ```
|
|
96
193
|
*/
|
|
97
194
|
export declare function isCodeSpanNode(node: MarkdownNode): node is CodeSpanNode;
|
|
98
195
|
/** Determine whether a node is a link. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orkestrel/markdown",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Markdown parser toolkit — a fast, zero-surprise CommonMark-style parser with GFM tables, a typed AST, contract-backed node guards, and safe HTML rendering. Part of the @orkestrel line.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ast",
|
|
@@ -25,13 +25,19 @@
|
|
|
25
25
|
],
|
|
26
26
|
"type": "module",
|
|
27
27
|
"sideEffects": false,
|
|
28
|
-
"main": "./dist/src/core/index.
|
|
28
|
+
"main": "./dist/src/core/index.cjs",
|
|
29
|
+
"module": "./dist/src/core/index.js",
|
|
29
30
|
"types": "./dist/src/core/index.d.ts",
|
|
30
31
|
"exports": {
|
|
31
32
|
".": {
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
"import": {
|
|
34
|
+
"types": "./dist/src/core/index.d.ts",
|
|
35
|
+
"default": "./dist/src/core/index.js"
|
|
36
|
+
},
|
|
37
|
+
"require": {
|
|
38
|
+
"types": "./dist/src/core/index.d.cts",
|
|
39
|
+
"default": "./dist/src/core/index.cjs"
|
|
40
|
+
}
|
|
35
41
|
},
|
|
36
42
|
"./package.json": "./package.json"
|
|
37
43
|
},
|
|
@@ -43,31 +49,35 @@
|
|
|
43
49
|
"copy": "node -e \"const fs=require('node:fs'),p=require('node:path'),a=process.argv[1],b=process.argv[2];fs.mkdirSync(p.dirname(b),{recursive:true});fs.cpSync(a,b,{force:true});console.log('Copied: '+a+' to '+b)\"",
|
|
44
50
|
"tmp:txt": "node -e \"const fs=require('node:fs'),p=require('node:path');function walk(d){for(const e of fs.readdirSync(d,{withFileTypes:true})){const f=p.join(d,e.name);if(e.isDirectory()){walk(f)}else if(!e.name.endsWith('.md')&&!e.name.endsWith('.txt')){const t=f+'.txt';if(!fs.existsSync(t)){fs.renameSync(f,t)}else{console.warn('Skipping '+f+' — target exists: '+t)}}}}try{walk('tmp')}catch(e){if(e.code!=='ENOENT')throw e}\"",
|
|
45
51
|
"lint": "oxlint --config .oxlintrc.json --fix .",
|
|
46
|
-
"check": "tsc --noEmit --project tsconfig.json",
|
|
52
|
+
"check": "tsc --noEmit --project tsconfig.json && npm run check:src",
|
|
47
53
|
"check:src": "npm run check:src:core",
|
|
48
54
|
"check:src:core": "tsc --noEmit -p configs/src/tsconfig.core.json",
|
|
49
55
|
"format": "oxfmt --config .oxfmtrc.json --write .",
|
|
50
56
|
"format:check": "oxfmt --config .oxfmtrc.json --check .",
|
|
51
57
|
"lint:check": "oxlint --config .oxlintrc.json .",
|
|
52
|
-
"test": "npm run test:src",
|
|
53
|
-
"test:src": "vitest run --config vite.config.ts --reporter=dot --project src:core",
|
|
58
|
+
"test": "npm run test:src && npm run test:guides",
|
|
59
|
+
"test:src": "vitest run --config vite.config.ts --no-cache --reporter=dot --project src:core",
|
|
60
|
+
"test:src:core": "vitest run --config vite.config.ts --no-cache --reporter=dot --project src:core",
|
|
61
|
+
"test:guides": "vitest run --config vite.config.ts --reporter=dot --project guides",
|
|
54
62
|
"build": "npm run clean && npm run build:src",
|
|
55
63
|
"build:src": "npm run build:src:core",
|
|
56
|
-
"build:src:core": "vite build --config configs/src/vite.core.config.ts &&
|
|
57
|
-
"prepublishOnly": "npm run format:check && npm run lint:check && npm run check && npm run
|
|
64
|
+
"build:src:core": "vite build --config configs/src/vite.core.config.ts && npm run copy dist/src/core/index.d.ts dist/src/core/index.d.cts",
|
|
65
|
+
"prepublishOnly": "npm run format:check && npm run lint:check && npm run check && npm run build && npm test"
|
|
58
66
|
},
|
|
59
67
|
"dependencies": {
|
|
60
|
-
"@orkestrel/contract": "^0.0.
|
|
68
|
+
"@orkestrel/contract": "^0.0.2"
|
|
61
69
|
},
|
|
62
70
|
"devDependencies": {
|
|
71
|
+
"@orkestrel/guide": "^0.0.1",
|
|
63
72
|
"@types/node": "^26.1.1",
|
|
64
|
-
"oxfmt": "^0.
|
|
65
|
-
"oxlint": "^1.
|
|
73
|
+
"oxfmt": "^0.59.0",
|
|
74
|
+
"oxlint": "^1.74.0",
|
|
66
75
|
"typescript": "^6.0.3",
|
|
67
|
-
"vite": "^8.1.
|
|
76
|
+
"vite": "^8.1.5",
|
|
77
|
+
"vite-plugin-dts": "^5.0.3",
|
|
68
78
|
"vitest": "^4.1.10"
|
|
69
79
|
},
|
|
70
80
|
"engines": {
|
|
71
|
-
"node": ">=
|
|
81
|
+
"node": ">=22"
|
|
72
82
|
}
|
|
73
83
|
}
|