@tabnas/markdown 0.4.1 → 0.5.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/markdown.js CHANGED
@@ -1,597 +1,131 @@
1
1
  "use strict";
2
- /* Copyright (c) 2021-2025 Richard Rodger, MIT License */
2
+ /* Copyright (c) 2021-2026 Richard Rodger, MIT License */
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.Markdown = void 0;
5
- exports.buildMarkdownStringMatcher = buildMarkdownStringMatcher;
6
- // The engine is the tabnas parser; jsonic supplies the relaxed-JSON
7
- // grammar that the embedded grammar text is authored in.
8
- const parser_1 = require("@tabnas/parser");
9
- const jsonic_1 = require("@tabnas/jsonic");
4
+ exports.renderHTML = exports.MdNode = exports.grammarText = exports.Markdown = void 0;
5
+ exports.parseDocument = parseDocument;
6
+ exports.parseInline = parseInline;
7
+ exports.toHtml = toHtml;
8
+ exports.parseTree = parseTree;
9
+ const commonmark_ts_1 = require("./commonmark.js");
10
+ const ast_ts_1 = require("./ast.js");
11
+ const html_ts_1 = require("./html.js");
12
+ const options_ts_1 = require("./options.js");
13
+ // ---------------------------------------------------------------------------
14
+ // Grammar source.
15
+ //
16
+ // The prose grammar is intentionally trivial: block structure is decided by
17
+ // the line-oriented algorithm in `block.ts`, not by declarative alts, so the
18
+ // `markdown` rule exists only to consume the token stream. The file is kept
19
+ // because `ts/embed-grammar.js` embeds it verbatim into both runtimes; see
20
+ // AGENTS.md. It is documentation of the entry rule, not a source of behaviour.
10
21
  // --- BEGIN EMBEDDED markdown-grammar.jsonic ---
11
22
  const grammarText = `
12
- # Markdown Grammar Definition
13
- # Parsed by a standard Jsonic instance and passed to jsonic.grammar()
14
- # Function references (@ prefixed) are resolved against the refs map
23
+ # Markdown entry rule — CommonMark 0.31.2
15
24
  #
16
- # Token naming:
17
- # #LN - line ending (removed from per-instance IGNORE set)
18
- # #SP - whitespace (removed from per-instance IGNORE set in strict mode)
19
- # #CA - comma / field separator
20
- # #ZZ - end of input
21
- # #VAL - token set: text, string, number, value literals
25
+ # This grammar is deliberately trivial, and it is NOT where the parser
26
+ # lives. Block structure is decided by the two-phase line algorithm of
27
+ # spec Appendix A, implemented in block.ts / block.go, and inline
28
+ # structure by the delimiter and bracket stacks in inline.ts / inline.go.
29
+ # None of that is expressible as declarative alts, which is why none of
30
+ # it is here.
22
31
  #
23
- # Rules markdown, newline, record, text are fully defined here.
24
- # Rules list, elem, val are modified in code (strict mode defines from scratch;
25
- # non-strict prepends to existing defaults to preserve JSON parsing).
26
-
32
+ # The markdown rule exists only to give the engine an entry point and to
33
+ # consume the token stream so its trailing-content check passes. The bo
34
+ # action reads the whole source via ctx.src() and hands it to the parser.
35
+ # Everything the rule does is in those two lines below.
36
+ #
37
+ # Consequences worth knowing rather than discovering:
38
+ # - The railroad diagram generated from this file is empty: a bare
39
+ # track with no boxes on it. That is accurate, not a rendering fault.
40
+ # - Editing this file changes documentation, not behaviour. The one
41
+ # exception is the open/close alts, which really are the rule.
42
+ #
43
+ # The file is kept because ts/embed-grammar.js embeds it verbatim into
44
+ # both runtimes as grammarText (see AGENTS.md). It may not contain
45
+ # backticks: the Go copy is a raw string literal.
27
46
  {
28
47
  rule: markdown: open: [
29
48
  { s: '#ZZ' }
30
- { s: '#LN' p: newline c: '@not-record-empty' }
31
- { p: record }
32
- ]
33
-
34
- rule: newline: open: [
35
- { s: '#LN #LN' r: newline }
36
- { s: '#LN' r: newline }
37
- { s: '#ZZ' }
38
- { r: record }
39
- ]
40
- rule: newline: close: [
41
- { s: '#LN #LN' r: newline }
42
- { s: '#LN' r: newline }
43
- { s: '#ZZ' }
44
- { r: record }
45
- ]
46
-
47
- rule: record: open: [
48
- { p: list }
49
49
  ]
50
- rule: record: close: [
50
+ rule: markdown: close: [
51
51
  { s: '#ZZ' }
52
- { s: '#LN #ZZ' b: 1 }
53
- { s: '#LN' r: '@record-close-next' }
54
- ]
55
-
56
- rule: text: open: [
57
- { s: ['#VAL' '#SP'] b: 1 r: text n: { text: 1 } g: 'markdown,space,follows' a: '@text-follows' }
58
- { s: ['#SP' '#VAL'] r: text n: { text: 1 } g: 'markdown,space,leads' a: '@text-leads' }
59
- { s: ['#SP' '#CA #LN #ZZ'] b: 1 n: { text: 1 } g: 'markdown,end' a: '@text-end' }
60
- { s: '#SP' n: { text: 1 } g: 'markdown,space' a: '@text-space' p: '@text-space-push' }
61
- {}
62
52
  ]
63
53
  }
64
54
  `;
