quikdown 1.1.0 → 1.2.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.
Files changed (58) hide show
  1. package/README.md +46 -6
  2. package/dist/quikdown.cjs +5 -5
  3. package/dist/quikdown.dark.css +1 -1
  4. package/dist/quikdown.esm.js +5 -5
  5. package/dist/quikdown.esm.min.js +2 -2
  6. package/dist/quikdown.esm.min.js.map +1 -1
  7. package/dist/quikdown.light.css +1 -1
  8. package/dist/quikdown.umd.js +5 -5
  9. package/dist/quikdown.umd.min.js +2 -2
  10. package/dist/quikdown.umd.min.js.map +1 -1
  11. package/dist/quikdown_ast.cjs +513 -0
  12. package/dist/quikdown_ast.d.ts +227 -0
  13. package/dist/quikdown_ast.esm.js +511 -0
  14. package/dist/quikdown_ast.esm.min.js +8 -0
  15. package/dist/quikdown_ast.esm.min.js.map +1 -0
  16. package/dist/quikdown_ast.umd.js +519 -0
  17. package/dist/quikdown_ast.umd.min.js +8 -0
  18. package/dist/quikdown_ast.umd.min.js.map +1 -0
  19. package/dist/quikdown_ast_html.cjs +1058 -0
  20. package/dist/quikdown_ast_html.d.ts +68 -0
  21. package/dist/quikdown_ast_html.esm.js +1056 -0
  22. package/dist/quikdown_ast_html.esm.min.js +8 -0
  23. package/dist/quikdown_ast_html.esm.min.js.map +1 -0
  24. package/dist/quikdown_ast_html.umd.js +1064 -0
  25. package/dist/quikdown_ast_html.umd.min.js +8 -0
  26. package/dist/quikdown_ast_html.umd.min.js.map +1 -0
  27. package/dist/quikdown_bd.cjs +12 -12
  28. package/dist/quikdown_bd.esm.js +12 -12
  29. package/dist/quikdown_bd.esm.min.js +2 -2
  30. package/dist/quikdown_bd.esm.min.js.map +1 -1
  31. package/dist/quikdown_bd.umd.js +12 -12
  32. package/dist/quikdown_bd.umd.min.js +2 -2
  33. package/dist/quikdown_bd.umd.min.js.map +1 -1
  34. package/dist/quikdown_edit.cjs +2297 -136
  35. package/dist/quikdown_edit.d.ts +110 -132
  36. package/dist/quikdown_edit.esm.js +2297 -136
  37. package/dist/quikdown_edit.esm.min.js +3 -4
  38. package/dist/quikdown_edit.esm.min.js.map +1 -1
  39. package/dist/quikdown_edit.umd.js +2298 -137
  40. package/dist/quikdown_edit.umd.min.js +3 -4
  41. package/dist/quikdown_edit.umd.min.js.map +1 -1
  42. package/dist/quikdown_json.cjs +556 -0
  43. package/dist/quikdown_json.d.ts +48 -0
  44. package/dist/quikdown_json.esm.js +554 -0
  45. package/dist/quikdown_json.esm.min.js +8 -0
  46. package/dist/quikdown_json.esm.min.js.map +1 -0
  47. package/dist/quikdown_json.umd.js +562 -0
  48. package/dist/quikdown_json.umd.min.js +8 -0
  49. package/dist/quikdown_json.umd.min.js.map +1 -0
  50. package/dist/quikdown_yaml.cjs +717 -0
  51. package/dist/quikdown_yaml.d.ts +51 -0
  52. package/dist/quikdown_yaml.esm.js +715 -0
  53. package/dist/quikdown_yaml.esm.min.js +8 -0
  54. package/dist/quikdown_yaml.esm.min.js.map +1 -0
  55. package/dist/quikdown_yaml.umd.js +723 -0
  56. package/dist/quikdown_yaml.umd.min.js +8 -0
  57. package/dist/quikdown_yaml.umd.min.js.map +1 -0
  58. package/package.json +92 -39
