@fuzdev/mdz 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.
Files changed (101) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +32 -0
  3. package/dist/Mdz.svelte +39 -0
  4. package/dist/Mdz.svelte.d.ts +17 -0
  5. package/dist/Mdz.svelte.d.ts.map +1 -0
  6. package/dist/MdzNodeView.svelte +140 -0
  7. package/dist/MdzNodeView.svelte.d.ts +9 -0
  8. package/dist/MdzNodeView.svelte.d.ts.map +1 -0
  9. package/dist/MdzPrecompiled.svelte +33 -0
  10. package/dist/MdzPrecompiled.svelte.d.ts +17 -0
  11. package/dist/MdzPrecompiled.svelte.d.ts.map +1 -0
  12. package/dist/MdzRoot.svelte +40 -0
  13. package/dist/MdzRoot.svelte.d.ts +14 -0
  14. package/dist/MdzRoot.svelte.d.ts.map +1 -0
  15. package/dist/MdzStream.svelte +37 -0
  16. package/dist/MdzStream.svelte.d.ts +18 -0
  17. package/dist/MdzStream.svelte.d.ts.map +1 -0
  18. package/dist/MdzStreamNodeView.svelte +150 -0
  19. package/dist/MdzStreamNodeView.svelte.d.ts +9 -0
  20. package/dist/MdzStreamNodeView.svelte.d.ts.map +1 -0
  21. package/dist/context_helpers.d.ts +23 -0
  22. package/dist/context_helpers.d.ts.map +1 -0
  23. package/dist/context_helpers.js +19 -0
  24. package/dist/mdz.d.ts +152 -0
  25. package/dist/mdz.d.ts.map +1 -0
  26. package/dist/mdz.js +61 -0
  27. package/dist/mdz_contexts.d.ts +106 -0
  28. package/dist/mdz_contexts.d.ts.map +1 -0
  29. package/dist/mdz_contexts.js +42 -0
  30. package/dist/mdz_helpers.d.ts +321 -0
  31. package/dist/mdz_helpers.d.ts.map +1 -0
  32. package/dist/mdz_helpers.js +668 -0
  33. package/dist/mdz_lexer.d.ts +123 -0
  34. package/dist/mdz_lexer.d.ts.map +1 -0
  35. package/dist/mdz_lexer.js +1405 -0
  36. package/dist/mdz_opcodes.d.ts +193 -0
  37. package/dist/mdz_opcodes.d.ts.map +1 -0
  38. package/dist/mdz_opcodes.js +14 -0
  39. package/dist/mdz_opcodes_to_nodes.d.ts +26 -0
  40. package/dist/mdz_opcodes_to_nodes.d.ts.map +1 -0
  41. package/dist/mdz_opcodes_to_nodes.js +410 -0
  42. package/dist/mdz_stream_parser.d.ts +109 -0
  43. package/dist/mdz_stream_parser.d.ts.map +1 -0
  44. package/dist/mdz_stream_parser.js +699 -0
  45. package/dist/mdz_stream_parser_block.d.ts +99 -0
  46. package/dist/mdz_stream_parser_block.d.ts.map +1 -0
  47. package/dist/mdz_stream_parser_block.js +437 -0
  48. package/dist/mdz_stream_parser_inline.d.ts +98 -0
  49. package/dist/mdz_stream_parser_inline.d.ts.map +1 -0
  50. package/dist/mdz_stream_parser_inline.js +481 -0
  51. package/dist/mdz_stream_parser_link.d.ts +29 -0
  52. package/dist/mdz_stream_parser_link.d.ts.map +1 -0
  53. package/dist/mdz_stream_parser_link.js +227 -0
  54. package/dist/mdz_stream_parser_list.d.ts +106 -0
  55. package/dist/mdz_stream_parser_list.d.ts.map +1 -0
  56. package/dist/mdz_stream_parser_list.js +438 -0
  57. package/dist/mdz_stream_parser_state.d.ts +476 -0
  58. package/dist/mdz_stream_parser_state.d.ts.map +1 -0
  59. package/dist/mdz_stream_parser_state.js +651 -0
  60. package/dist/mdz_stream_parser_text.d.ts +25 -0
  61. package/dist/mdz_stream_parser_text.d.ts.map +1 -0
  62. package/dist/mdz_stream_parser_text.js +67 -0
  63. package/dist/mdz_stream_parser_url.d.ts +76 -0
  64. package/dist/mdz_stream_parser_url.d.ts.map +1 -0
  65. package/dist/mdz_stream_parser_url.js +328 -0
  66. package/dist/mdz_stream_state.svelte.d.ts +53 -0
  67. package/dist/mdz_stream_state.svelte.d.ts.map +1 -0
  68. package/dist/mdz_stream_state.svelte.js +360 -0
  69. package/dist/mdz_to_svelte.d.ts +71 -0
  70. package/dist/mdz_to_svelte.d.ts.map +1 -0
  71. package/dist/mdz_to_svelte.js +127 -0
  72. package/dist/mdz_token_parser.d.ts +20 -0
  73. package/dist/mdz_token_parser.d.ts.map +1 -0
  74. package/dist/mdz_token_parser.js +449 -0
  75. package/dist/svelte_preprocess_mdz.d.ts +80 -0
  76. package/dist/svelte_preprocess_mdz.d.ts.map +1 -0
  77. package/dist/svelte_preprocess_mdz.js +543 -0
  78. package/dist/tsdoc_mdz.d.ts +45 -0
  79. package/dist/tsdoc_mdz.d.ts.map +1 -0
  80. package/dist/tsdoc_mdz.js +88 -0
  81. package/package.json +131 -0
  82. package/src/lib/context_helpers.ts +52 -0
  83. package/src/lib/mdz.ts +190 -0
  84. package/src/lib/mdz_contexts.ts +99 -0
  85. package/src/lib/mdz_helpers.ts +727 -0
  86. package/src/lib/mdz_lexer.ts +1761 -0
  87. package/src/lib/mdz_opcodes.ts +227 -0
  88. package/src/lib/mdz_opcodes_to_nodes.ts +470 -0
  89. package/src/lib/mdz_stream_parser.ts +766 -0
  90. package/src/lib/mdz_stream_parser_block.ts +490 -0
  91. package/src/lib/mdz_stream_parser_inline.ts +527 -0
  92. package/src/lib/mdz_stream_parser_link.ts +283 -0
  93. package/src/lib/mdz_stream_parser_list.ts +525 -0
  94. package/src/lib/mdz_stream_parser_state.ts +957 -0
  95. package/src/lib/mdz_stream_parser_text.ts +95 -0
  96. package/src/lib/mdz_stream_parser_url.ts +386 -0
  97. package/src/lib/mdz_stream_state.svelte.ts +383 -0
  98. package/src/lib/mdz_to_svelte.ts +213 -0
  99. package/src/lib/mdz_token_parser.ts +544 -0
  100. package/src/lib/svelte_preprocess_mdz.ts +777 -0
  101. package/src/lib/tsdoc_mdz.ts +97 -0