55
+ exports.grammarText = grammarText;
65
56
  // --- END EMBEDDED markdown-grammar.jsonic ---
66
- // Plugin implementation.
57
+ // ---------------------------------------------------------------------------
58
+ // Public parse API (engine-free)
59
+ /** Parse Markdown to the mdast-adjacent JSON AST. */
60
+ function parseDocument(src, opts) {
61
+ const options = (0, options_ts_1.resolveOptions)(opts);
62
+ return (0, ast_ts_1.toAst)((0, commonmark_ts_1.parse)(src, options), options);
63
+ }
64
+ /** Parse a single run of inline Markdown to an `Inline[]`. */
65
+ function parseInline(text, opts) {
66
+ const doc = parseDocument(text, opts);
67
+ const first = doc.children[0];
68
+ return first && 'paragraph' === first.type ? first.children : [];
69
+ }
70
+ /** Parse Markdown and render it to CommonMark-conformant HTML. */
71
+ function toHtml(src, opts) {
72
+ const options = (0, options_ts_1.resolveOptions)(opts);
73
+ return (0, html_ts_1.renderHTML)((0, commonmark_ts_1.parse)(src, options), options);
74
+ }
75
+ /** Parse Markdown to the native CommonMark node tree. */
76
+ function parseTree(src, opts) {
77
+ return (0, commonmark_ts_1.parse)(src, (0, options_ts_1.resolveOptions)(opts));
78
+ }
79
+ // ---------------------------------------------------------------------------
80
+ // Plugin wiring
81
+ //
82
+ // The `markdown` rule's `bo` action reads the whole source via `ctx.src()` and
83
+ // hands it to the parser; the alts then consume the token stream so the
84
+ // engine's trailing-content check (lex must end at #ZZ) passes. `#AA` is the
85
+ // ANY-token wildcard and `r:'markdown'` loops at the same depth, consuming one
86
+ // token per iteration until only #ZZ remains.
67
87
  const Markdown = (tn, options) => {
68
- // Human descriptions for the tokens, surfaced in railroad diagram legends
69
- // (read off the live config by @tabnas/railroad). Newline and whitespace are
70
- // structurally significant (record separator / field text); the JSON
71
- // brace/bracket tokens only appear inside embedded jsonic field values.
88
+ const opts = (0, options_ts_1.resolveOptions)(options);
89
+ tn.options({ rule: { start: 'markdown' } });
90
+ // The parser reads `ctx.src()` directly rather than the token stream, so
91
+ // disable the lexers that would corrupt Markdown syntax before it gets
92
+ // there: backtick code spans lex as unterminated strings, `# heading` as a
93
+ // comment, and `1. list` as a number.
72
94
  tn.options({
73
- config: {
74
- modify: {
75
- 'markdown-tokendesc': (cfg) => {
76
- cfg.tokenDesc = Object.assign(cfg.tokenDesc || {}, {
77
- '#LN': 'newline (ends a record / row)',
78
- '#SP': 'whitespace (significant: field text)',
79
- '#OB': 'open brace { (embedded JSON map)',
80
- '#CB': 'close brace } (embedded JSON map)',
81
- '#OS': 'open bracket [ (embedded JSON list)',
82
- '#CS': 'close bracket ] (embedded JSON list)',
83
- '#CL': 'colon : (key:value in embedded JSON)',
84
- 'KEY': 'embedded JSON map key',
85
- 'VAL': 'field value: text, number, string, or keyword',
86
- });
87
- },
88
- },
89
- },
95
+ string: { lex: false },
96
+ comment: { lex: false },
97
+ number: { lex: false },
98
+ value: { lex: false },
99
+ lex: { emptyResult: { type: 'document', children: [] } },
90
100
  });
91
- // Normalize boolean options.
92
- const strict = !!options.strict;
93
- const objres = !!options.object;
94
- const header = !!options.header;
95
- // These may be changed below by superior options.
96
- let trim = !!options.trim;
97
- let comment = !!options.comment;
98
- let opt_number = !!options.number;
99
- let opt_value = !!options.value;
100
- let record_empty = !!options.record?.empty;
101
- const stream = options.stream;
102
- // In strict mode, Jsonic field content is not parsed.
103
- if (strict) {
104
- if (false !== options.string.markdown) {
105
- tn.options({
106
- lex: {
107
- match: {
108
- stringmarkdown: { order: 1e5, make: buildMarkdownStringMatcher(options) },
109
- },
110
- },
111
- });
112
- }
113
- tn.options({
114
- rule: { exclude: 'jsonic,imp' },
115
- });
116
- }
117
- // Fields may contain Jsonic content.
118
- else {
119
- if (true === options.string.markdown) {
120
- tn.options({
121
- lex: {
122
- match: {
123
- stringmarkdown: { order: 1e5, make: buildMarkdownStringMatcher(options) },
124
- },
125
- },
126
- });
127
- }
128
- trim = null === options.trim ? true : trim;
129
- comment = null === options.comment ? true : comment;
130
- opt_number = null === options.number ? true : opt_number;
131
- opt_value = null === options.value ? true : opt_value;
132
- tn.options({
133
- rule: { exclude: 'imp' },
134
- });
135
- }
136
- // Stream rows as they are parsed, do not store in result.
137
- if (stream) {
138
- let parser = tn.internal().parser;
139
- let origStart = parser.start.bind(parser);
140
- parser.start = ((...args) => {
141
- try {
142
- return origStart(...args);
143
- }
144
- catch (e) {
145
- stream('error', e);
146
- }
147
- });
148
- }
149
- let token = {};
150
- if (strict) {
151
- // Disable JSON structure tokens
152
- token = {
153
- '#OB': null,
154
- '#CB': null,
155
- '#OS': null,
156
- '#CS': null,
157
- '#CL': null,
158
- };
159
- }
160
- // Custom "comma"
161
- if (options.field.separation) {
162
- token['#CA'] = options.field.separation;
163
- }
164
- // Jsonic option overrides.
165
- let jsonicOptions = {
166
- rule: {
167
- start: 'markdown',
168
- },
169
- fixed: {
170
- token,
171
- },
172
- tokenSet: {
173
- IGNORE: [
174
- strict ? null : undefined, // Handle #SP space
175
- null, // Handle #LN newlines
176
- undefined, // Still ignore #CM comments
177
- ],
178
- },
179
- number: {
180
- lex: opt_number,
181
- },
182
- value: {
183
- lex: opt_value,
184
- },
185
- comment: {
186
- lex: comment,
187
- },
188
- lex: {
189
- emptyResult: [],
190
- },
191
- line: {
192
- single: record_empty,
193
- chars: null == options.record.separators
194
- ? undefined
195
- : options.record.separators,
196
- rowChars: null == options.record.separators
197
- ? undefined
198
- : options.record.separators,
199
- },
200
- error: {
201
- markdown_extra_field: 'unexpected extra field value: $fsrc',
202
- markdown_missing_field: 'missing field',
203
- },
204
- hint: {
205
- markdown_extra_field: `Row $row has too many fields (the first of which is: $fsrc). Only $len
206
- fields per row are expected.`,
207
- markdown_missing_field: `Row $row has too few fields. $len fields per row are expected.`,
208
- },
209
- };
210
- tn.options(jsonicOptions);
211
- // Named function references for declarative grammar definition.
212
101
  const refs = {
213
- // === State actions (auto-wired by @rulename-{bo,ao,bc,ac} convention) ===
214
102
  '@markdown-bo': (r, ctx) => {
215
- ctx.u.recordI = 0;
216
- stream && stream('start');
217
- r.node = [];
218
- },
219
- '@markdown-ac': (_r) => {
220
- stream && stream('end');
221
- },
222
- '@record-bc': (r, ctx) => {
223
- let fields = ctx.u.fields || options.field.names;
224
- if (0 === ctx.u.recordI && header) {
225
- ctx.u.fields = undefined === r.child.node ? [] : r.child.node;
226
- }
227
- else {
228
- let record = r.child.node || [];
229
- if (objres) {
230
- let obj = {};
231
- let i = 0;
232
- if (fields) {
233
- if (options.field.exact) {
234
- if (record.length !== fields.length) {
235
- return ctx.t0.bad(record.length > fields.length
236
- ? 'markdown_extra_field'
237
- : 'markdown_missing_field');
238
- }
239
- }
240
- let fI = 0;
241
- for (; fI < fields.length; fI++) {
242
- obj[fields[fI]] =
243
- undefined === record[fI] ? options.field.empty : record[fI];
244
- }
245
- i = fI;
246
- }
247
- for (; i < record.length; i++) {
248
- let field_name = options.field.nonameprefix + i;
249
- obj[field_name] =
250
- undefined === record[i] ? options.field.empty : record[i];
251
- }
252
- record = obj;
253
- }
254
- else {
255
- for (let i = 0; i < record.length; i++) {
256
- record[i] =
257
- undefined === record[i] ? options.field.empty : record[i];
258
- }
259
- }
260
- if (stream) {
261
- stream('record', record);
262
- }
263
- else {
264
- r.node.push(record);
265
- }
266
- }
267
- ctx.u.recordI++;
268
- },
269
- '@text-bc': (r) => {
270
- r.parent.node = undefined === r.child.node ? r.node : r.child.node;
271
- },
272
- // === Alt actions ===
273
- '@elem-open-empty': (r) => {
274
- r.node.push(options.field.empty);
275
- r.u.done = true;
103
+ const src = ctx.src();
104
+ r.node = parseDocument(src, opts);
276
105
  },
277
- '@elem-close-trailing': (r) => {
278
- r.node.push(options.field.empty);
279
- },
280
- '@text-follows': (r) => {
281
- let v = 1 === r.n.text ? r : r.prev;
282
- r.node = v.node = (1 === r.n.text ? '' : r.prev.node) + r.o0.val;
283
- },
284
- '@text-leads': (r) => {
285
- let v = 1 === r.n.text ? r : r.prev;
286
- r.node = v.node =
287
- (1 === r.n.text ? '' : r.prev.node) +
288
- (2 <= r.n.text || !trim ? r.o0.src : '') +
289
- r.o1.src;
290
- },
291
- '@text-end': (r) => {
292
- let v = 1 === r.n.text ? r : r.prev;
293
- r.node = v.node =
294
- (1 === r.n.text ? '' : r.prev.node) + (!trim ? r.o0.src : '');
295
- },
296
- '@text-space': (r) => {
297
- if (strict) {
298
- let v = 1 === r.n.text ? r : r.prev;
299
- r.node = v.node =
300
- (1 === r.n.text ? '' : r.prev.node) + (!trim ? r.o0.src : '');
301
- }
302
- },
303
- // === Condition refs ===
304
- '@not-record-empty': () => !record_empty,
305
- // === FuncRef for dynamic rule names ===
306
- '@record-close-next': () => record_empty ? 'record' : 'newline',
307
- '@text-space-push': () => strict ? '' : 'val',
308
106
  };
309
- // Usually [#TX, #ST, #NR, #VL]
310
- let VAL = tn.tokenSet.VAL;
311
- let { LN, CA, SP, ZZ } = tn.token;
312
- // Parse embedded grammar definition with a jsonic-grammar Tabnas instance.
313
- const grammarDef = new parser_1.Tabnas().use(jsonic_1.jsonic).parse(grammarText);
314
- grammarDef.ref = refs;
315
- tn.grammar(grammarDef);
316
- // Rules list, elem, val are modified in code rather than the grammar file,
317
- // because in non-strict mode the default jsonic alternatives must be
318
- // preserved to support embedded JSON values like [1,2] and {x:1}.
319
- //
320
- // In STRICT mode the rules are rebuilt from scratch (clear()): the new
321
- // node-building contract makes the jsonic defaults accumulate via child$
322
- // and the info marker, which flattens records and produces `[object
323
- // Object]` keys. Each rule then owns its node — allocate in `bo`,
324
- // coalesce in `bc`. This mirrors the Go port (markdown.go list/elem/val),
325
- // which already passes against the new core.
326
- //
327
- // In NON-STRICT mode the jsonic open/close alternatives are kept (so the
328
- // embedded JSON structural tokens `[`/`]`/`{`/`}` still parse). The
329
- // markdown record alternates are prepended (record/field handling wins
330
- // for top-level rows) with an unconditional `elem`/`val` fallback
331
- // appended after the jsonic alts (so jsonic's `#OS`/`#CS` etc. are tried
332
- // first for embedded containers). The corrupting jsonic lifecycle
333
- // bo/bc actions are replaced with clean, record-aware versions.
334
- if (strict) {
335
- tn.rule('list', (rs) => {
336
- return rs
337
- .clear()
338
- // Allocate the record's field array; the parent (record) reads it
339
- // back from r.child.node in @record-bc.
340
- .bo((r) => {
341
- r.node = [];
342
- })
343
- .open([
344
- // If not ignoring empty fields, don't consume LN used to close empty record.
345
- { s: [LN], b: 1 },
346
- // Parse each field as an element.
347
- { p: 'elem' },
348
- ])
349
- .close([
350
- // LN ends record
351
- { s: [LN], b: 1 },
352
- { s: [ZZ] },
353
- ]);
354
- });
355
- tn.rule('elem', (rs) => {
356
- return rs
357
- .clear()
358
- .open([
359
- // An empty element (`,` with nothing before it).
360
- {
361
- s: [CA],
362
- b: 1,
363
- a: (r) => {
364
- r.node.push(options.field.empty);
365
- r.u.done = true;
366
- },
367
- },
368
- // Otherwise parse a field value.
369
- { p: 'val' },
370
- ])
371
- .close([
372
- // An empty element at the end of the line / input.
373
- {
374
- s: [CA, [LN, ZZ]],
375
- b: 1,
376
- a: (r) => r.node.push(options.field.empty),
377
- },
378
- // Next element.
379
- { s: [CA], r: 'elem' },
380
- // LN ends record
381
- { s: [LN], b: 1 },
382
- // ZZ ends input
383
- { s: [ZZ] },
384
- ])
385
- // Push the parsed field value, unless an open alt already handled it
386
- // (done flag) or there was no value.
387
- .bc((r) => {
388
- if (true !== r.u.done && undefined !== r.child.node) {
389
- r.node.push(r.child.node);
390
- }
391
- });
392
- });
393
- tn.rule('val', (rs) => {
394
- return rs
395
- .clear()
396
- // A value rule owns its node; start undefined so bc can tell whether
397
- // a child / token supplied a value (implicit-null otherwise).
398
- .bo((r) => {
399
- r.node = undefined;
400
- })
401
- .open([
402
- // Handle text and space concatenation.
403
- { s: [VAL, SP], b: 2, p: 'text' },
404
- { s: [SP], b: 1, p: 'text' },
405
- // A plain value token.
406
- { s: [VAL] },
407
- // LN ends record
408
- { s: [LN], b: 1 },
409
- ])
410
- // Coalesce: child value > matched token > implicit null (undefined).
411
- .bc((r, ctx) => {
412
- if (undefined === r.node) {
413
- if (undefined !== r.child.node) {
414
- r.node = r.child.node;
415
- }
416
- else if (0 !== r.os) {
417
- r.node = r.o0.resolveVal(r, ctx);
418
- }
419
- }
420
- });
421
- });
422
- }
423
- else {
424
- // Non-strict: keep the jsonic/json alternatives (embedded containers),
425
- // layer the markdown record alternates around them.
426
- tn.rule('list', (rs) => {
427
- return rs
428
- // Record context allocates its own clean field array. For an
429
- // embedded `[...]`, json's @array$ open-alt re-allocates, so this is
430
- // harmless there. Replace jsonic's list bo (dmap/implist + info
431
- // marker) which would otherwise corrupt the record node.
432
- .clearActions('bo', 'bc')
433
- .bo((r) => {
434
- r.node = [];
435
- })
436
- // Don't consume the LN that closes an (empty) record.
437
- .open([{ s: [LN], b: 1 }])
438
- // Fallback: a record field. Appended AFTER the jsonic alts so the
439
- // embedded `#OS`/`#OS #CS` alts are matched first.
440
- .open([{ p: 'elem' }], { append: true })
441
- // LN / ZZ end a record.
442
- .close([{ s: [LN], b: 1 }])
443
- .close([{ s: [ZZ] }], { append: true });
444
- });
445
- tn.rule('elem', (rs) => {
446
- return rs
447
- // Replace jsonic's elem bc (child$ / pair handling) with a clean
448
- // push so record fields and embedded array elements both land as
449
- // plain values.
450
- .clearActions('bc')
451
- .open([
452
- // An empty element (`,` with nothing before it).
453
- {
454
- s: [CA],
455
- b: 1,
456
- a: (r) => {
457
- r.node.push(options.field.empty);
458
- r.u.done = true;
459
- },
460
- },
461
- ])
462
- // Fallback: parse a field/element value, after jsonic's alts.
463
- .open([{ p: 'val' }], { append: true })
464
- .close([
465
- // An empty element at the end of the line / input.
466
- {
467
- s: [CA, [LN, ZZ]],
468
- b: 1,
469
- a: (r) => r.node.push(options.field.empty),
470
- },
471
- // LN ends record
472
- { s: [LN], b: 1 },
473
- ])
474
- .bc((r) => {
475
- if (true !== r.u.done && undefined !== r.child.node) {
476
- r.node.push(r.child.node);
477
- }
478
- });
479
- });
480
- tn.rule('val', (rs) => {
481
- return rs
482
- .open([
483
- // Handle text and space concatenation.
484
- { s: [VAL, SP], b: 2, p: 'text' },
485
- { s: [SP], b: 1, p: 'text' },
486
- // LN ends record
487
- { s: [LN], b: 1 },
488
- ]);
489
- });
490
- }
491
- // Close is called on final rule - set parent val node
492
- tn.rule('text', (rs) => {
493
- rs.bc((r) => {
494
- r.parent.node = undefined === r.child.node ? r.node : r.child.node;
495
- });
107
+ tn.rule('markdown', (rs) => {
108
+ return rs
109
+ .clear()
110
+ .bo(refs['@markdown-bo'])
111
+ .open([{ s: '#AA', r: 'markdown' }, {}])
112
+ .close([{ s: '#ZZ' }, {}]);
496
113
  });
497
- };
498
- exports.Markdown = Markdown;
499
- // Custom Markdown String matcher.
500
- // Handles "a""b" -> "a"b" quoting wierdness.
501
- // This is a reduced copy of the standard Jsonic string matcher.
502
- function buildMarkdownStringMatcher(mdopts) {
503
- return function makeMarkdownStringMatcher(cfg, _opts) {
504
- return function markdownStringMatcher(lex) {
505
- let quoteMap = { [mdopts.string.quote]: true };
506
- let { pnt, src } = lex;
507
- let { sI, rI, cI } = pnt;
508
- let srclen = src.length;
509
- if (quoteMap[src[sI]]) {
510
- const q = src[sI]; // Quote character
511
- const qI = sI;
512
- const qrI = rI;
513
- ++sI;
514
- ++cI;
515
- let s = [];
516
- for (sI; sI < srclen; sI++) {
517
- cI++;
518
- let c = src[sI];
519
- // Quote char.
520
- if (q === c) {
521
- sI++;
522
- cI++;
523
- if (q === src[sI]) {
524
- s.push(q);
525
- }
526
- else {
527
- break; // String finished.
528
- }
529
- }
530
- // Body part of string.
531
- else {
532
- let bI = sI;
533
- let qc = q.charCodeAt(0);
534
- let cc = src.charCodeAt(sI);
535
- while (sI < srclen && 32 <= cc && qc !== cc) {
536
- cc = src.charCodeAt(++sI);
537
- cI++;
538
- }
539
- cI--;
540
- if (cfg.line.chars[src[sI]]) {
541
- if (cfg.line.rowChars[src[sI]]) {
542
- pnt.rI = ++rI;
543
- }
544
- cI = 1;
545
- s.push(src.substring(bI, sI + 1));
546
- }
547
- else if (cc < 32) {
548
- pnt.sI = sI;
549
- pnt.cI = cI;
550
- return lex.bad('unprintable', sI, sI + 1);
551
- }
552
- else {
553
- s.push(src.substring(bI, sI));
554
- sI--;
555
- }
556
- }
557
- }
558
- if (src[sI - 1] !== q || pnt.sI === sI - 1) {
559
- pnt.rI = qrI;
560
- return lex.bad('unterminated_string', qI, sI);
561
- }
562
- const tkn = lex.token('#ST', s.join(''), src.substring(pnt.sI, sI), pnt);
563
- pnt.sI = sI;
564
- pnt.rI = rI;
565
- pnt.cI = cI;
566
- return tkn;
567
- }
568
- };
114
+ tn.markdown = {
115
+ parseDocument: (t) => parseDocument(t, opts),
116
+ parseInline: (t) => parseInline(t, opts),
117
+ toHtml: (t) => toHtml(t, opts),
118
+ parseTree: (t) => parseTree(t, opts),
569
119
  };
570
- }
571
- // Default option values.
572
- Markdown.defaults = {
573
- trim: null,
574
- comment: null,
575
- number: null,
576
- value: null,
577
- header: true,
578
- object: true,
579
- stream: null,
580
- strict: true,
581
- field: {
582
- separation: null,
583
- nonameprefix: 'field~',
584
- empty: '',
585
- names: undefined,
586
- exact: false,
587
- },
588
- record: {
589
- separators: null,
590
- empty: false,
591
- },
592
- string: {
593
- quote: '"',
594
- markdown: null,
595
- },
596
120
  };
121
+ exports.Markdown = Markdown;
122
+ Markdown.defaults = { gfm: true, breaks: false };
123
+ var node_ts_1 = require("./node.js");
124
+ Object.defineProperty(exports, "MdNode", { enumerable: true, get: function () { return node_ts_1.MdNode; } });
125
+ // Re-exported so the package entry offers the same pair as the Go package,
126
+ // where `RenderHTML` is exported alongside `ToHTML`. Without this, rendering a
127
+ // tree you built or mutated yourself meant a deep import of `commonmark.ts`,
128
+ // and the two runtimes' public surfaces did not match.
129
+ var html_ts_2 = require("./html.js");
130
+ Object.defineProperty(exports, "renderHTML", { enumerable: true, get: function () { return html_ts_2.renderHTML; } });
597
131
  //# sourceMappingURL=markdown.js.map