@@ -0,0 +1,556 @@
1
+ /**
2
+ * quikdown_json - JSON Markdown Parser
3
+ * @version 1.2.2
4
+ * @license BSD-2-Clause
5
+ * @copyright DeftIO 2025
6
+ */
7
+ 'use strict';
8
+
9
+ /**
10
+ * quikdown_ast - Forgiving markdown to AST parser
11
+ * Converts markdown to a structured Abstract Syntax Tree
12
+ * @param {string} markdown - The markdown source text
13
+ * @param {Object} options - Optional configuration object
14
+ * @returns {Object} - The AST object
15
+ */
16
+
17
+ // Version will be injected at build time
18
+ const quikdownVersion$1 = '1.2.2';
19
+
20
+ // Safety limit to prevent infinite loops in list parsing
21
+ const MAX_LOOP_ITERATIONS = 1000;
22
+
23
+ /**
24
+ * Parse markdown into an AST
25
+ * @param {string} markdown - The markdown source text
26
+ * @param {Object} options - Optional configuration object
27
+ * @returns {Object} - The AST object
28
+ */
29
+ function quikdown_ast(markdown, options = {}) {
30
+ if (!markdown || typeof markdown !== 'string') {
31
+ return { type: 'document', children: [] };
32
+ }
33
+
34
+ // Normalize line endings (handle CRLF, CR, LF uniformly)
35
+ const text = markdown.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
36
+
37
+ const children = parseBlocks(text);
38
+
39
+ return {
40
+ type: 'document',
41
+ children
42
+ };
43
+ }
44
+
45
+ /**
46
+ * Parse block-level elements
47
+ */
48
+ function parseBlocks(text, options) {
49
+ const blocks = [];
50
+ const lines = text.split('\n');
51
+ let i = 0;
52
+
53
+ while (i < lines.length) {
54
+ const line = lines[i];
55
+
56
+ // Empty line - skip
57
+ if (line.trim() === '') {
58
+ i++;
59
+ continue;
60
+ }
61
+
62
+ // Fenced code block (``` or ~~~)
63
+ const fenceMatch = line.match(/^(```|~~~)(.*)$/);
64
+ if (fenceMatch) {
65
+ const [, openFence, langPart] = fenceMatch;
66
+ const lang = langPart.trim();
67
+ const codeLines = [];
68
+ i++;
69
+
70
+ // Find closing fence (forgiving: accept mismatched fences or EOF)
71
+ while (i < lines.length) {
72
+ const closingMatch = lines[i].match(/^(```|~~~)\s*$/);
73
+ if (closingMatch) {
74
+ i++;
75
+ break;
76
+ }
77
+ codeLines.push(lines[i]);
78
+ i++;
79
+ }
80
+
81
+ blocks.push({
82
+ type: 'code_block',
83
+ lang: lang || null,
84
+ content: codeLines.join('\n'),
85
+ fence: openFence
86
+ });
87
+ continue;
88
+ }
89
+
90
+ // Horizontal rule
91
+ if (/^---+\s*$/.test(line) || /^\*\*\*+\s*$/.test(line) || /^___+\s*$/.test(line)) {
92
+ blocks.push({ type: 'hr' });
93
+ i++;
94
+ continue;
95
+ }
96
+
97
+ // Heading (forgiving: accept #heading without space)
98
+ const headingMatch = line.match(/^(#{1,6})\s*(.+?)\s*#*$/);
99
+ if (headingMatch) {
100
+ const [, hashes, content] = headingMatch;
101
+ blocks.push({
102
+ type: 'heading',
103
+ level: hashes.length,
104
+ children: parseInline(content)
105
+ });
106
+ i++;
107
+ continue;
108
+ }
109
+
110
+ // Table (look for separator line)
111
+ if (line.includes('|')) {
112
+ const tableResult = tryParseTable(lines, i);
113
+ if (tableResult) {
114
+ blocks.push(tableResult.node);
115
+ i = tableResult.nextIndex;
116
+ continue;
117
+ }
118
+ }
119
+
120
+ // Blockquote
121
+ if (line.match(/^>\s*/)) {
122
+ const quoteLines = [];
123
+ while (i < lines.length && lines[i].match(/^>\s*/)) {
124
+ quoteLines.push(lines[i].replace(/^>\s*/, ''));
125
+ i++;
126
+ }
127
+ blocks.push({
128
+ type: 'blockquote',
129
+ children: parseBlocks(quoteLines.join('\n'))
130
+ });
131
+ continue;
132
+ }
133
+
134
+ // List (ordered or unordered)
135
+ const listMatch = line.match(/^(\s*)([*\-+]|\d+\.)\s+(.*)$/);
136
+ if (listMatch) {
137
+ const listResult = parseList(lines, i);
138
+ blocks.push(listResult.node);
139
+ i = listResult.nextIndex;
140
+ continue;
141
+ }
142
+
143
+ // Paragraph - collect lines until empty line or block element
144
+ const paragraphLines = [];
145
+ while (i < lines.length) {
146
+ const pLine = lines[i];
147
+
148
+ // Stop on empty line
149
+ if (pLine.trim() === '') break;
150
+
151
+ // Stop on block elements
152
+ if (/^(```|~~~)/.test(pLine)) break;
153
+ if (/^#{1,6}\s/.test(pLine)) break;
154
+ if (/^---+\s*$/.test(pLine) || /^\*\*\*+\s*$/.test(pLine) || /^___+\s*$/.test(pLine)) break;
155
+ if (/^>\s*/.test(pLine)) break;
156
+ if (/^(\s*)([*\-+]|\d+\.)\s+/.test(pLine)) break;
157
+ if (pLine.includes('|') && i + 1 < lines.length && /^\|?[\s\-:|]+\|?$/.test(lines[i + 1])) break;
158
+
159
+ paragraphLines.push(pLine);
160
+ i++;
161
+ }
162
+
163
+ if (paragraphLines.length > 0) {
164
+ blocks.push({
165
+ type: 'paragraph',
166
+ children: parseInline(paragraphLines.join('\n'))
167
+ });
168
+ }
169
+ }
170
+
171
+ return blocks;
172
+ }
173
+
174
+ /**
175
+ * Try to parse a table starting at the given line
176
+ */
177
+ function tryParseTable(lines, startIndex, options) {
178
+ // Need at least 2 lines (header + separator)
179
+ if (startIndex + 1 >= lines.length) return null;
180
+
181
+ const headerLine = lines[startIndex];
182
+ const separatorLine = lines[startIndex + 1];
183
+
184
+ // Check if separator line is valid
185
+ if (!/^\|?[\s\-:|]+\|?$/.test(separatorLine) || !separatorLine.includes('-')) {
186
+ return null;
187
+ }
188
+
189
+ // Parse header
190
+ const headerCells = parseTableRow(headerLine);
191
+ if (headerCells.length === 0) return null;
192
+
193
+ // Parse alignments from separator
194
+ const separatorCells = parseTableRow(separatorLine);
195
+ const alignments = separatorCells.map(cell => {
196
+ const trimmed = cell.trim();
197
+ if (trimmed.startsWith(':') && trimmed.endsWith(':')) return 'center';
198
+ if (trimmed.endsWith(':')) return 'right';
199
+ return 'left';
200
+ });
201
+
202
+ // Parse headers with inline formatting
203
+ const headers = headerCells.map(cell => parseInline(cell.trim()));
204
+
205
+ // Parse body rows
206
+ const rows = [];
207
+ let i = startIndex + 2;
208
+ while (i < lines.length) {
209
+ const rowLine = lines[i];
210
+ if (!rowLine.includes('|') || rowLine.trim() === '') break;
211
+
212
+ const cells = parseTableRow(rowLine);
213
+ rows.push(cells.map(cell => parseInline(cell.trim())));
214
+ i++;
215
+ }
216
+
217
+ return {
218
+ node: {
219
+ type: 'table',
220
+ headers,
221
+ rows,
222
+ alignments
223
+ },
224
+ nextIndex: i
225
+ };
226
+ }
227
+
228
+ /**
229
+ * Parse a table row into cells
230
+ */
231
+ function parseTableRow(line) {
232
+ // Handle pipes at start/end or not
233
+ let trimmed = line.trim();
234
+ if (trimmed.startsWith('|')) trimmed = trimmed.slice(1);
235
+ if (trimmed.endsWith('|')) trimmed = trimmed.slice(0, -1);
236
+ return trimmed.split('|');
237
+ }
238
+
239
+ /**
240
+ * Parse a list starting at the given line
241
+ */
242
+ function parseList(lines, startIndex, options) {
243
+ const items = [];
244
+ let i = startIndex;
245
+ let loopCount = 0;
246
+
247
+ // Determine initial list type
248
+ const firstMatch = lines[i].match(/^(\s*)([*\-+]|\d+\.)\s+(.*)$/);
249
+ const isOrdered = /^\d+\./.test(firstMatch[2]);
250
+ const baseIndent = firstMatch[1].length;
251
+
252
+ while (i < lines.length && loopCount < MAX_LOOP_ITERATIONS) {
253
+ loopCount++;
254
+ const line = lines[i];
255
+ const match = line.match(/^(\s*)([*\-+]|\d+\.)\s+(.*)$/);
256
+
257
+ if (!match) break;
258
+
259
+ const [, indent, marker, content] = match;
260
+ const indentLevel = indent.length;
261
+
262
+ // If less indented than base, stop
263
+ if (indentLevel < baseIndent) break;
264
+
265
+ // If same indentation but different list type, stop
266
+ const itemIsOrdered = /^\d+\./.test(marker);
267
+ if (indentLevel === baseIndent && itemIsOrdered !== isOrdered) break;
268
+
269
+ // If more indented, it's a nested list - handle by collecting sub-lines
270
+ if (indentLevel > baseIndent) {
271
+ // This is a nested list item, collect and parse as sublist
272
+ const subLines = [];
273
+ let subLoopCount = 0;
274
+ while (i < lines.length && subLoopCount < MAX_LOOP_ITERATIONS) {
275
+ subLoopCount++;
276
+ const subLine = lines[i];
277
+ const subMatch = subLine.match(/^(\s*)([*\-+]|\d+\.)\s+/);
278
+ if (!subMatch) break;
279
+ if (subMatch[1].length < baseIndent) break;
280
+ if (subMatch[1].length === baseIndent) break;
281
+ subLines.push(subLine);
282
+ i++;
283
+ }
284
+
285
+ if (subLines.length > 0 && items.length > 0) {
286
+ // Add nested list to last item
287
+ const nestedResult = parseList(subLines, 0);
288
+ const lastItem = items[items.length - 1];
289
+ if (!lastItem.children) {
290
+ lastItem.children = [];
291
+ } else if (!Array.isArray(lastItem.children)) {
292
+ lastItem.children = [{ type: 'paragraph', children: lastItem.children }];
293
+ }
294
+ lastItem.children.push(nestedResult.node);
295
+ }
296
+ continue;
297
+ }
298
+
299
+ // Parse list item
300
+ const itemNode = {
301
+ type: 'list_item',
302
+ checked: null,
303
+ children: null
304
+ };
305
+
306
+ // Check for task list syntax
307
+ const taskMatch = content.match(/^\[([x ])\]\s*(.*)$/i);
308
+ if (taskMatch && !isOrdered) {
309
+ itemNode.checked = taskMatch[1].toLowerCase() === 'x';
310
+ itemNode.children = parseInline(taskMatch[2]);
311
+ } else {
312
+ itemNode.children = parseInline(content);
313
+ }
314
+
315
+ items.push(itemNode);
316
+ i++;
317
+ }
318
+
319
+ return {
320
+ node: {
321
+ type: 'list',
322
+ ordered: isOrdered,
323
+ items
324
+ },
325
+ nextIndex: i
326
+ };
327
+ }
328
+
329
+ /**
330
+ * Parse inline elements
331
+ */
332
+ function parseInline(text, options) {
333
+ if (!text) return [];
334
+
335
+ const nodes = [];
336
+ let remaining = text;
337
+
338
+ while (remaining.length > 0) {
339
+ let matched = false;
340
+
341
+ // Line break (1+ trailing spaces or explicit \n after processing)
342
+ // Handle inline line breaks (two spaces at end of line or backslash before newline)
343
+ const brMatch = remaining.match(/^(.+?)(?: {2}|\\\n|\n)/);
344
+ if (brMatch && remaining.includes('\n')) {
345
+ const beforeBr = remaining.indexOf('\n');
346
+ const beforeText = remaining.slice(0, beforeBr);
347
+ const afterText = remaining.slice(beforeBr + 1);
348
+
349
+ // Check if line break is significant (2+ trailing spaces or backslash)
350
+ if (beforeText.endsWith(' ') || beforeText.endsWith('\\')) {
351
+ const cleanText = beforeText.replace(/\\$/, '').replace(/ +$/, '');
352
+ if (cleanText) {
353
+ nodes.push(...parseInlineContent(cleanText));
354
+ }
355
+ nodes.push({ type: 'br' });
356
+ remaining = afterText;
357
+ matched = true;
358
+ continue;
359
+ }
360
+ }
361
+
362
+ // Images: ![alt](url)
363
+ const imgMatch = remaining.match(/^!\[([^\]]*)\]\(\s*([^)\s]+)\s*\)/);
364
+ if (imgMatch) {
365
+ nodes.push({
366
+ type: 'image',
367
+ alt: imgMatch[1],
368
+ url: imgMatch[2].trim() // Forgiving: trim whitespace in URL
369
+ });
370
+ remaining = remaining.slice(imgMatch[0].length);
371
+ matched = true;
372
+ continue;
373
+ }
374
+
375
+ // Links: [text](url)
376
+ const linkMatch = remaining.match(/^\[([^\]]+)\]\(\s*([^)\s]+)\s*\)/);
377
+ if (linkMatch) {
378
+ nodes.push({
379
+ type: 'link',
380
+ url: linkMatch[2].trim(), // Forgiving: trim whitespace in URL
381
+ children: parseInlineContent(linkMatch[1])
382
+ });
383
+ remaining = remaining.slice(linkMatch[0].length);
384
+ matched = true;
385
+ continue;
386
+ }
387
+
388
+ // Inline code: `code`
389
+ const codeMatch = remaining.match(/^`([^`]+)`/);
390
+ if (codeMatch) {
391
+ nodes.push({
392
+ type: 'code',
393
+ value: codeMatch[1]
394
+ });
395
+ remaining = remaining.slice(codeMatch[0].length);
396
+ matched = true;
397
+ continue;
398
+ }
399
+
400
+ // Bold: **text** or __text__
401
+ const boldMatch = remaining.match(/^(\*\*|__)(.+?)\1/);
402
+ if (boldMatch) {
403
+ nodes.push({
404
+ type: 'strong',
405
+ children: parseInlineContent(boldMatch[2])
406
+ });
407
+ remaining = remaining.slice(boldMatch[0].length);
408
+ matched = true;
409
+ continue;
410
+ }
411
+
412
+ // Strikethrough: ~~text~~
413
+ const strikeMatch = remaining.match(/^~~(.+?)~~/);
414
+ if (strikeMatch) {
415
+ nodes.push({
416
+ type: 'del',
417
+ children: parseInlineContent(strikeMatch[1])
418
+ });
419
+ remaining = remaining.slice(strikeMatch[0].length);
420
+ matched = true;
421
+ continue;
422
+ }
423
+
424
+ // Italic: *text* or _text_ (not at word boundary for underscores)
425
+ const emMatch = remaining.match(/^(\*|_)(?!\1)(.+?)(?<!\1)\1(?!\1)/);
426
+ if (emMatch) {
427
+ nodes.push({
428
+ type: 'em',
429
+ children: parseInlineContent(emMatch[2])
430
+ });
431
+ remaining = remaining.slice(emMatch[0].length);
432
+ matched = true;
433
+ continue;
434
+ }
435
+
436
+ // Autolinks: URLs starting with http:// or https://
437
+ const urlMatch = remaining.match(/^(https?:\/\/[^\s<>[\]]+)/);
438
+ if (urlMatch) {
439
+ nodes.push({
440
+ type: 'link',
441
+ url: urlMatch[1],
442
+ children: [{ type: 'text', value: urlMatch[1] }]
443
+ });
444
+ remaining = remaining.slice(urlMatch[0].length);
445
+ matched = true;
446
+ continue;
447
+ }
448
+
449
+ // Plain text - consume until next potential inline element or end
450
+ if (!matched) {
451
+ // Find next potential inline marker
452
+ const nextMarker = remaining.search(/[`*_~![\\n]|https?:\/\//);
453
+ if (nextMarker === -1) {
454
+ // No more markers, consume rest as text
455
+ nodes.push({ type: 'text', value: remaining });
456
+ break;
457
+ } else if (nextMarker === 0) {
458
+ // Current char is a marker but didn't match - consume it as text
459
+ nodes.push({ type: 'text', value: remaining[0] });
460
+ remaining = remaining.slice(1);
461
+ } else {
462
+ // Consume text up to next marker
463
+ nodes.push({ type: 'text', value: remaining.slice(0, nextMarker) });
464
+ remaining = remaining.slice(nextMarker);
465
+ }
466
+ }
467
+ }
468
+
469
+ // Merge adjacent text nodes
470
+ return mergeTextNodes(nodes);
471
+ }
472
+
473
+ /**
474
+ * Parse inline content (recursive helper for nested inline elements)
475
+ */
476
+ function parseInlineContent(text, options) {
477
+ // For simple nested content, use parseInline
478
+ // But handle newlines as spaces for inline content
479
+ const normalized = text.replace(/\n/g, ' ');
480
+ return parseInline(normalized);
481
+ }
482
+
483
+ /**
484
+ * Merge adjacent text nodes
485
+ */
486
+ function mergeTextNodes(nodes) {
487
+ const merged = [];
488
+ for (const node of nodes) {
489
+ if (node.type === 'text' && merged.length > 0 && merged[merged.length - 1].type === 'text') {
490
+ merged[merged.length - 1].value += node.value;
491
+ } else {
492
+ merged.push(node);
493
+ }
494
+ }
495
+ return merged;
496
+ }
497
+
498
+ // Attach version
499
+ quikdown_ast.version = quikdownVersion$1;
500
+
501
+ // Export for both CommonJS and ES6
502
+ /* istanbul ignore next */
503
+ if (typeof module !== 'undefined' && module.exports) {
504
+ module.exports = quikdown_ast;
505
+ }
506
+
507
+ // For browser global
508
+ /* istanbul ignore next */
509
+ if (typeof window !== 'undefined') {
510
+ window.quikdown_ast = quikdown_ast;
511
+ }
512
+
513
+ /**
514
+ * quikdown_json - Markdown to JSON converter
515
+ * Converts markdown to JSON via AST
516
+ * @param {string} markdown - The markdown source text
517
+ * @param {Object} options - Optional configuration object
518
+ * @param {number} options.indent - JSON indentation (default: 2)
519
+ * @returns {string} - JSON string representation of the AST
520
+ */
521
+
522
+
523
+ // Version will be injected at build time
524
+ const quikdownVersion = '1.2.2';
525
+
526
+ /**
527
+ * Convert markdown to JSON
528
+ * @param {string} markdown - The markdown source text
529
+ * @param {Object} options - Optional configuration object
530
+ * @returns {string} - JSON string
531
+ */
532
+ function quikdown_json(markdown, options = {}) {
533
+ const ast = quikdown_ast(markdown, options);
534
+ const indent = options.indent !== undefined ? options.indent : 2;
535
+ return JSON.stringify(ast, null, indent);
536
+ }
537
+
538
+ // Expose the AST parser for direct access
539
+ quikdown_json.parse = quikdown_ast;
540
+
541
+ // Attach version
542
+ quikdown_json.version = quikdownVersion;
543
+
544
+ // Export for both CommonJS and ES6
545
+ /* istanbul ignore next */
546
+ if (typeof module !== 'undefined' && module.exports) {
547
+ module.exports = quikdown_json;
548
+ }
549
+
550
+ // For browser global
551
+ /* istanbul ignore next */
552
+ if (typeof window !== 'undefined') {
553
+ window.quikdown_json = quikdown_json;
554
+ }
555
+
556
+ module.exports = quikdown_json;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * quikdown_json - Markdown to JSON Converter
3
+ * TypeScript definitions
4
+ */
5
+
6
+ declare module 'quikdown/json' {
7
+ import type { DocumentNode, QuikdownASTOptions } from 'quikdown/ast';
8
+
9
+ /**
10
+ * Options for the JSON converter
11
+ */
12
+ export interface QuikdownJSONOptions extends QuikdownASTOptions {
13
+ /**
14
+ * Number of spaces for JSON indentation
15
+ * @default 2
16
+ */
17
+ indent?: number;
18
+ }
19
+
20
+ /**
21
+ * Convert markdown to JSON string
22
+ * @param markdown - The markdown source text
23
+ * @param options - Optional configuration
24
+ * @returns JSON string representation of the AST
25
+ */
26
+ function quikdown_json(markdown: string, options?: QuikdownJSONOptions): string;
27
+
28
+ namespace quikdown_json {
29
+ /**
30
+ * Direct access to the AST parser
31
+ * @param markdown - The markdown source text
32
+ * @param options - Optional configuration
33
+ * @returns The AST document object
34
+ */
35
+ export function parse(markdown: string, options?: QuikdownASTOptions): DocumentNode;
36
+
37
+ /**
38
+ * The version of quikdown_json
39
+ */
40
+ export const version: string;
41
+ }
42
+
43
+ export = quikdown_json;
44
+ }
45
+
46
+ // For ES6 module imports
47
+ export default quikdown_json;
48
+ export { QuikdownJSONOptions };