atdoc-core 0.1.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.
@@ -0,0 +1,23 @@
1
+ export type TokenType = 'NODE' | 'PAREN' | 'STYLES' | 'SLOT_OPEN' | 'SLOT_CLOSE' | 'RAW' | 'TEXT';
2
+ export interface Token {
3
+ type: TokenType;
4
+ value: string;
5
+ /** Source character offsets — lets consumers (e.g. editor diagnostics) map a token back to a range. */
6
+ start: number;
7
+ end: number;
8
+ /** RAW tokens only — false if the scan ran out of input before finding the closing "]" (mid-typing, or a genuinely unterminated block). Lets consumers (e.g. the editor's completion provider) tell "caret still inside raw content" apart from "raw content already closed". */
9
+ closed?: boolean;
10
+ /** raw-escaped RAW tokens only — each local escape sequence the scan consumed ("@]", "@[", "@@]", "@@["), with its source range. Lets the Parser point an editor marker at the exact escape when one looks like it swallowed the intended closing bracket. */
11
+ escapes?: RawEscape[];
12
+ }
13
+ /** One consumed local escape inside @raw's content — see scanDepthRaw. */
14
+ export interface RawEscape {
15
+ start: number;
16
+ end: number;
17
+ /** The literal source characters, e.g. "@]" or "@@[". */
18
+ seq: string;
19
+ /** True when the next source character after the escape is a newline — the signature of an escape that consumed a "]" the author meant as the node's end-of-line closer (see Parser.diagnoseRawEscapes). */
20
+ atLineEnd: boolean;
21
+ }
22
+ export declare function tokenize(source: string): Token[];
23
+ //# sourceMappingURL=Lexer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Lexer.d.ts","sourceRoot":"","sources":["../src/Lexer.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,YAAY,GAAG,KAAK,GAAG,MAAM,CAAC;AAElG,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,uGAAuG;IACvG,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,iRAAiR;IACjR,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,8PAA8P;IAC9P,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC;CACvB;AAED,0EAA0E;AAC1E,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,yDAAyD;IACzD,GAAG,EAAE,MAAM,CAAC;IACZ,4MAA4M;IAC5M,SAAS,EAAE,OAAO,CAAC;CACpB;AAsJD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,CA6IhD"}
package/dist/Lexer.js ADDED
@@ -0,0 +1,292 @@
1
+ // Lexer — implements Inline Syntax Specification §2 (Lexer behavior definition) precisely:
2
+ //
3
+ // 1. "@@" → literal "@" (checked before any registry lookup)
4
+ // 2. "@" + known command name → NODE token
5
+ // 3. "@" + anything else → literal text
6
+ //
7
+ // It is registry-aware (see registry.ts) rather than a context-free tokenizer,
8
+ // because raw-content nodes (@code, @mermaid, @raw, @kbd, @fn) require the
9
+ // Lexer to switch into an opaque scan mode for their bracket content — see
10
+ // Inline Syntax Specification §9 (@raw Opaque Domain) and Special-Nodes.md §6.
11
+ import { getNodeDef } from './registry';
12
+ const IDENT_CHAR = /[a-zA-Z0-9_-]/;
13
+ /**
14
+ * Scans a strong-quoted slot, starting just after the opening "{[".
15
+ *
16
+ * The content runs verbatim to the first "]}" — no bracket depth, no escapes,
17
+ * nothing to get wrong. That is the whole point: the ordinary "[...]" form
18
+ * terminates on depth, so content whose brackets don't balance cannot be
19
+ * written at all in @code/@mermaid (which define no escapes) and needs
20
+ * hand-escaping in @raw. Measured over 1,632 code fences in real READMEs, 2
21
+ * had unbalanced brackets and 4 contained "]}", with no overlap — so the pair
22
+ * that can't be written one way can always be written the other.
23
+ *
24
+ * A fixed terminator can still be defeated by content that contains "]}", the
25
+ * same way any fixed delimiter can; that content keeps the "[...]" form.
26
+ */
27
+ function scanStrongRaw(source, start) {
28
+ const end = source.indexOf(']}', start);
29
+ if (end === -1)
30
+ return { text: source.slice(start), endPos: source.length, closed: false };
31
+ return { text: source.slice(start, end), endPos: end + 2, closed: true };
32
+ }
33
+ function isRawFamily(mode) {
34
+ return mode === 'raw' || mode === 'raw-escaped' || mode === 'key' || mode === 'integer';
35
+ }
36
+ /**
37
+ * Scans raw, unparsed content starting right after the opening "[".
38
+ * Tracks nested "[" / "]" depth so literal brackets inside code/diagram
39
+ * content don't prematurely terminate the slot (see Text-Formatting.md §4 Raw
40
+ * and Widget-Blocks.md §4 Mermaid for why this matters in practice).
41
+ *
42
+ * `localEscape` enables @raw's four local exceptions (Inline Spec §9):
43
+ * "@]" → literal "]"
44
+ * "@@]" → literal "@]"
45
+ * "@[" → literal "["
46
+ * "@@[" → literal "@["
47
+ * These do NOT apply to @code/@mermaid, which define no escape mechanism at all.
48
+ */
49
+ function scanDepthRaw(source, start, localEscape) {
50
+ let depth = 1;
51
+ let buf = '';
52
+ let i = start;
53
+ const n = source.length;
54
+ const escapes = [];
55
+ while (i < n) {
56
+ if (localEscape && source[i] === '@' && source[i + 1] === '@' && source[i + 2] === ']') {
57
+ escapes.push({ start: i, end: i + 3, seq: '@@]', atLineEnd: source[i + 3] === '\n' });
58
+ buf += '@]';
59
+ i += 3;
60
+ continue;
61
+ }
62
+ if (localEscape && source[i] === '@' && source[i + 1] === '@' && source[i + 2] === '[') {
63
+ escapes.push({ start: i, end: i + 3, seq: '@@[', atLineEnd: source[i + 3] === '\n' });
64
+ buf += '@[';
65
+ i += 3;
66
+ continue;
67
+ }
68
+ if (localEscape && source[i] === '@' && source[i + 1] === ']') {
69
+ escapes.push({ start: i, end: i + 2, seq: '@]', atLineEnd: source[i + 2] === '\n' });
70
+ buf += ']';
71
+ i += 2;
72
+ continue;
73
+ }
74
+ if (localEscape && source[i] === '@' && source[i + 1] === '[') {
75
+ escapes.push({ start: i, end: i + 2, seq: '@[', atLineEnd: source[i + 2] === '\n' });
76
+ buf += '[';
77
+ i += 2;
78
+ continue;
79
+ }
80
+ const ch = source[i];
81
+ if (ch === '[') {
82
+ depth++;
83
+ buf += ch;
84
+ i++;
85
+ continue;
86
+ }
87
+ if (ch === ']') {
88
+ depth--;
89
+ i++;
90
+ if (depth === 0)
91
+ return { text: buf, endPos: i, closed: true, escapes };
92
+ buf += ch;
93
+ continue;
94
+ }
95
+ buf += ch;
96
+ i++;
97
+ }
98
+ // Ran out of input before depth reached 0 — genuinely unterminated (or, for
99
+ // the editor's incremental re-tokenize of `textBeforeCaret`, just not typed
100
+ // that far yet). See Token.closed.
101
+ return { text: buf, endPos: i, closed: false, escapes };
102
+ }
103
+ /** Flat scan for @kbd's `key` and @fn's `integer` — no nesting, no escapes. */
104
+ function scanFlatRaw(source, start) {
105
+ let i = start;
106
+ const n = source.length;
107
+ let buf = '';
108
+ while (i < n && source[i] !== ']') {
109
+ buf += source[i];
110
+ i++;
111
+ }
112
+ if (i >= n)
113
+ return { text: buf, endPos: i, closed: false }; // ran out before finding "]"
114
+ return { text: buf, endPos: i + 1, closed: true };
115
+ }
116
+ function scanRawContent(source, start, mode) {
117
+ if (mode === 'key' || mode === 'integer')
118
+ return scanFlatRaw(source, start);
119
+ return scanDepthRaw(source, start, mode === 'raw-escaped');
120
+ }
121
+ /**
122
+ * Finds where a "{styles}" run ends, scanning from just after the "{".
123
+ * Returns the index of the terminator and whether it was a real "}".
124
+ *
125
+ * Deliberately stricter than the EBNF, which defines the inner set as
126
+ * `text-char - "}"` and leaves `text-char = any-unicode-char` — i.e. a
127
+ * {styles} run could technically span lines and swallow anything. Taken
128
+ * literally, a half-typed "{" (`@h(4){` with the "}" not there yet) eats the
129
+ * rest of the document up to whatever "}" appears next — a brace inside an
130
+ * unrelated `@code` block, say — silently deleting every node in between
131
+ * from the AST. Nothing legitimate needs that reach: a styles run is a short
132
+ * comma-separated token list, no spec example spans lines, and the editor's
133
+ * Monarch rule (/\{[^}]*\}/, matched per line) never supported it either.
134
+ * So the scan stops at:
135
+ * "}" — the real terminator (closed: true)
136
+ * end of line — unterminated; the author is mid-typing
137
+ * "[" — unterminated; the content slot has started, and no
138
+ * styles value ever contains "["
139
+ * Both unterminated cases still produce a STYLES token so the Parser can
140
+ * flag the slot itself (e.g. "@heading has no {styles} slot"), just one that
141
+ * stops before it can damage the rest of the document.
142
+ */
143
+ function scanStylesEnd(source, start) {
144
+ const n = source.length;
145
+ let i = start;
146
+ while (i < n) {
147
+ const ch = source[i];
148
+ if (ch === '}')
149
+ return { end: i, closed: true };
150
+ if (ch === '\n' || ch === '[')
151
+ return { end: i, closed: false };
152
+ i++;
153
+ }
154
+ return { end: n, closed: false };
155
+ }
156
+ export function tokenize(source) {
157
+ const tokens = [];
158
+ const n = source.length;
159
+ let i = 0;
160
+ let textBuf = '';
161
+ let textStart = -1;
162
+ const appendText = (s, pos) => {
163
+ if (textBuf === '')
164
+ textStart = pos;
165
+ textBuf += s;
166
+ };
167
+ const flushText = () => {
168
+ if (textBuf) {
169
+ tokens.push({ type: 'TEXT', value: textBuf, start: textStart, end: textStart + textBuf.length });
170
+ textBuf = '';
171
+ textStart = -1;
172
+ }
173
+ };
174
+ while (i < n) {
175
+ const ch = source[i];
176
+ if (ch === '@') {
177
+ // Step 1 (Inline Spec §2): "@@" is checked first, purely by pattern —
178
+ // before any Command Registry lookup. See Special-Nodes.md §5.
179
+ if (source[i + 1] === '@') {
180
+ appendText('@', i);
181
+ i += 2;
182
+ continue;
183
+ }
184
+ const nodeStart = i;
185
+ // Step 2: maximal-munch identifier, then registry lookup.
186
+ let j = i + 1;
187
+ while (j < n && IDENT_CHAR.test(source[j]))
188
+ j++;
189
+ const ident = source.slice(i + 1, j);
190
+ const nodeDef = ident ? getNodeDef(ident) : undefined;
191
+ if (!nodeDef) {
192
+ // Step 3: unknown command → literal text (Inline Spec §6).
193
+ appendText(source.slice(i, j), i);
194
+ i = j;
195
+ continue;
196
+ }
197
+ flushText();
198
+ tokens.push({ type: 'NODE', value: ident, start: nodeStart, end: j });
199
+ i = j;
200
+ // Optional "(...)" and "{...}" — modifier/level/title/language/uri/id/
201
+ // options, and styles respectively. Canonical order is (paren) before
202
+ // {styles} (Block Syntax Specification §6/§7), but a swapped `{styles}
203
+ // (title)` must still tokenize as STYLES then PAREN rather than let the
204
+ // out-of-place "(" decay into literal TEXT — otherwise the Parser never
205
+ // sees a PAREN token to flag with a specific "wrong order" error, and
206
+ // authors just get a misleading "expects a content slot" instead.
207
+ // Grammar excludes ")"/"}" from the inner text-char sets, so a naive
208
+ // indexOf is faithful for "(...)" (no nesting is syntactically valid,
209
+ // and Block Spec §5's @img example genuinely spans lines). "{...}" gets
210
+ // the stricter scanStylesEnd() instead — see there for why.
211
+ let sawParen = false;
212
+ let sawStyles = false;
213
+ while (!sawParen || !sawStyles) {
214
+ if (!sawParen && source[i] === '(') {
215
+ const parenStart = i;
216
+ const close = source.indexOf(')', i + 1);
217
+ const end = close === -1 ? n : close;
218
+ const parenEnd = close === -1 ? n : close + 1;
219
+ tokens.push({ type: 'PAREN', value: source.slice(i + 1, end), start: parenStart, end: parenEnd });
220
+ i = parenEnd;
221
+ sawParen = true;
222
+ }
223
+ else if (!sawStyles && source[i] === '{' && !(isRawFamily(nodeDef.content) && source[i + 1] === '[')) {
224
+ // "{[" is the strong-quote content opener, not a styles slot — see
225
+ // the content handling below. There's no ambiguity to resolve:
226
+ // scanStylesEnd() already treats "[" as a terminator because no
227
+ // styles value ever contains one, so "{[" could never have opened a
228
+ // valid styles slot anyway.
229
+ const stylesStart = i;
230
+ const { end, closed } = scanStylesEnd(source, i + 1);
231
+ const stylesEnd = closed ? end + 1 : end;
232
+ tokens.push({ type: 'STYLES', value: source.slice(i + 1, end), start: stylesStart, end: stylesEnd });
233
+ i = stylesEnd;
234
+ sawStyles = true;
235
+ }
236
+ else {
237
+ break;
238
+ }
239
+ }
240
+ // Void nodes (@hr, @n) take no slot at all — see registry.ts content: 'none'.
241
+ if (nodeDef.content === 'none') {
242
+ continue;
243
+ }
244
+ // Strong quote: "{[" ... "]}" runs verbatim to the first "]}", with no
245
+ // depth counting and no escapes at all. It exists because @code and
246
+ // @mermaid define no escape mechanism (Inline Spec §9), so a fenced
247
+ // block whose brackets don't balance — an EBNF grammar quoting "[" and
248
+ // "]" as terminals, say — simply had no representation and had to be
249
+ // degraded to an inline @raw, losing both its language tag and its block
250
+ // rendering. Carrying no escapes, it also emits no escape notices.
251
+ if (isRawFamily(nodeDef.content) && source[i] === '{' && source[i + 1] === '[') {
252
+ const slotStart = i;
253
+ const { text, endPos, closed } = scanStrongRaw(source, i + 2);
254
+ tokens.push({ type: 'RAW', value: text, start: slotStart, end: endPos, closed });
255
+ i = endPos;
256
+ }
257
+ else if (source[i] === '[') {
258
+ if (isRawFamily(nodeDef.content)) {
259
+ const slotStart = i;
260
+ const { text, endPos, closed, escapes } = scanRawContent(source, i + 1, nodeDef.content);
261
+ const rawTok = { type: 'RAW', value: text, start: slotStart, end: endPos, closed };
262
+ if (escapes && escapes.length > 0)
263
+ rawTok.escapes = escapes;
264
+ tokens.push(rawTok);
265
+ i = endPos;
266
+ }
267
+ else {
268
+ tokens.push({ type: 'SLOT_OPEN', value: '[', start: i, end: i + 1 });
269
+ i++;
270
+ }
271
+ }
272
+ continue;
273
+ }
274
+ if (ch === '[') {
275
+ flushText();
276
+ tokens.push({ type: 'SLOT_OPEN', value: '[', start: i, end: i + 1 });
277
+ i++;
278
+ continue;
279
+ }
280
+ if (ch === ']') {
281
+ flushText();
282
+ tokens.push({ type: 'SLOT_CLOSE', value: ']', start: i, end: i + 1 });
283
+ i++;
284
+ continue;
285
+ }
286
+ appendText(ch, i);
287
+ i++;
288
+ }
289
+ flushText();
290
+ return tokens;
291
+ }
292
+ //# sourceMappingURL=Lexer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Lexer.js","sourceRoot":"","sources":["../src/Lexer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ import type { Token } from './Lexer';
2
+ import type { DocASTNode, DocDiagnostic } from './types';
3
+ export declare class DocParser {
4
+ private tokens;
5
+ private cursor;
6
+ /** Non-fatal issues collected during parsing (e.g. an unclosed bracket, a node used in the wrong context). */
7
+ diagnostics: DocDiagnostic[];
8
+ constructor(tokens: Token[]);
9
+ /** Records a non-fatal issue without aborting the parse — see the file-level Editor Mode comment. Severity defaults to 'error' (omitted on the diagnostic itself, preserving the historical shape). */
10
+ private diagnose;
11
+ /** Best-effort position for a diagnostic when there's no specific token to blame (e.g. end-of-input). */
12
+ private cursorPos;
13
+ parse(): DocASTNode[];
14
+ private isTopLevelBlock;
15
+ private parseImplicitParagraph;
16
+ /**
17
+ * Parses one node starting at the current NODE token.
18
+ * `parentType` is the immediate containing node's type (or undefined at
19
+ * document root) — used to enforce `restrictedTo` (Widget-Blocks.md §3,
20
+ * Structural-Blocks.md §5 Table: @tab/@cols/@data are only valid inside
21
+ * their specific parent). A violation is a diagnostic, not a throw — the
22
+ * node still parses normally, just flagged as misplaced (Editor Mode).
23
+ */
24
+ private parseNode;
25
+ private parseContentByMode;
26
+ /**
27
+ * Restructures @list's flat inline content into `list-item` nodes (Block
28
+ * Syntax Specification §5 List). A line is anything between "\n" boundaries
29
+ * inside the content's string runs; a DocASTNode segment stays attached to
30
+ * whichever line it falls on.
31
+ *
32
+ * - Every non-blank line is its own item — a leading "- " is optional and
33
+ * stripped when present, purely for backward compatibility with the old
34
+ * dash-required style; it was never required to make something an item.
35
+ * - A leading "N. " / "N)" is also optional; when present it's stripped and
36
+ * kept as `marker` (only meaningful for @list(ordered), see Adapters.ts,
37
+ * letting the numbering jump/resume via <li value>).
38
+ * - A line that's nothing but a single nested `@list[...]` (plus surrounding
39
+ * whitespace) isn't a new item — it's folded into the previous item's
40
+ * content as that item's sub-list.
41
+ * - Blank lines are ignored.
42
+ */
43
+ private buildListItems;
44
+ /** Depth-aware: a literal, unpaired "[" typed as plain text (e.g. "array[0]") stays transparent instead of prematurely closing the slot. */
45
+ private parseSlotContent;
46
+ /**
47
+ * Escape-awareness feedback for @raw (Inline Syntax Specification §9) — the
48
+ * "advance notice" tier of Editor Mode. Never blocks: the content parses
49
+ * exactly as the escape rules say either way.
50
+ *
51
+ * Two tiers:
52
+ *
53
+ * - warning — the node shows swallow symptoms: it never found its closing
54
+ * "]" at all, or an escape sat at the very end of a line the content then
55
+ * ran past. The near-certain cause is an escape that consumed the "]" the
56
+ * author meant as the node's end (`@raw[@mark[hello@@]]`-style, or a
57
+ * trailing "@" fusing with the closer). Scoped to escape-at-line-end
58
+ * rather than "any newline in the content" so a deliberate multi-line
59
+ * @raw with mid-line escapes (e.g. Markdown import preserving an
60
+ * unbalanced code block) stays at the info tier.
61
+ *
62
+ * - info — every other consumed escape gets a quiet heads-up that it *is*
63
+ * an escape (a literal bracket that neither ends the node nor counts
64
+ * toward depth). This is what catches the cases no heuristic can: an
65
+ * accidental `@]` that swallows the rest of its own line still parses
66
+ * "successfully", and only the author knows it wasn't meant — the note
67
+ * tells them what the Parser did with what they wrote.
68
+ */
69
+ private diagnoseRawEscapes;
70
+ /**
71
+ * @color/@bordered's {styles} value is semantically validated here purely
72
+ * for editor feedback (Inline Syntax Specification §7 leaves token *meaning*
73
+ * to the Renderer — an unrecognized value already falls back gracefully at
74
+ * render time — but it's almost always a typo, or a missing value, the
75
+ * author would want flagged, not a silent no-op). An empty `{}` counts as
76
+ * an invalid value here too, same as a real unrecognized token — it's
77
+ * flagged right alongside the case where {styles} is missing entirely (see
78
+ * the call site above).
79
+ */
80
+ private diagnoseUnknownColorValue;
81
+ /**
82
+ * Like parseSlotContent, but for content modes that only ever hold plain text
83
+ * (currently just @meta's key=value lines). "@@" already resolves to a literal
84
+ * "@" at the Lexer level (Inline Spec §2 step 1), so it never reaches here as a
85
+ * NODE token. Void nodes (@n, content:'none') and raw-family nodes (@raw/@code/
86
+ * @kbd/..., content:'raw'/'raw-escaped'/'key'/'integer') get a narrow carve-out
87
+ * since they can't recursively contain more of the very commands this slot
88
+ * forbids. Every other @command is still invalid here, but instead of throwing
89
+ * and losing the whole document, it gets fully consumed (to keep the cursor in
90
+ * sync), silently dropped from the output, and recorded in `diagnostics` — the
91
+ * editor renders that as a squiggly + hover, the rendered doc simply doesn't
92
+ * contain it.
93
+ */
94
+ private collectRawText;
95
+ /**
96
+ * Trims leading/trailing whitespace-only string chunks off a cell's inline
97
+ * content array — the array equivalent of `str.trim()` for a mixed text/node list.
98
+ */
99
+ private trimCellEdges;
100
+ /**
101
+ * Parses @cols/@data content as comma-separated cells, each cell holding inline
102
+ * content (text plus a curated set of formatting nodes — @n, @raw/@code/@kbd/...,
103
+ * and whatever registry.ts's isCellAllowedNode() lets through, e.g. @bold/@mark/
104
+ * @link). Anything else is unsupported here: fully consumed (cursor stays in
105
+ * sync), dropped from the output, and recorded as a diagnostic — same policy as
106
+ * collectRawText, just producing structured cells instead of a flat string.
107
+ *
108
+ * Commas only split cells at this slot's own depth — a comma inside a nested
109
+ * node's own "[...]" (e.g. `@bold[a,b]`) stays literal, since that TEXT token
110
+ * is emitted while `depth > 0`.
111
+ */
112
+ private parseInlineCellList;
113
+ private parseDataRows;
114
+ private skipWhitespaceText;
115
+ /**
116
+ * Scans forward tracking SLOT_OPEN/SLOT_CLOSE depth until the bracket that
117
+ * was already opened by the caller (depth starts at 1, representing that
118
+ * "[") finds its match — used to abandon a structurally malformed construct
119
+ * (e.g. `@table` missing `@cols`/`@data`) without losing cursor sync with
120
+ * the rest of the document. Runs out cleanly at end-of-input.
121
+ */
122
+ private skipToMatchingSlotClose;
123
+ /** Like the old expectSlotOpen, but returns success instead of throwing — a missing "[" is a diagnostic, and the node is left with empty/default content. */
124
+ private trySlotOpen;
125
+ /**
126
+ * Like the old expectSlotClose, but records a diagnostic instead of
127
+ * throwing when the closing "]" is missing. Every content-collecting loop
128
+ * that calls this (parseSlotContent, parseInlineCellList, parseDataRows,
129
+ * the @table/@tabs child loops) only stops without consuming a SLOT_CLOSE
130
+ * when the token stream itself has run out — so reaching here without one
131
+ * always means end-of-input, i.e. an unclosed bracket. Editor Mode treats
132
+ * that as "auto-close at EOF" rather than aborting the whole document.
133
+ */
134
+ private closeSlot;
135
+ }
136
+ //# sourceMappingURL=Parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Parser.d.ts","sourceRoot":"","sources":["../src/Parser.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAiBzD,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,MAAM,CAAK;IAEnB,8GAA8G;IACvG,WAAW,EAAE,aAAa,EAAE,CAAM;IAEzC,YAAY,MAAM,EAAE,KAAK,EAAE,EAE1B;IAED,uMAAuM;IACvM,OAAO,CAAC,QAAQ;IAMhB,yGAAyG;IACzG,OAAO,CAAC,SAAS;IAOV,KAAK,IAAI,UAAU,EAAE,CA+B3B;IAED,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,sBAAsB;IAkC9B;;;;;;;OAOG;IACH,OAAO,CAAC,SAAS;IAoGjB,OAAO,CAAC,kBAAkB;IAmI1B;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,cAAc;IAmDtB,4IAA4I;IAC5I,OAAO,CAAC,gBAAgB;IAuCxB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,OAAO,CAAC,kBAAkB;IAwC1B;;;;;;;;;OASG;IACH,OAAO,CAAC,yBAAyB;IAUjC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,cAAc;IAqDtB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAiBrB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,mBAAmB;IA+E3B,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,kBAAkB;IAM1B;;;;;;OAMG;IACH,OAAO,CAAC,uBAAuB;IAa/B,6JAA6J;IAC7J,OAAO,CAAC,WAAW;IAUnB;;;;;;;;OAQG;IACH,OAAO,CAAC,SAAS;CAQlB"}