@@ -0,0 +1,283 @@
1
+ /**
2
+ * Markdown link `[text](url)` handlers and HTML-style tag handlers
3
+ * (`<tag>`, `<Tag />`, `</tag>`) for the streaming mdz parser.
4
+ *
5
+ * @module
6
+ */
7
+
8
+ import type {MdzNodeTypeContainer} from './mdz_opcodes.js';
9
+ import {
10
+ A_UPPER,
11
+ LEFT_BRACKET,
12
+ LEFT_PAREN,
13
+ NEWLINE,
14
+ RIGHT_ANGLE,
15
+ RIGHT_BRACKET,
16
+ RIGHT_PAREN,
17
+ SLASH,
18
+ SPACE,
19
+ Z_UPPER,
20
+ is_letter,
21
+ is_tag_name_char,
22
+ is_valid_path_char,
23
+ mdz_is_safe_reference,
24
+ mdz_is_url,
25
+ } from './mdz_helpers.js';
26
+ import {
27
+ type MdzStreamParserState,
28
+ type TryResult,
29
+ accumulate_text,
30
+ alloc_id,
31
+ emit,
32
+ ensure_paragraph,
33
+ flush_text,
34
+ is_run_boundary,
35
+ offset,
36
+ pop_stack_entry,
37
+ push_stack_entry,
38
+ revert_above,
39
+ } from './mdz_stream_parser_state.js';
40
+
41
+ // -- Links --
42
+
43
+ /** @nodocs */
44
+ export const try_link_open = (state: MdzStreamParserState): boolean => {
45
+ flush_text(state);
46
+ ensure_paragraph(state);
47
+
48
+ const id = alloc_id(state);
49
+ const link_start = offset(state);
50
+ emit(state, {type: 'open', id, node_type: 'Link', start: link_start});
51
+ push_stack_entry(state, id, 'Link', link_start, '[');
52
+ state.active_text_id = null;
53
+ state.pos++;
54
+ state.column++;
55
+ state.prev_char = LEFT_BRACKET;
56
+ return true;
57
+ };
58
+
59
+ /**
60
+ * Revert an optimistic Link container to its literal `[` and consume the
61
+ * `]` at `bracket_pos` as text. Used whenever a `]` doesn't form a valid
62
+ * `[text](url)` — missing `(`, empty url, invalid url char, etc.
63
+ *
64
+ * @nodocs
65
+ */
66
+ export const abort_link_to_text = (
67
+ state: MdzStreamParserState,
68
+ link_stack_idx: number,
69
+ bracket_pos: number,
70
+ ): void => {
71
+ flush_text(state);
72
+ revert_above(state, link_stack_idx);
73
+ const entry = pop_stack_entry(state);
74
+ emit(state, {type: 'revert', id: entry.id, replacement_text: '[', start: entry.start});
75
+ state.active_text_id = null;
76
+ accumulate_text(state, ']', offset(state, bracket_pos));
77
+ state.pos = bracket_pos + 1;
78
+ state.column++;
79
+ state.prev_char = RIGHT_BRACKET;
80
+ };
81
+
82
+ /**
83
+ * Try to complete a link after seeing `]`.
84
+ * Returns false if more input is needed (leaves pos at `]`).
85
+ *
86
+ * @nodocs
87
+ */
88
+ export const try_complete_link = (state: MdzStreamParserState, link_stack_idx: number): boolean => {
89
+ const bracket_pos = state.pos;
90
+
91
+ // need at least one char after ]
92
+ if (bracket_pos + 1 >= state.buffer.length) return false;
93
+
94
+ const after_bracket = state.buffer.charCodeAt(bracket_pos + 1);
95
+ if (after_bracket !== LEFT_PAREN) {
96
+ abort_link_to_text(state, link_stack_idx, bracket_pos);
97
+ return true;
98
+ }
99
+
100
+ // found ]( — scan for )
101
+ let i = bracket_pos + 2; // past ](
102
+ while (i < state.buffer.length) {
103
+ const c = state.buffer.charCodeAt(i);
104
+ if (c === RIGHT_PAREN) {
105
+ const reference = state.buffer.slice(bracket_pos + 2, i);
106
+ // validate reference: non-empty and only valid path chars
107
+ if (!reference.trim()) {
108
+ abort_link_to_text(state, link_stack_idx, bracket_pos);
109
+ return true;
110
+ }
111
+ let valid = true;
112
+ for (let j = 0; j < reference.length; j++) {
113
+ if (!is_valid_path_char(reference.charCodeAt(j))) {
114
+ valid = false;
115
+ break;
116
+ }
117
+ }
118
+ if (!valid) {
119
+ abort_link_to_text(state, link_stack_idx, bracket_pos);
120
+ return true;
121
+ }
122
+ // Reject unsafe protocols (javascript:, data:, etc.) at parse time.
123
+ // `is_valid_path_char` permits `:` so we have to filter explicitly.
124
+ if (!mdz_is_safe_reference(reference)) {
125
+ abort_link_to_text(state, link_stack_idx, bracket_pos);
126
+ return true;
127
+ }
128
+
129
+ // success — close the link with reference
130
+ flush_text(state);
131
+ revert_above(state, link_stack_idx);
132
+ const entry = pop_stack_entry(state);
133
+ const link_type = mdz_is_url(reference) ? 'external' : 'internal';
134
+ emit(state, {
135
+ type: 'close',
136
+ id: entry.id,
137
+ end: offset(state, i + 1),
138
+ reference,
139
+ link_type,
140
+ });
141
+ state.active_text_id = null;
142
+ state.pos = i + 1;
143
+ state.column += i + 1 - bracket_pos;
144
+ state.prev_char = RIGHT_PAREN;
145
+ return true;
146
+ }
147
+ if (c === NEWLINE || c === SPACE) {
148
+ // invalid character in URL (simplified check)
149
+ break;
150
+ }
151
+ i++;
152
+ }
153
+
154
+ // didn't find ) — need more input or invalid
155
+ if (i >= state.buffer.length) return false; // need more input
156
+
157
+ // found invalid char before ) — revert
158
+ abort_link_to_text(state, link_stack_idx, bracket_pos);
159
+ return true;
160
+ };
161
+
162
+ // -- Tags --
163
+
164
+ /** @nodocs */
165
+ export const try_tag_open = (state: MdzStreamParserState): TryResult => {
166
+ const start = state.pos;
167
+ let i = start + 1; // past <
168
+
169
+ // tag name must start with letter. A `<` at the end of the buffer can't
170
+ // classify yet — it may be a tag open, or the closing tag of an open
171
+ // element (whose `</` dispatch needs the next char); consuming it as text
172
+ // here would eat the closer and strand the element. Hold, like the
173
+ // mid-name case below.
174
+ if (i >= state.buffer.length) return 'need_more';
175
+ if (!is_letter(state.buffer.charCodeAt(i))) {
176
+ return 'not_match';
177
+ }
178
+
179
+ // collect tag name
180
+ const name_start = i;
181
+ while (i < state.buffer.length && is_tag_name_char(state.buffer.charCodeAt(i))) {
182
+ i++;
183
+ }
184
+ if (i >= state.buffer.length) return 'need_more';
185
+
186
+ const name = state.buffer.slice(name_start, i);
187
+
188
+ // skip whitespace
189
+ while (i < state.buffer.length && state.buffer.charCodeAt(i) === SPACE) {
190
+ i++;
191
+ }
192
+ if (i >= state.buffer.length) return 'need_more';
193
+
194
+ // check for self-closing />
195
+ if (state.buffer.charCodeAt(i) === SLASH && i + 1 >= state.buffer.length) {
196
+ return 'need_more'; // `/` at the buffer end can't classify yet (`/>` or junk)
197
+ }
198
+ if (state.buffer.charCodeAt(i) === SLASH && state.buffer.charCodeAt(i + 1) === RIGHT_ANGLE) {
199
+ const first_char = name.charCodeAt(0);
200
+ const is_component = first_char >= A_UPPER && first_char <= Z_UPPER;
201
+ const node_type: MdzNodeTypeContainer = is_component ? 'Component' : 'Element';
202
+
203
+ flush_text(state);
204
+ ensure_paragraph(state);
205
+ const id = alloc_id(state);
206
+ const tag_start = offset(state, start);
207
+ emit(state, {type: 'open', id, node_type, start: tag_start, name});
208
+ emit(state, {type: 'close', id, end: offset(state, i + 2)});
209
+ state.active_text_id = null;
210
+ state.pos = i + 2;
211
+ state.column += i + 2 - start;
212
+ state.prev_char = RIGHT_ANGLE;
213
+ return 'consumed';
214
+ }
215
+
216
+ // check for >
217
+ if (state.buffer.charCodeAt(i) !== RIGHT_ANGLE) {
218
+ return 'not_match';
219
+ }
220
+ i++; // past >
221
+
222
+ const first_char = name.charCodeAt(0);
223
+ const is_component = first_char >= A_UPPER && first_char <= Z_UPPER;
224
+ const node_type: MdzNodeTypeContainer = is_component ? 'Component' : 'Element';
225
+
226
+ flush_text(state);
227
+ ensure_paragraph(state);
228
+ const id = alloc_id(state);
229
+ const tag_start = offset(state, start);
230
+ const delimiter = state.buffer.slice(start, i); // e.g., "<Alert>"
231
+ emit(state, {type: 'open', id, node_type, start: tag_start, name});
232
+ push_stack_entry(state, id, node_type, tag_start, delimiter, name);
233
+ state.active_text_id = null;
234
+ state.pos = i;
235
+ state.column += i - start;
236
+ state.prev_char = RIGHT_ANGLE;
237
+ return 'consumed';
238
+ };
239
+
240
+ /** @nodocs */
241
+ export const try_close_tag = (state: MdzStreamParserState): TryResult => {
242
+ // we're at </
243
+ let i = state.pos + 2; // past </
244
+
245
+ if (i >= state.buffer.length) return 'need_more';
246
+
247
+ // collect tag name
248
+ const name_start = i;
249
+ while (i < state.buffer.length && is_tag_name_char(state.buffer.charCodeAt(i))) {
250
+ i++;
251
+ }
252
+ if (i >= state.buffer.length) return 'need_more';
253
+ if (state.buffer.charCodeAt(i) !== RIGHT_ANGLE) return 'not_match';
254
+
255
+ const name = state.buffer.slice(name_start, i);
256
+ i++; // past >
257
+
258
+ // find matching open tag on stack
259
+ let found_idx = -1;
260
+ for (let j = state.stack.length - 1; j >= 0; j--) {
261
+ const entry = state.stack[j]!;
262
+ if (
263
+ (entry.node_type === 'Element' || entry.node_type === 'Component') &&
264
+ entry.tag_name === name
265
+ ) {
266
+ found_idx = j;
267
+ break;
268
+ }
269
+ if (is_run_boundary(entry.node_type)) break;
270
+ }
271
+
272
+ if (found_idx === -1) return 'not_match';
273
+
274
+ flush_text(state);
275
+ revert_above(state, found_idx);
276
+ const entry = pop_stack_entry(state);
277
+ emit(state, {type: 'close', id: entry.id, end: offset(state, i)});
278
+ state.active_text_id = null;
279
+ state.column += i - state.pos;
280
+ state.pos = i;
281
+ state.prev_char = RIGHT_ANGLE;
282
+ return 'consumed';
283
+ };