@fuzdev/fuz_ui 0.204.0 → 0.205.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/dist/ApiModule.svelte +14 -1
- package/dist/ApiModule.svelte.d.ts.map +1 -1
- package/dist/DeclarationDetail.svelte +15 -4
- package/dist/DeclarationDetail.svelte.d.ts.map +1 -1
- package/package.json +12 -36
- package/dist/Mdz.svelte +0 -34
- package/dist/Mdz.svelte.d.ts +0 -11
- package/dist/Mdz.svelte.d.ts.map +0 -1
- package/dist/MdzNodeView.svelte +0 -107
- package/dist/MdzNodeView.svelte.d.ts +0 -9
- package/dist/MdzNodeView.svelte.d.ts.map +0 -1
- package/dist/MdzPrecompiled.svelte +0 -30
- package/dist/MdzPrecompiled.svelte.d.ts +0 -11
- package/dist/MdzPrecompiled.svelte.d.ts.map +0 -1
- package/dist/MdzRoot.svelte +0 -30
- package/dist/MdzRoot.svelte.d.ts +0 -12
- package/dist/MdzRoot.svelte.d.ts.map +0 -1
- package/dist/MdzStream.svelte +0 -32
- package/dist/MdzStream.svelte.d.ts +0 -12
- package/dist/MdzStream.svelte.d.ts.map +0 -1
- package/dist/MdzStreamNodeView.svelte +0 -106
- package/dist/MdzStreamNodeView.svelte.d.ts +0 -9
- package/dist/MdzStreamNodeView.svelte.d.ts.map +0 -1
- package/dist/mdz.d.ts +0 -112
- package/dist/mdz.d.ts.map +0 -1
- package/dist/mdz.js +0 -1186
- package/dist/mdz_components.d.ts +0 -63
- package/dist/mdz_components.d.ts.map +0 -1
- package/dist/mdz_components.js +0 -32
- package/dist/mdz_helpers.d.ts +0 -164
- package/dist/mdz_helpers.d.ts.map +0 -1
- package/dist/mdz_helpers.js +0 -424
- package/dist/mdz_lexer.d.ts +0 -93
- package/dist/mdz_lexer.d.ts.map +0 -1
- package/dist/mdz_lexer.js +0 -732
- package/dist/mdz_opcodes.d.ts +0 -174
- package/dist/mdz_opcodes.d.ts.map +0 -1
- package/dist/mdz_opcodes.js +0 -14
- package/dist/mdz_opcodes_to_nodes.d.ts +0 -20
- package/dist/mdz_opcodes_to_nodes.d.ts.map +0 -1
- package/dist/mdz_opcodes_to_nodes.js +0 -332
- package/dist/mdz_stream_parser.d.ts +0 -80
- package/dist/mdz_stream_parser.d.ts.map +0 -1
- package/dist/mdz_stream_parser.js +0 -354
- package/dist/mdz_stream_parser_block.d.ts +0 -76
- package/dist/mdz_stream_parser_block.d.ts.map +0 -1
- package/dist/mdz_stream_parser_block.js +0 -458
- package/dist/mdz_stream_parser_inline.d.ts +0 -52
- package/dist/mdz_stream_parser_inline.d.ts.map +0 -1
- package/dist/mdz_stream_parser_inline.js +0 -378
- package/dist/mdz_stream_parser_link.d.ts +0 -22
- package/dist/mdz_stream_parser_link.d.ts.map +0 -1
- package/dist/mdz_stream_parser_link.js +0 -215
- package/dist/mdz_stream_parser_state.d.ts +0 -187
- package/dist/mdz_stream_parser_state.d.ts.map +0 -1
- package/dist/mdz_stream_parser_state.js +0 -398
- package/dist/mdz_stream_parser_text.d.ts +0 -14
- package/dist/mdz_stream_parser_text.d.ts.map +0 -1
- package/dist/mdz_stream_parser_text.js +0 -50
- package/dist/mdz_stream_parser_url.d.ts +0 -60
- package/dist/mdz_stream_parser_url.d.ts.map +0 -1
- package/dist/mdz_stream_parser_url.js +0 -307
- package/dist/mdz_stream_state.svelte.d.ts +0 -44
- package/dist/mdz_stream_state.svelte.d.ts.map +0 -1
- package/dist/mdz_stream_state.svelte.js +0 -357
- package/dist/mdz_to_svelte.d.ts +0 -41
- package/dist/mdz_to_svelte.d.ts.map +0 -1
- package/dist/mdz_to_svelte.js +0 -100
- package/dist/mdz_token_parser.d.ts +0 -14
- package/dist/mdz_token_parser.d.ts.map +0 -1
- package/dist/mdz_token_parser.js +0 -344
- package/dist/svelte_preprocess_mdz.d.ts +0 -65
- package/dist/svelte_preprocess_mdz.d.ts.map +0 -1
- package/dist/svelte_preprocess_mdz.js +0 -529
- package/dist/tsdoc_mdz.d.ts +0 -45
- package/dist/tsdoc_mdz.d.ts.map +0 -1
- package/dist/tsdoc_mdz.js +0 -88
- package/src/lib/mdz.ts +0 -1532
- package/src/lib/mdz_components.ts +0 -64
- package/src/lib/mdz_helpers.ts +0 -449
- package/src/lib/mdz_lexer.ts +0 -1012
- package/src/lib/mdz_opcodes.ts +0 -205
- package/src/lib/mdz_opcodes_to_nodes.ts +0 -375
- package/src/lib/mdz_stream_parser.ts +0 -415
- package/src/lib/mdz_stream_parser_block.ts +0 -532
- package/src/lib/mdz_stream_parser_inline.ts +0 -414
- package/src/lib/mdz_stream_parser_link.ts +0 -271
- package/src/lib/mdz_stream_parser_state.ts +0 -539
- package/src/lib/mdz_stream_parser_text.ts +0 -77
- package/src/lib/mdz_stream_parser_url.ts +0 -365
- package/src/lib/mdz_stream_state.svelte.ts +0 -387
- package/src/lib/mdz_to_svelte.ts +0 -141
- package/src/lib/mdz_token_parser.ts +0 -434
- package/src/lib/svelte_preprocess_mdz.ts +0 -742
- package/src/lib/tsdoc_mdz.ts +0 -97
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Streaming parser state and low-level operations.
|
|
3
|
-
*
|
|
4
|
-
* Free functions take a `MdzStreamParserState` first parameter so handlers can
|
|
5
|
-
* live in separate sibling modules — JS private (`#`) fields can't cross
|
|
6
|
-
* module boundaries.
|
|
7
|
-
*
|
|
8
|
-
* @module
|
|
9
|
-
*/
|
|
10
|
-
import type { MdzContainerNodeType, MdzNodeId, MdzOpcode } from './mdz_opcodes.js';
|
|
11
|
-
/**
|
|
12
|
-
* Tri-state result for `try_*` parser handlers.
|
|
13
|
-
* - `'consumed'`: input matched and the parser advanced
|
|
14
|
-
* - `'need_more'`: input is potentially valid but more bytes are required to decide
|
|
15
|
-
* - `'not_match'`: input definitely doesn't match — caller falls through to the next handler
|
|
16
|
-
*/
|
|
17
|
-
export type TryResult = 'consumed' | 'need_more' | 'not_match';
|
|
18
|
-
export interface StackEntry {
|
|
19
|
-
id: MdzNodeId;
|
|
20
|
-
node_type: MdzContainerNodeType;
|
|
21
|
-
/** Whether this was opened speculatively (will be reverted if not closed). */
|
|
22
|
-
optimistic: boolean;
|
|
23
|
-
/** The opening delimiter text, used as `replacement_text` on revert. */
|
|
24
|
-
delimiter: string;
|
|
25
|
-
/** Tag name for Element/Component entries, `undefined` for all others. */
|
|
26
|
-
tag_name: string | undefined;
|
|
27
|
-
/** Whether any child content has been emitted inside this container. */
|
|
28
|
-
has_children: boolean;
|
|
29
|
-
/**
|
|
30
|
-
* Whether any non-whitespace text or non-text child has been emitted
|
|
31
|
-
* inside this container. Only tracked for `Paragraph` entries to detect
|
|
32
|
-
* whitespace-only paragraphs that should be dropped at close.
|
|
33
|
-
*/
|
|
34
|
-
has_non_whitespace_content: boolean;
|
|
35
|
-
/** Global byte offset of the opening delimiter. */
|
|
36
|
-
start: number;
|
|
37
|
-
}
|
|
38
|
-
export interface CodeblockState {
|
|
39
|
-
id: MdzNodeId;
|
|
40
|
-
backtick_count: number;
|
|
41
|
-
text_id: MdzNodeId | null;
|
|
42
|
-
/** The full opening fence line (e.g. "```ts\n"), used as `replacement_text` on revert. */
|
|
43
|
-
delimiter: string;
|
|
44
|
-
/** Global byte offset of the opening fence. */
|
|
45
|
-
start: number;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Pending auto-link URL/path state for text-first rendering.
|
|
49
|
-
* When set, URL chars flow as visible text. On terminator, a `wrap` opcode
|
|
50
|
-
* retroactively wraps the text node in a Link.
|
|
51
|
-
*
|
|
52
|
-
* For URLs, `confirmed` starts false during speculative prefix matching
|
|
53
|
-
* (chars stream as text while we verify `https://` or `http://`).
|
|
54
|
-
* For paths, `confirmed` starts true (prefix already validated by hold).
|
|
55
|
-
*/
|
|
56
|
-
export interface PendingUrl {
|
|
57
|
-
url_text: string;
|
|
58
|
-
start: number;
|
|
59
|
-
link_type: 'external' | 'internal';
|
|
60
|
-
/** Whether the URL/path prefix has been fully confirmed. */
|
|
61
|
-
confirmed: boolean;
|
|
62
|
-
/** Prefix match tracking — only used when `!confirmed`. */
|
|
63
|
-
viable_https: boolean;
|
|
64
|
-
viable_http: boolean;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Mutable state for the streaming parser. One instance per `MdzStreamParser`.
|
|
68
|
-
* Handlers in sibling modules take this as their first parameter — the streaming
|
|
69
|
-
* parser uses free functions, not class methods, so state crosses module
|
|
70
|
-
* boundaries.
|
|
71
|
-
*/
|
|
72
|
-
export interface MdzStreamParserState {
|
|
73
|
-
buffer: string;
|
|
74
|
-
pos: number;
|
|
75
|
-
opcodes: Array<MdzOpcode>;
|
|
76
|
-
next_id: MdzNodeId;
|
|
77
|
-
stack: Array<StackEntry>;
|
|
78
|
-
column: number;
|
|
79
|
-
prev_char: number;
|
|
80
|
-
active_text_id: MdzNodeId | null;
|
|
81
|
-
accumulated_text: string;
|
|
82
|
-
accumulated_text_start: number;
|
|
83
|
-
codeblock: CodeblockState | null;
|
|
84
|
-
/** Global byte offset of the start of `buffer`. */
|
|
85
|
-
base_offset: number;
|
|
86
|
-
/** Whether we're inside a heading (newline ends it). */
|
|
87
|
-
in_heading: boolean;
|
|
88
|
-
/** Whether we're inside an optimistic inline Code container. */
|
|
89
|
-
in_code: boolean;
|
|
90
|
-
/** Cached flag: whether a Paragraph is open on the stack. */
|
|
91
|
-
in_paragraph: boolean;
|
|
92
|
-
pending_url: PendingUrl | null;
|
|
93
|
-
/**
|
|
94
|
-
* Stack of text segments for heading ID computation.
|
|
95
|
-
* Each open container inside a heading pushes a new segment.
|
|
96
|
-
* On close: pop and append to parent (children's text is part of heading).
|
|
97
|
-
* On revert: pop, prepend replacement_text, append to parent
|
|
98
|
-
* (document order: delimiter text comes before children's text).
|
|
99
|
-
*/
|
|
100
|
-
heading_text_parts: Array<string>;
|
|
101
|
-
/**
|
|
102
|
-
* When true, skip leading newlines at the start of the next processing pass.
|
|
103
|
-
* Set after block element closes (codeblock, heading, HR) when trailing
|
|
104
|
-
* newlines couldn't be absorbed within the same buffer — needed for
|
|
105
|
-
* char-by-char streaming where post-block newlines arrive in later chunks.
|
|
106
|
-
*/
|
|
107
|
-
skip_leading_newlines: boolean;
|
|
108
|
-
/**
|
|
109
|
-
* Stack index of the innermost open `Paragraph`, or `-1` when none.
|
|
110
|
-
* Lets `mark_paragraph_non_whitespace` skip the stack walk that runs on
|
|
111
|
-
* every non-whitespace emit. Updated only on Paragraph push/pop (block
|
|
112
|
-
* boundaries — only one of `Paragraph`/`Heading` can be on the stack
|
|
113
|
-
* at a time, so the cache is stable across inline pushes/pops).
|
|
114
|
-
*/
|
|
115
|
-
paragraph_stack_idx: number;
|
|
116
|
-
/**
|
|
117
|
-
* Id of the most-recent `text`/`append_text` emission, used by
|
|
118
|
-
* `trim_trailing_newline` to target the right opcode after `take_opcodes()`
|
|
119
|
-
* has drained the queue. `null` after a structural emit (open/close/revert)
|
|
120
|
-
* sealed the prior text run.
|
|
121
|
-
*/
|
|
122
|
-
last_text_id: MdzNodeId | null;
|
|
123
|
-
/** Whether the most recent text emission's content ended in `'\n'`. */
|
|
124
|
-
last_text_ended_with_newline: boolean;
|
|
125
|
-
/**
|
|
126
|
-
* Whether the most recent text emission was a `text` opcode (not
|
|
127
|
-
* `append_text`) with content exactly `'\n'` — trimming the trailing \n
|
|
128
|
-
* would leave the text node empty, so `active_text_id` must be cleared
|
|
129
|
-
* to keep subsequent content from merging into a deleted node.
|
|
130
|
-
*/
|
|
131
|
-
last_text_was_singleton_newline: boolean;
|
|
132
|
-
}
|
|
133
|
-
export declare const create_state: () => MdzStreamParserState;
|
|
134
|
-
export declare const alloc_id: (state: MdzStreamParserState) => MdzNodeId;
|
|
135
|
-
/**
|
|
136
|
-
* Push a new container frame onto the stack. Fills the boilerplate fields
|
|
137
|
-
* (`has_children`, `has_non_whitespace_content`) so call sites only spell out
|
|
138
|
-
* what varies per container type. Keeping the object literal in one place
|
|
139
|
-
* also gives V8 a single monomorphic creation site for `StackEntry`.
|
|
140
|
-
*/
|
|
141
|
-
export declare const push_stack_entry: (state: MdzStreamParserState, id: MdzNodeId, node_type: MdzContainerNodeType, start: number, optimistic?: boolean, delimiter?: string, tag_name?: string) => void;
|
|
142
|
-
/** Global byte offset for a local buffer position. */
|
|
143
|
-
export declare const offset: (state: MdzStreamParserState, pos?: number) => number;
|
|
144
|
-
export declare const emit: (state: MdzStreamParserState, op: MdzOpcode) => void;
|
|
145
|
-
/** Accumulate text, tracking the start offset for the first character. */
|
|
146
|
-
export declare const accumulate_text: (state: MdzStreamParserState, text: string, start_offset: number) => void;
|
|
147
|
-
/**
|
|
148
|
-
* Flush accumulated text as a text or append_text opcode.
|
|
149
|
-
*/
|
|
150
|
-
export declare const flush_text: (state: MdzStreamParserState) => void;
|
|
151
|
-
export declare const ensure_paragraph: (state: MdzStreamParserState) => void;
|
|
152
|
-
/**
|
|
153
|
-
* Find the innermost open container of a given type.
|
|
154
|
-
* Returns stack index, or -1 if not found.
|
|
155
|
-
* Does not cross block boundaries (Paragraph, Heading).
|
|
156
|
-
*/
|
|
157
|
-
export declare const find_open: (state: MdzStreamParserState, type: MdzContainerNodeType) => number;
|
|
158
|
-
/**
|
|
159
|
-
* Revert all stack entries above the given index.
|
|
160
|
-
*/
|
|
161
|
-
export declare const revert_above: (state: MdzStreamParserState, target_idx: number) => void;
|
|
162
|
-
/**
|
|
163
|
-
* Revert all optimistic inline containers in the current block context.
|
|
164
|
-
*/
|
|
165
|
-
export declare const revert_all_optimistic: (state: MdzStreamParserState) => void;
|
|
166
|
-
/**
|
|
167
|
-
* Trim a trailing newline from paragraph content.
|
|
168
|
-
* Checks unflushed accumulated text first; otherwise emits a `trim_text`
|
|
169
|
-
* opcode targeting the most recent text/append_text via the tracking fields
|
|
170
|
-
* on `state` (which survive `take_opcodes()` drains). The opcode stream
|
|
171
|
-
* stays append-only — no retroactive opcode mutation.
|
|
172
|
-
*/
|
|
173
|
-
export declare const trim_trailing_newline: (state: MdzStreamParserState) => void;
|
|
174
|
-
export declare const close_paragraph: (state: MdzStreamParserState) => void;
|
|
175
|
-
export declare const close_heading: (state: MdzStreamParserState) => void;
|
|
176
|
-
/**
|
|
177
|
-
* Close an unclosed codeblock at EOF by reverting it to a paragraph wrapper.
|
|
178
|
-
*
|
|
179
|
-
* Unlike `revert_empty_codeblock` (which pushes the wrapper onto the stack
|
|
180
|
-
* because parsing continues), this is terminal — called only from `finish()`
|
|
181
|
-
* after no further emits happen — so it skips the `push_stack_entry` /
|
|
182
|
-
* `in_paragraph` / `paragraph_stack_idx` bookkeeping. The wrapper exists only
|
|
183
|
-
* in the opcode stream; the parser state's stack stays untouched.
|
|
184
|
-
*/
|
|
185
|
-
export declare const close_codeblock_at_eof: (state: MdzStreamParserState) => void;
|
|
186
|
-
export declare const handle_paragraph_break: (state: MdzStreamParserState) => void;
|
|
187
|
-
//# sourceMappingURL=mdz_stream_parser_state.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mdz_stream_parser_state.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_stream_parser_state.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,398 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Streaming parser state and low-level operations.
|
|
3
|
-
*
|
|
4
|
-
* Free functions take a `MdzStreamParserState` first parameter so handlers can
|
|
5
|
-
* live in separate sibling modules — JS private (`#`) fields can't cross
|
|
6
|
-
* module boundaries.
|
|
7
|
-
*
|
|
8
|
-
* @module
|
|
9
|
-
*/
|
|
10
|
-
import { NEWLINE, mdz_heading_id_from_text } from './mdz_helpers.js';
|
|
11
|
-
export const create_state = () => ({
|
|
12
|
-
buffer: '',
|
|
13
|
-
pos: 0,
|
|
14
|
-
opcodes: [],
|
|
15
|
-
next_id: 0,
|
|
16
|
-
stack: [],
|
|
17
|
-
column: 0,
|
|
18
|
-
prev_char: -1,
|
|
19
|
-
active_text_id: null,
|
|
20
|
-
accumulated_text: '',
|
|
21
|
-
accumulated_text_start: 0,
|
|
22
|
-
codeblock: null,
|
|
23
|
-
base_offset: 0,
|
|
24
|
-
in_heading: false,
|
|
25
|
-
in_code: false,
|
|
26
|
-
in_paragraph: false,
|
|
27
|
-
pending_url: null,
|
|
28
|
-
heading_text_parts: [],
|
|
29
|
-
// matches mdz_parse: leading newlines before any block are skipped, not
|
|
30
|
-
// preserved as paragraph content
|
|
31
|
-
skip_leading_newlines: true,
|
|
32
|
-
paragraph_stack_idx: -1,
|
|
33
|
-
last_text_id: null,
|
|
34
|
-
last_text_ended_with_newline: false,
|
|
35
|
-
last_text_was_singleton_newline: false,
|
|
36
|
-
});
|
|
37
|
-
export const alloc_id = (state) => state.next_id++;
|
|
38
|
-
/**
|
|
39
|
-
* Whether `text` contains any non-whitespace character. Hot path — called from
|
|
40
|
-
* `emit` on every text emission. Char-loop checking common whitespace (space,
|
|
41
|
-
* tab, newline, carriage return, form feed, vertical tab) avoids the regex
|
|
42
|
-
* allocation that `/\S/.test()` incurs per call.
|
|
43
|
-
*
|
|
44
|
-
* Deliberately ASCII-only. `/\S/` and `String.prototype.trim()` (which
|
|
45
|
-
* `mdz_parse` uses to detect whitespace-only paragraphs) recognize Unicode
|
|
46
|
-
* whitespace too (U+00A0 NBSP, U+2028/U+2029, U+3000, etc.). A paragraph
|
|
47
|
-
* containing only Unicode whitespace would be kept by the streaming parser
|
|
48
|
-
* but dropped by `mdz_parse` — no fixture currently hits this.
|
|
49
|
-
*/
|
|
50
|
-
const has_non_whitespace = (text) => {
|
|
51
|
-
for (let i = 0; i < text.length; i++) {
|
|
52
|
-
const c = text.charCodeAt(i);
|
|
53
|
-
// 0x09=tab, 0x0a=LF, 0x0b=VT, 0x0c=FF, 0x0d=CR, 0x20=space
|
|
54
|
-
if (c !== 0x20 && (c < 0x09 || c > 0x0d))
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
return false;
|
|
58
|
-
};
|
|
59
|
-
/**
|
|
60
|
-
* Push a new container frame onto the stack. Fills the boilerplate fields
|
|
61
|
-
* (`has_children`, `has_non_whitespace_content`) so call sites only spell out
|
|
62
|
-
* what varies per container type. Keeping the object literal in one place
|
|
63
|
-
* also gives V8 a single monomorphic creation site for `StackEntry`.
|
|
64
|
-
*/
|
|
65
|
-
export const push_stack_entry = (state, id, node_type, start, optimistic = false, delimiter = '', tag_name) => {
|
|
66
|
-
state.stack.push({
|
|
67
|
-
id,
|
|
68
|
-
node_type,
|
|
69
|
-
optimistic,
|
|
70
|
-
delimiter,
|
|
71
|
-
tag_name,
|
|
72
|
-
has_children: false,
|
|
73
|
-
has_non_whitespace_content: false,
|
|
74
|
-
start,
|
|
75
|
-
});
|
|
76
|
-
if (node_type === 'Paragraph') {
|
|
77
|
-
state.paragraph_stack_idx = state.stack.length - 1;
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
/**
|
|
81
|
-
* Mark the innermost open `Paragraph` as having non-whitespace content,
|
|
82
|
-
* via the `paragraph_stack_idx` cache (O(1) instead of an O(stack) walk).
|
|
83
|
-
*
|
|
84
|
-
* No-op when no Paragraph is open — that includes the Heading case, since
|
|
85
|
-
* block boundaries are mutually exclusive (a Heading on stack means
|
|
86
|
-
* `paragraph_stack_idx === -1`).
|
|
87
|
-
*/
|
|
88
|
-
const mark_paragraph_non_whitespace = (state) => {
|
|
89
|
-
if (state.paragraph_stack_idx === -1)
|
|
90
|
-
return;
|
|
91
|
-
state.stack[state.paragraph_stack_idx].has_non_whitespace_content = true;
|
|
92
|
-
};
|
|
93
|
-
/** Global byte offset for a local buffer position. */
|
|
94
|
-
export const offset = (state, pos = state.pos) => state.base_offset + pos;
|
|
95
|
-
export const emit = (state, op) => {
|
|
96
|
-
state.opcodes.push(op);
|
|
97
|
-
// mark the innermost container as having children
|
|
98
|
-
if (op.type === 'text' || op.type === 'append_text' || op.type === 'void') {
|
|
99
|
-
const top = state.stack[state.stack.length - 1];
|
|
100
|
-
if (top) {
|
|
101
|
-
top.has_children = true;
|
|
102
|
-
// propagate non-whitespace marker to the nearest Paragraph so
|
|
103
|
-
// whitespace-only paragraphs can be discarded at close
|
|
104
|
-
if (op.type === 'void' || has_non_whitespace(op.content)) {
|
|
105
|
-
mark_paragraph_non_whitespace(state);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
else if (op.type === 'open') {
|
|
110
|
-
// opening a child container counts as content for the parent
|
|
111
|
-
const parent = state.stack[state.stack.length - 1];
|
|
112
|
-
if (parent) {
|
|
113
|
-
parent.has_children = true;
|
|
114
|
-
mark_paragraph_non_whitespace(state);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
else if (op.type === 'wrap') {
|
|
118
|
-
// retroactive Link wrap of a text node — the resulting Link is non-whitespace
|
|
119
|
-
mark_paragraph_non_whitespace(state);
|
|
120
|
-
}
|
|
121
|
-
// track the most recent text run so `trim_trailing_newline` can target it
|
|
122
|
-
// after `take_opcodes()` has drained the queue
|
|
123
|
-
if (op.type === 'text') {
|
|
124
|
-
state.last_text_id = op.id;
|
|
125
|
-
state.last_text_ended_with_newline = op.content.endsWith('\n');
|
|
126
|
-
state.last_text_was_singleton_newline = op.content === '\n';
|
|
127
|
-
}
|
|
128
|
-
else if (op.type === 'append_text') {
|
|
129
|
-
state.last_text_id = op.id;
|
|
130
|
-
state.last_text_ended_with_newline = op.content.endsWith('\n');
|
|
131
|
-
// append_text builds on a prior text node; the underlying node can't be
|
|
132
|
-
// singleton even if this appended chunk is just '\n'
|
|
133
|
-
state.last_text_was_singleton_newline = false;
|
|
134
|
-
}
|
|
135
|
-
else if (op.type === 'open' || op.type === 'close' || op.type === 'revert') {
|
|
136
|
-
// structural opcode seals the prior text run
|
|
137
|
-
state.last_text_id = null;
|
|
138
|
-
state.last_text_ended_with_newline = false;
|
|
139
|
-
state.last_text_was_singleton_newline = false;
|
|
140
|
-
}
|
|
141
|
-
// track text content for heading ID computation
|
|
142
|
-
if (state.in_heading && state.heading_text_parts.length > 0) {
|
|
143
|
-
if (op.type === 'text' || op.type === 'append_text') {
|
|
144
|
-
state.heading_text_parts[state.heading_text_parts.length - 1] += op.content;
|
|
145
|
-
}
|
|
146
|
-
else if (op.type === 'open') {
|
|
147
|
-
// child container: push a new segment for its text content
|
|
148
|
-
state.heading_text_parts.push('');
|
|
149
|
-
}
|
|
150
|
-
else if (op.type === 'close') {
|
|
151
|
-
// normal close: pop child's text and merge into parent
|
|
152
|
-
if (state.heading_text_parts.length > 1) {
|
|
153
|
-
const child_text = state.heading_text_parts.pop();
|
|
154
|
-
state.heading_text_parts[state.heading_text_parts.length - 1] += child_text;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
else if (op.type === 'revert') {
|
|
158
|
-
// revert: pop child's text, prepend replacement (document order), merge into parent
|
|
159
|
-
if (state.heading_text_parts.length > 1) {
|
|
160
|
-
const child_text = state.heading_text_parts.pop();
|
|
161
|
-
state.heading_text_parts[state.heading_text_parts.length - 1] +=
|
|
162
|
-
(op.replacement_text || '') + child_text;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
/** Accumulate text, tracking the start offset for the first character. */
|
|
168
|
-
export const accumulate_text = (state, text, start_offset) => {
|
|
169
|
-
if (state.accumulated_text.length === 0) {
|
|
170
|
-
state.accumulated_text_start = start_offset;
|
|
171
|
-
}
|
|
172
|
-
state.accumulated_text += text;
|
|
173
|
-
};
|
|
174
|
-
/**
|
|
175
|
-
* Flush accumulated text as a text or append_text opcode.
|
|
176
|
-
*/
|
|
177
|
-
export const flush_text = (state) => {
|
|
178
|
-
if (state.accumulated_text.length === 0)
|
|
179
|
-
return;
|
|
180
|
-
if (state.active_text_id !== null) {
|
|
181
|
-
emit(state, {
|
|
182
|
-
type: 'append_text',
|
|
183
|
-
id: state.active_text_id,
|
|
184
|
-
content: state.accumulated_text,
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
ensure_paragraph(state);
|
|
189
|
-
const id = alloc_id(state);
|
|
190
|
-
const start = state.accumulated_text_start;
|
|
191
|
-
emit(state, {
|
|
192
|
-
type: 'text',
|
|
193
|
-
id,
|
|
194
|
-
content: state.accumulated_text,
|
|
195
|
-
text_type: 'Text',
|
|
196
|
-
start,
|
|
197
|
-
end: start + state.accumulated_text.length,
|
|
198
|
-
});
|
|
199
|
-
state.active_text_id = id;
|
|
200
|
-
}
|
|
201
|
-
state.accumulated_text = '';
|
|
202
|
-
};
|
|
203
|
-
export const ensure_paragraph = (state) => {
|
|
204
|
-
if (state.in_heading || state.in_paragraph)
|
|
205
|
-
return;
|
|
206
|
-
const id = alloc_id(state);
|
|
207
|
-
const start = offset(state);
|
|
208
|
-
emit(state, { type: 'open', id, node_type: 'Paragraph', start });
|
|
209
|
-
push_stack_entry(state, id, 'Paragraph', start);
|
|
210
|
-
state.in_paragraph = true;
|
|
211
|
-
};
|
|
212
|
-
/**
|
|
213
|
-
* Find the innermost open container of a given type.
|
|
214
|
-
* Returns stack index, or -1 if not found.
|
|
215
|
-
* Does not cross block boundaries (Paragraph, Heading).
|
|
216
|
-
*/
|
|
217
|
-
export const find_open = (state, type) => {
|
|
218
|
-
for (let i = state.stack.length - 1; i >= 0; i--) {
|
|
219
|
-
const entry = state.stack[i];
|
|
220
|
-
if (entry.node_type === type)
|
|
221
|
-
return i;
|
|
222
|
-
// don't cross block boundaries
|
|
223
|
-
if (entry.node_type === 'Paragraph' || entry.node_type === 'Heading')
|
|
224
|
-
return -1;
|
|
225
|
-
}
|
|
226
|
-
return -1;
|
|
227
|
-
};
|
|
228
|
-
/**
|
|
229
|
-
* Revert all stack entries above the given index.
|
|
230
|
-
*/
|
|
231
|
-
export const revert_above = (state, target_idx) => {
|
|
232
|
-
while (state.stack.length - 1 > target_idx) {
|
|
233
|
-
const entry = state.stack.pop();
|
|
234
|
-
if (entry.node_type === 'Code')
|
|
235
|
-
state.in_code = false;
|
|
236
|
-
if (entry.optimistic) {
|
|
237
|
-
emit(state, {
|
|
238
|
-
type: 'revert',
|
|
239
|
-
id: entry.id,
|
|
240
|
-
replacement_text: entry.delimiter,
|
|
241
|
-
start: entry.start,
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
245
|
-
emit(state, { type: 'close', id: entry.id, end: offset(state) });
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
state.active_text_id = null;
|
|
249
|
-
};
|
|
250
|
-
/**
|
|
251
|
-
* Revert all optimistic inline containers in the current block context.
|
|
252
|
-
*/
|
|
253
|
-
export const revert_all_optimistic = (state) => {
|
|
254
|
-
while (state.stack.length > 0) {
|
|
255
|
-
const top = state.stack[state.stack.length - 1];
|
|
256
|
-
if (top.node_type === 'Paragraph' || top.node_type === 'Heading')
|
|
257
|
-
break;
|
|
258
|
-
state.stack.pop();
|
|
259
|
-
if (top.node_type === 'Code')
|
|
260
|
-
state.in_code = false;
|
|
261
|
-
if (top.optimistic) {
|
|
262
|
-
emit(state, {
|
|
263
|
-
type: 'revert',
|
|
264
|
-
id: top.id,
|
|
265
|
-
replacement_text: top.delimiter,
|
|
266
|
-
start: top.start,
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
else {
|
|
270
|
-
emit(state, { type: 'close', id: top.id, end: offset(state) });
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
state.active_text_id = null;
|
|
274
|
-
};
|
|
275
|
-
/**
|
|
276
|
-
* Trim a trailing newline from paragraph content.
|
|
277
|
-
* Checks unflushed accumulated text first; otherwise emits a `trim_text`
|
|
278
|
-
* opcode targeting the most recent text/append_text via the tracking fields
|
|
279
|
-
* on `state` (which survive `take_opcodes()` drains). The opcode stream
|
|
280
|
-
* stays append-only — no retroactive opcode mutation.
|
|
281
|
-
*/
|
|
282
|
-
export const trim_trailing_newline = (state) => {
|
|
283
|
-
if (state.accumulated_text.endsWith('\n')) {
|
|
284
|
-
state.accumulated_text = state.accumulated_text.slice(0, -1);
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
if (state.last_text_id === null || !state.last_text_ended_with_newline)
|
|
288
|
-
return;
|
|
289
|
-
// emit trim opcode; consumer adjusts content and removes empty nodes
|
|
290
|
-
emit(state, { type: 'trim_text', id: state.last_text_id, count: 1 });
|
|
291
|
-
// if this trim empties a singleton text node, clear active_text_id so
|
|
292
|
-
// subsequent content doesn't merge into a deleted node via append_text
|
|
293
|
-
if (state.last_text_was_singleton_newline) {
|
|
294
|
-
state.active_text_id = null;
|
|
295
|
-
}
|
|
296
|
-
// after trim, the prior text no longer ends in \n — guard against re-trim
|
|
297
|
-
state.last_text_ended_with_newline = false;
|
|
298
|
-
state.last_text_was_singleton_newline = false;
|
|
299
|
-
};
|
|
300
|
-
export const close_paragraph = (state) => {
|
|
301
|
-
// find and close the paragraph on the stack
|
|
302
|
-
for (let i = state.stack.length - 1; i >= 0; i--) {
|
|
303
|
-
if (state.stack[i].node_type === 'Paragraph') {
|
|
304
|
-
// trim trailing newline from paragraph content
|
|
305
|
-
trim_trailing_newline(state);
|
|
306
|
-
// revert everything above the paragraph
|
|
307
|
-
while (state.stack.length - 1 > i) {
|
|
308
|
-
const entry = state.stack.pop();
|
|
309
|
-
if (entry.node_type === 'Code')
|
|
310
|
-
state.in_code = false;
|
|
311
|
-
emit(state, {
|
|
312
|
-
type: 'revert',
|
|
313
|
-
id: entry.id,
|
|
314
|
-
replacement_text: entry.delimiter,
|
|
315
|
-
start: entry.start,
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
const entry = state.stack.pop();
|
|
319
|
-
// drop whitespace-only paragraphs to match `mdz_parse`'s output;
|
|
320
|
-
// consumers (`mdz_opcodes_to_nodes`, `MdzStreamState`) honor `discard`
|
|
321
|
-
// by removing the node and its descendants from the tree
|
|
322
|
-
const discard = !entry.has_non_whitespace_content;
|
|
323
|
-
emit(state, discard
|
|
324
|
-
? { type: 'close', id: entry.id, end: offset(state), discard: true }
|
|
325
|
-
: { type: 'close', id: entry.id, end: offset(state) });
|
|
326
|
-
state.active_text_id = null;
|
|
327
|
-
state.in_paragraph = false;
|
|
328
|
-
state.paragraph_stack_idx = -1;
|
|
329
|
-
return;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
};
|
|
333
|
-
export const close_heading = (state) => {
|
|
334
|
-
// revert optimistic containers inside the heading (before clearing in_heading,
|
|
335
|
-
// so revert replacement text is captured in heading_text_parts)
|
|
336
|
-
revert_all_optimistic(state);
|
|
337
|
-
// compute heading ID from accumulated text before clearing heading state
|
|
338
|
-
const heading_text = state.heading_text_parts.join('');
|
|
339
|
-
state.heading_text_parts = [];
|
|
340
|
-
state.in_heading = false;
|
|
341
|
-
const heading_id = mdz_heading_id_from_text(heading_text);
|
|
342
|
-
const end = offset(state);
|
|
343
|
-
// find and close the heading
|
|
344
|
-
for (let i = state.stack.length - 1; i >= 0; i--) {
|
|
345
|
-
if (state.stack[i].node_type === 'Heading') {
|
|
346
|
-
const entry = state.stack[i];
|
|
347
|
-
state.stack.splice(i, 1);
|
|
348
|
-
emit(state, { type: 'close', id: entry.id, end, heading_id });
|
|
349
|
-
state.active_text_id = null;
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
};
|
|
354
|
-
/**
|
|
355
|
-
* Close an unclosed codeblock at EOF by reverting it to a paragraph wrapper.
|
|
356
|
-
*
|
|
357
|
-
* Unlike `revert_empty_codeblock` (which pushes the wrapper onto the stack
|
|
358
|
-
* because parsing continues), this is terminal — called only from `finish()`
|
|
359
|
-
* after no further emits happen — so it skips the `push_stack_entry` /
|
|
360
|
-
* `in_paragraph` / `paragraph_stack_idx` bookkeeping. The wrapper exists only
|
|
361
|
-
* in the opcode stream; the parser state's stack stays untouched.
|
|
362
|
-
*/
|
|
363
|
-
export const close_codeblock_at_eof = (state) => {
|
|
364
|
-
if (!state.codeblock)
|
|
365
|
-
return;
|
|
366
|
-
const cb = state.codeblock;
|
|
367
|
-
// trim trailing newline from codeblock content (mirrors close_paragraph behavior)
|
|
368
|
-
trim_trailing_newline(state);
|
|
369
|
-
const wrap_id = alloc_id(state);
|
|
370
|
-
emit(state, {
|
|
371
|
-
type: 'revert',
|
|
372
|
-
id: cb.id,
|
|
373
|
-
replacement_text: cb.delimiter,
|
|
374
|
-
start: cb.start,
|
|
375
|
-
wrap_node_type: 'Paragraph',
|
|
376
|
-
wrap_id,
|
|
377
|
-
});
|
|
378
|
-
emit(state, { type: 'close', id: wrap_id, end: offset(state) });
|
|
379
|
-
state.codeblock = null;
|
|
380
|
-
};
|
|
381
|
-
export const handle_paragraph_break = (state) => {
|
|
382
|
-
flush_text(state);
|
|
383
|
-
// revert all unclosed optimistic inline containers
|
|
384
|
-
revert_all_optimistic(state);
|
|
385
|
-
close_paragraph(state);
|
|
386
|
-
// skip all consecutive newlines
|
|
387
|
-
while (state.pos < state.buffer.length && state.buffer.charCodeAt(state.pos) === NEWLINE) {
|
|
388
|
-
state.pos++;
|
|
389
|
-
}
|
|
390
|
-
// if we ran out of buffer while skipping, carry the absorb across chunks —
|
|
391
|
-
// otherwise a `\n\n\n\n` split mid-run would leak a leading `\n` into the
|
|
392
|
-
// next paragraph's text. Mirrors the heading-newline absorb in `process_inline`.
|
|
393
|
-
if (state.pos >= state.buffer.length) {
|
|
394
|
-
state.skip_leading_newlines = true;
|
|
395
|
-
}
|
|
396
|
-
state.column = 0;
|
|
397
|
-
state.prev_char = NEWLINE;
|
|
398
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plain-text run consumption for the streaming mdz parser.
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
5
|
-
*/
|
|
6
|
-
import { type MdzStreamParserState } from './mdz_stream_parser_state.js';
|
|
7
|
-
/**
|
|
8
|
-
* Consume a run of plain text characters. Scans ahead to the next
|
|
9
|
-
* structurally interesting character and accumulates the whole run
|
|
10
|
-
* as a single slice, avoiding per-character string concatenation
|
|
11
|
-
* and dispatch overhead.
|
|
12
|
-
*/
|
|
13
|
-
export declare const consume_text_run: (state: MdzStreamParserState) => void;
|
|
14
|
-
//# sourceMappingURL=mdz_stream_parser_text.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mdz_stream_parser_text.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/mdz_stream_parser_text.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAqBH,OAAO,EACN,KAAK,oBAAoB,EAIzB,MAAM,8BAA8B,CAAC;AAEtC;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,oBAAoB,KAAG,IAsC9D,CAAC"}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plain-text run consumption for the streaming mdz parser.
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
5
|
-
*/
|
|
6
|
-
import { ASTERISK, BACKTICK, HTTPS_PREFIX_LENGTH, H_LOWER, H_UPPER, LEFT_ANGLE, LEFT_BRACKET, NEWLINE, PERIOD, RIGHT_BRACKET, SLASH, SPACE, TAB, TILDE, UNDERSCORE, is_word_char, match_url_prefix_case_insensitive, } from './mdz_helpers.js';
|
|
7
|
-
import { accumulate_text, ensure_paragraph, offset, } from './mdz_stream_parser_state.js';
|
|
8
|
-
/**
|
|
9
|
-
* Consume a run of plain text characters. Scans ahead to the next
|
|
10
|
-
* structurally interesting character and accumulates the whole run
|
|
11
|
-
* as a single slice, avoiding per-character string concatenation
|
|
12
|
-
* and dispatch overhead.
|
|
13
|
-
*/
|
|
14
|
-
export const consume_text_run = (state) => {
|
|
15
|
-
ensure_paragraph(state);
|
|
16
|
-
const start = state.pos;
|
|
17
|
-
state.pos++;
|
|
18
|
-
while (state.pos < state.buffer.length) {
|
|
19
|
-
const c = state.buffer.charCodeAt(state.pos);
|
|
20
|
-
if (c === BACKTICK ||
|
|
21
|
-
c === ASTERISK ||
|
|
22
|
-
c === UNDERSCORE ||
|
|
23
|
-
c === TILDE ||
|
|
24
|
-
c === LEFT_BRACKET ||
|
|
25
|
-
c === RIGHT_BRACKET ||
|
|
26
|
-
c === LEFT_ANGLE ||
|
|
27
|
-
c === NEWLINE ||
|
|
28
|
-
// URL/path: only break when actually at a URL or path start.
|
|
29
|
-
// Most h/H/./slash in prose are not URLs/paths — continuing the scan
|
|
30
|
-
// avoids the full dispatch cycle through process_loop → process_inline.
|
|
31
|
-
// For `h`/`H` at a word boundary, also break when there isn't enough
|
|
32
|
-
// buffer left to confirm `https://` / `http://` — process_inline's
|
|
33
|
-
// speculator then carries the prefix match across chunk boundaries.
|
|
34
|
-
// Scheme matching is case-insensitive (RFC 3986).
|
|
35
|
-
((c === H_LOWER || c === H_UPPER) &&
|
|
36
|
-
(match_url_prefix_case_insensitive(state.buffer, state.pos) > 0 ||
|
|
37
|
-
(state.buffer.length - state.pos < HTTPS_PREFIX_LENGTH &&
|
|
38
|
-
!is_word_char(state.buffer.charCodeAt(state.pos - 1))))) ||
|
|
39
|
-
((c === SLASH || c === PERIOD) &&
|
|
40
|
-
(state.buffer.charCodeAt(state.pos - 1) === SPACE ||
|
|
41
|
-
state.buffer.charCodeAt(state.pos - 1) === NEWLINE ||
|
|
42
|
-
state.buffer.charCodeAt(state.pos - 1) === TAB))) {
|
|
43
|
-
break;
|
|
44
|
-
}
|
|
45
|
-
state.pos++;
|
|
46
|
-
}
|
|
47
|
-
accumulate_text(state, state.buffer.slice(start, state.pos), offset(state, start));
|
|
48
|
-
state.prev_char = state.buffer.charCodeAt(state.pos - 1);
|
|
49
|
-
state.column += state.pos - start;
|
|
50
|
-
};
|