mdrefine 0.2.4 → 0.2.5

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.
@@ -19,7 +19,9 @@ export declare const descriptionLine: RegExp;
19
19
  export interface MisreadLists {
20
20
  /**
21
21
  * Paragraphs, and headings underlined with `===` or `---`, whose text starts
22
- * with a list marker, and the text that renderers read as continuing it.
22
+ * with a list marker, and the text that renderers read as continuing it. In
23
+ * the Obsidian dialect also those with a later line that Obsidian reads as
24
+ * starting a list item where CommonMark reads text (issue #375).
23
25
  */
24
26
  text: ReadonlySet<Nodes>;
25
27
  /**
@@ -41,6 +43,29 @@ export interface MisreadLists {
41
43
  * the description as blocks, here an ordered list (issue #344).
42
44
  */
43
45
  descriptions: ReadonlySet<Nodes>;
46
+ /**
47
+ * In the Obsidian dialect, paragraphs, headings, and table cells whose text
48
+ * holds a backtick that no run of the same length closes, which the parser
49
+ * leaves as text, also in a highlight, an inline comment, or an image's
50
+ * description. Obsidian's Live Preview shows the text after it as code, at
51
+ * least to the end of its line, and Reading view pairs a run of two or more
52
+ * with a later, shorter one, as in ``a ``` b `c` d`` (issue #362).
53
+ *
54
+ * After a run of three or more, Live Preview shows the blocks below as code
55
+ * too, also out of a list item and across blank lines, up to a block with a
56
+ * run of the same length outside an indented code block, which it closes
57
+ * there, a fenced code block, or a list item. Those blocks are in the set as
58
+ * well, with a table that holds such a run.
59
+ */
60
+ unclosedCode: ReadonlySet<Nodes>;
61
+ /**
62
+ * In the Obsidian dialect, the blocks that Reading view reads as more of an
63
+ * HTML block above them. A line of blank space directly below an HTML block
64
+ * that ends at a blank line continues the block, and so do the blocks after
65
+ * it, up to an empty line (issue #358). Each counts from the start of its
66
+ * first line, with the marker of a list item there.
67
+ */
68
+ htmlText: ReadonlySet<Nodes>;
44
69
  }
45
70
  /**
46
71
  * Where renderers may read a list in text that the parser read as text.
@@ -65,5 +90,10 @@ export interface MisreadLists {
65
90
  * `Term` and a line `: 2. x` below it are a term and a description, and the
66
91
  * description holds blocks, here an ordered list, as a list item does. The
67
92
  * blocks indented below it in its container belong to it too (issue #344).
93
+ *
94
+ * Obsidian starts a list below a paragraph line where CommonMark does not:
95
+ * Live Preview at an ordered marker with a number other than 1 and text after
96
+ * it, except in a block quote, and Reading view at an empty item, `*`, `+`,
97
+ * `- `, or `1.`, which Live Preview reads so for `+ ` and `- ` (issue #375).
68
98
  */
69
99
  export declare function misreadLists(document: Document): MisreadLists;
@@ -36,6 +36,11 @@ const found = new WeakMap();
36
36
  * `Term` and a line `: 2. x` below it are a term and a description, and the
37
37
  * description holds blocks, here an ordered list, as a list item does. The
38
38
  * blocks indented below it in its container belong to it too (issue #344).
39
+ *
40
+ * Obsidian starts a list below a paragraph line where CommonMark does not:
41
+ * Live Preview at an ordered marker with a number other than 1 and text after
42
+ * it, except in a block quote, and Reading view at an empty item, `*`, `+`,
43
+ * `- `, or `1.`, which Live Preview reads so for `+ ` and `- ` (issue #375).
39
44
  */
40
45
  export function misreadLists(document) {
41
46
  const known = found.get(document.tree);
@@ -47,6 +52,7 @@ export function misreadLists(document) {
47
52
  const nested = new Set();
48
53
  const next = new Set();
49
54
  const descriptions = new Set();
55
+ const obsidian = document.dialect === "obsidian";
50
56
  /** The column of the first character from `offset` on, after spaces and tabs. */
51
57
  const columnAt = (offset) => {
52
58
  let start = offset;
@@ -73,8 +79,35 @@ export function misreadLists(document) {
73
79
  return node.children[0]?.position?.start.offset ?? start;
74
80
  return undefined;
75
81
  };
82
+ /**
83
+ * In the Obsidian dialect, the offset of the marker on the first line of
84
+ * `node` after its first that Obsidian reads as starting a list item where
85
+ * CommonMark reads text; `quoted` says whether `node` is in a block quote.
86
+ */
87
+ const obsidianItem = (node, quoted) => {
88
+ const end = node.position.end.offset;
89
+ // A marker four or more columns right of the text is more of the text.
90
+ const text = columnAt(node.position.start.offset);
91
+ const breaks = /\r\n|\r|\n/g;
92
+ breaks.lastIndex = node.position.start.offset;
93
+ for (let found = breaks.exec(source); found && found.index < end; found = breaks.exec(source)) {
94
+ const lineStart = found.index + found[0].length;
95
+ let lineEnd = lineStart;
96
+ while (lineEnd < end && source[lineEnd] !== "\n" && source[lineEnd] !== "\r")
97
+ lineEnd++;
98
+ const line = source.slice(lineStart, lineEnd);
99
+ const prefix = /^[ \t>]*/.exec(line)[0].length;
100
+ const content = line.slice(prefix);
101
+ const ordered = /^(\d{1,9})[.)][ \t]+\S/.exec(content);
102
+ if (columnAt(lineStart + prefix) - text <= 3 &&
103
+ ((ordered && Number(ordered[1]) !== 1 && !quoted) ||
104
+ /^(?:[*+]|-(?=[ \t])|0*1[.)])[ \t]*$/.test(content)))
105
+ return lineStart + prefix;
106
+ }
107
+ return undefined;
108
+ };
76
109
  /** Returns the last line of misread text that ends `parent` and whose `===` renderers read as text. */
77
- const visit = (parent) => {
110
+ const visit = (parent, quoted = false) => {
78
111
  let reach;
79
112
  /** The last line of misread text whose `===` renderers read as text, if the last block is that. */
80
113
  let continued;
@@ -102,11 +135,13 @@ export function misreadLists(document) {
102
135
  // Renderers continue the text lazily on the line below the container
103
136
  // that it ends, but only with text (issue #343).
104
137
  const adjacent = continued === child.position.start.line - 1 && (!inside || start !== undefined);
105
- const misread = start !== undefined &&
138
+ const atStart = start !== undefined &&
106
139
  (listMarker.test(source.slice(start, start + 11)) || adjacent) &&
107
140
  !(index === 0 && parent.type === "listItem" && typeof parent.checked === "boolean");
141
+ const item = obsidian && start !== undefined ? obsidianItem(child, quoted) : undefined;
142
+ const misread = atStart || item !== undefined;
108
143
  if (misread || adjacent || reach !== undefined) {
109
- const column = columnAt(misread ? start : offset);
144
+ const column = columnAt(atStart ? start : (item ?? offset));
110
145
  if ((adjacent && !misread) || (reach !== undefined && column > reach))
111
146
  nested.add(child);
112
147
  else if (reach !== undefined) {
@@ -124,7 +159,7 @@ export function misreadLists(document) {
124
159
  : undefined;
125
160
  inside = false;
126
161
  if ("children" in child && !leaves.has(child.type)) {
127
- const last = visit(child);
162
+ const last = visit(child, quoted || child.type === "blockquote");
128
163
  if (last !== undefined && last === child.position.end.line) {
129
164
  continued = last;
130
165
  inside = true;
@@ -134,8 +169,214 @@ export function misreadLists(document) {
134
169
  return continued;
135
170
  };
136
171
  visit(document.tree);
137
- const result = { text, nested, next, descriptions };
172
+ const htmlText = new Set();
173
+ const unclosedCode = new Set();
174
+ if (document.dialect === "obsidian") {
175
+ /**
176
+ * Leaf blocks in document order, and whether each starts a list item, also
177
+ * inside a container that does, as in `- > a`.
178
+ */
179
+ const order = [];
180
+ const collect = (node, item) => {
181
+ if (leaves.has(node.type) || !("children" in node))
182
+ order.push([node, item]);
183
+ else
184
+ node.children.forEach((child, index) => collect(child, index === 0 && (item || node.type === "listItem")));
185
+ };
186
+ collect(document.tree, false);
187
+ const lines = source.split(/\r\n|\r|\n/);
188
+ /** Whether line `number`, counted from 1, holds blank space and more than block quote markers. */
189
+ const spaced = (number) => {
190
+ const line = lines[number - 1] ?? "";
191
+ return /^[ \t>]*$/.test(line) && /[^>]/.test(line);
192
+ };
193
+ /**
194
+ * Whether the last leaf block is an HTML block that ends at a blank line, or
195
+ * text that Obsidian reads as more of one, which the next block may continue.
196
+ * Leaf blocks count, not containers, because an empty line inside a list
197
+ * ends the HTML block there.
198
+ */
199
+ let open = false;
200
+ order.forEach(([leaf], index) => {
201
+ const previous = order[index - 1]?.[0];
202
+ if (open && previous?.position && leaf.position) {
203
+ for (let line = previous.position.end.line + 1; line < leaf.position.start.line; line++)
204
+ if (!spaced(line))
205
+ open = false;
206
+ if (open) {
207
+ // From the start of its line: a list item's marker there, `- ` in
208
+ // `- *a*`, is text of the HTML block too.
209
+ const offset = leaf.position.start.offset ?? 0;
210
+ let from = offset;
211
+ while (from > 0 && source[from - 1] !== "\n" && source[from - 1] !== "\r")
212
+ from--;
213
+ const start = { ...leaf.position.start, offset: from, column: 1 };
214
+ htmlText.add(from === offset ? leaf : { ...leaf, position: { ...leaf.position, start } });
215
+ }
216
+ }
217
+ // Other HTML blocks end at their own end marker, as a comment does at `-->`.
218
+ if (!open &&
219
+ leaf.type === "html" &&
220
+ leaf.position &&
221
+ !/^<(?:!--|\?|!\[CDATA\[|![A-Za-z]|(?:script|pre|style|textarea)(?:[\s>]|$))/i.test(leaf.value.trimStart()))
222
+ open = spaced(leaf.position.end.line + 1);
223
+ });
224
+ /**
225
+ * The runs of backticks that nothing closes in the text of `node`, outside
226
+ * code, math, and wikilinks. Live Preview starts code at them also inside a
227
+ * highlight, an inline comment, and an image's description, whose source
228
+ * the parser does not read as code spans; a backtick in a link's
229
+ * destination or title starts none, but counts in an image's source.
230
+ */
231
+ const openRuns = (node) => {
232
+ const start = node.position?.start.offset;
233
+ const end = node.position?.end.offset;
234
+ if (start === undefined || end === undefined)
235
+ return [];
236
+ if (node.type === "obsidianHighlight" ||
237
+ node.type === "obsidianComment" ||
238
+ node.type === "image" ||
239
+ node.type === "imageReference")
240
+ return unclosedRuns(source, start, end);
241
+ // The parser reads every run that another closes as code, so every one
242
+ // left in text is unclosed.
243
+ if (node.type === "text")
244
+ return backtickRuns(source, start, end);
245
+ return "children" in node ? node.children.flatMap(openRuns) : [];
246
+ };
247
+ /**
248
+ * The length of a run of three or more backticks whose code Live Preview
249
+ * carries into the blocks below, up to a block with a run of the same
250
+ * length, a fenced code block, or a list item. A run in a wikilink, in math,
251
+ * or in an HTML block closes it too, because Live Preview reads none of
252
+ * those inside the code.
253
+ */
254
+ let carry;
255
+ for (const [leaf, item] of order) {
256
+ const start = leaf.position?.start.offset;
257
+ const end = leaf.position?.end.offset;
258
+ if (start === undefined || end === undefined)
259
+ continue;
260
+ if (carry !== undefined) {
261
+ const fenced = leaf.type === "code" && /^ {0,3}(?:```|~~~)/.test(source.slice(start, end));
262
+ if (item || fenced)
263
+ carry = undefined;
264
+ else {
265
+ unclosedCode.add(leaf);
266
+ // Live Preview shows an indented code block there as more of the
267
+ // code, and its backticks close nothing.
268
+ if (leaf.type === "code")
269
+ continue;
270
+ const runs = backtickRuns(source, start, end);
271
+ const close = runs.findIndex(([, length]) => length === carry);
272
+ if (close >= 0)
273
+ carry = carried(source, runs.slice(close + 1));
274
+ continue;
275
+ }
276
+ }
277
+ const parts = leaf.type === "table"
278
+ ? leaf.children.flatMap((row) => row.children)
279
+ : leaf.type === "paragraph" || leaf.type === "heading"
280
+ ? [leaf]
281
+ : [];
282
+ const runs = parts.flatMap((part) => {
283
+ const open = openRuns(part);
284
+ if (open.length > 0)
285
+ unclosedCode.add(part);
286
+ return open;
287
+ });
288
+ const long = runs.find(([, length]) => length >= 3);
289
+ if (long === undefined)
290
+ continue;
291
+ // Live Preview shows the rest of a table as code from such a run.
292
+ if (leaf.type === "table")
293
+ unclosedCode.add(leaf);
294
+ const after = backtickRuns(source, long[0] + long[1], end);
295
+ const close = after.findIndex(([, length]) => length === long[1]);
296
+ carry = close < 0 ? long[1] : carried(source, after.slice(close + 1));
297
+ }
298
+ }
299
+ const result = { text, nested, next, descriptions, unclosedCode, htmlText };
138
300
  found.set(document.tree, result);
139
301
  return result;
140
302
  }
303
+ /**
304
+ * The runs of backticks from `start` to `end`. A backslash before a run
305
+ * escapes its first backtick only.
306
+ */
307
+ function backtickRuns(source, start, end) {
308
+ const runs = [];
309
+ for (let at = source.indexOf("`", start); at >= 0 && at < end;) {
310
+ let after = at;
311
+ while (after < end && source[after] === "`")
312
+ after++;
313
+ let slashes = 0;
314
+ while (source[at - 1 - slashes] === "\\")
315
+ slashes++;
316
+ const from = slashes % 2 === 0 ? at : at + 1;
317
+ if (after > from)
318
+ runs.push([from, after - from]);
319
+ at = source.indexOf("`", after);
320
+ }
321
+ return runs;
322
+ }
323
+ /**
324
+ * The runs of backticks from `start` to `end` that no later run of the same
325
+ * length there closes, as CommonMark pairs them into code spans.
326
+ */
327
+ function unclosedRuns(source, start, end) {
328
+ const runs = backtickRuns(source, start, end);
329
+ /** The index of the next run of the same length after each run, or -1. */
330
+ const next = [];
331
+ const later = new Map();
332
+ for (let index = runs.length - 1; index >= 0; index--) {
333
+ const length = runs[index][1];
334
+ next[index] = later.get(length) ?? -1;
335
+ later.set(length, index);
336
+ }
337
+ const open = [];
338
+ for (let index = 0; index < runs.length; index++) {
339
+ if (next[index] < 0)
340
+ open.push(runs[index]);
341
+ else
342
+ index = next[index];
343
+ }
344
+ return open;
345
+ }
346
+ /**
347
+ * The length of the run of three or more backticks whose code Live Preview
348
+ * carries past the last of `runs`, if any. Live Preview closes a run with the
349
+ * next run of the same length; the code of a run of one or two backticks ends
350
+ * with its line.
351
+ */
352
+ function carried(source, runs) {
353
+ let open;
354
+ /** Where the line of the open run ends, and that of the current one. */
355
+ let openLineEnd = 0;
356
+ let lineEnd = -1;
357
+ for (const run of runs) {
358
+ if (run[0] >= lineEnd)
359
+ lineEnd = lineBreak(source, run[0]);
360
+ if (open !== undefined) {
361
+ const sameLine = run[0] < openLineEnd;
362
+ if (run[1] === open[1] && (open[1] >= 3 || sameLine)) {
363
+ open = undefined;
364
+ continue;
365
+ }
366
+ // Other runs are part of the code.
367
+ if (open[1] >= 3 || sameLine)
368
+ continue;
369
+ }
370
+ open = run;
371
+ openLineEnd = lineEnd;
372
+ }
373
+ return open !== undefined && open[1] >= 3 ? open[1] : undefined;
374
+ }
375
+ /** The offset of the first line break at or after `from`, or the length of `source`. */
376
+ function lineBreak(source, from) {
377
+ for (let at = from; at < source.length; at++)
378
+ if (source[at] === "\n" || source[at] === "\r")
379
+ return at;
380
+ return source.length;
381
+ }
141
382
  //# sourceMappingURL=misread-lists.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"misread-lists.js","sourceRoot":"","sources":["../../src/syntax/misread-lists.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Nodes, Parents, Root } from \"mdast\";\nimport type { Document } from \"../core/types.js\";\n\n/**\n * A list marker as CommonMark reads one at the start of a line's content: a\n * bullet, `-`, `*`, or `+`, or a number of one to nine digits followed by `.`\n * or `)`, and then a space, a tab, or the end of the line.\n */\nexport const listMarker = /^(?:[-+*]|\\d{1,9}[.)])(?:[ \\t\\r\\n]|$)/;\n/**\n * A line whose content, after blank space and block quote markers, starts with\n * `:` and a space or tab. In a paragraph, such a line opens a definition\n * description on Forgejo and Gitea.\n */\nexport const descriptionLine = /^[ \\t>]*:[ \\t]/m;\n\n/**\n * Text that the parser read where renderers may read a list, or on Forgejo and\n * Gitea a definition description, and the blocks after it.\n */\nexport interface MisreadLists {\n /**\n * Paragraphs, and headings underlined with `===` or `---`, whose text starts\n * with a list marker, and the text that renderers read as continuing it.\n */\n text: ReadonlySet<Nodes>;\n /**\n * The blocks after such text, or after a description, in its container whose\n * first lines start further right than the text, up to one that does not.\n * Renderers may read them inside the list's last item or the description,\n * where their indentation counts from the item's text: an indented code block\n * can be a paragraph there.\n */\n nested: ReadonlySet<Nodes>;\n /**\n * The block after those below such text, which starts no further right than\n * the text. Renderers may read it as more items of the list.\n */\n next: ReadonlySet<Nodes>;\n /**\n * In the Forgejo and Gitea dialects, paragraphs with a line that opens a\n * definition description, as `Term` and `: 2. x` do. Those renderers read\n * the description as blocks, here an ordered list (issue #344).\n */\n descriptions: ReadonlySet<Nodes>;\n}\n\n/** Leaf blocks: their children, if they have any, are not blocks. */\nconst leaves = new Set<Nodes[\"type\"]>([\"paragraph\", \"heading\", \"table\", \"code\", \"html\"]);\nconst found = new WeakMap<Root, MisreadLists>();\n\n/**\n * Where renderers may read a list in text that the parser read as text.\n *\n * micromark refuses to start a list that does not start at 1, or an empty\n * item, where it would interrupt a paragraph, as CommonMark says, but also\n * where no paragraph is open: at the start of a list item, block quote, or\n * footnote definition below a paragraph, and after an indented code block\n * (issue #191). It reads the line as text there, where GitHub, commonmark.js,\n * and markdown-it read a list. By CommonMark's rules, text can start with a\n * list marker only below a link reference definition, as what remains of the\n * definition's lines; GitHub and commonmark.js read text there too, and\n * markdown-it a list. The paragraph of a task list item starts after its\n * checkbox, which renderers read as the start of the item's text, so it does\n * not count. Renderers read the `===` below such text as text, of the list\n * item or after an empty one, so a paragraph or heading on the next line\n * continues it too, and a block there is nested: a `---` would underline it.\n * Where such text ends a list item or block quote, renderers continue it\n * lazily into a paragraph or heading on the next line below the container.\n *\n * Forgejo and Gitea read a definition list, which the parser reads as text:\n * `Term` and a line `: 2. x` below it are a term and a description, and the\n * description holds blocks, here an ordered list, as a list item does. The\n * blocks indented below it in its container belong to it too (issue #344).\n */\nexport function misreadLists(document: Document): MisreadLists {\n const known = found.get(document.tree);\n if (known) return known;\n const { source } = document;\n const forge = document.dialect === \"forgejo\" || document.dialect === \"gitea\";\n const text = new Set<Nodes>();\n const nested = new Set<Nodes>();\n const next = new Set<Nodes>();\n const descriptions = new Set<Nodes>();\n /** The column of the first character from `offset` on, after spaces and tabs. */\n const columnAt = (offset: number) => {\n let start = offset;\n while (start > 0 && source[start - 1] !== \"\\n\" && source[start - 1] !== \"\\r\") start--;\n let column = 0;\n for (let at = start; at < source.length; at++) {\n const character = source[at];\n if (at >= offset && character !== \" \" && character !== \"\\t\") break;\n column = character === \"\\t\" ? column + 4 - (column % 4) : column + 1;\n }\n return column;\n };\n /** Where a paragraph's or an underlined heading's text starts. */\n const textStart = (node: Nodes): number | undefined => {\n const start = node.position?.start.offset;\n if (start === undefined || node.position?.end.offset === undefined) return undefined;\n if (node.type === \"paragraph\") return start;\n // An underlined heading below link reference definitions starts at them.\n if (node.type === \"heading\" && source[start] !== \"#\")\n return node.children[0]?.position?.start.offset ?? start;\n return undefined;\n };\n /** Returns the last line of misread text that ends `parent` and whose `===` renderers read as text. */\n const visit = (parent: Parents): number | undefined => {\n let reach: number | undefined;\n /** The last line of misread text whose `===` renderers read as text, if the last block is that. */\n let continued: number | undefined;\n /** Whether that text ends the last block, a container, rather than being it. */\n let inside = false;\n /** The column of the last definition description while the blocks after it may belong to it. */\n let described: number | undefined;\n parent.children.forEach((child, index) => {\n const offset = child.position?.start.offset;\n if (offset === undefined) return;\n const start = textStart(child);\n if (described !== undefined) {\n if (columnAt(offset) > described) nested.add(child);\n else described = undefined;\n }\n if (\n forge &&\n start !== undefined &&\n descriptionLine.test(source.slice(offset, child.position!.end.offset))\n ) {\n descriptions.add(child);\n described = Math.min(described ?? columnAt(offset), columnAt(offset));\n }\n // Renderers continue the text lazily on the line below the container\n // that it ends, but only with text (issue #343).\n const adjacent =\n continued === child.position!.start.line - 1 && (!inside || start !== undefined);\n const misread =\n start !== undefined &&\n (listMarker.test(source.slice(start, start + 11)) || adjacent) &&\n !(index === 0 && parent.type === \"listItem\" && typeof parent.checked === \"boolean\");\n if (misread || adjacent || reach !== undefined) {\n const column = columnAt(misread ? start! : offset);\n if ((adjacent && !misread) || (reach !== undefined && column > reach)) nested.add(child);\n else if (reach !== undefined) {\n next.add(child);\n reach = undefined;\n }\n if (misread) {\n text.add(child);\n reach = Math.min(reach ?? column, column);\n }\n }\n continued =\n misread && child.type === \"heading\" && child.depth === 1\n ? child.position!.end.line\n : undefined;\n inside = false;\n if (\"children\" in child && !leaves.has(child.type)) {\n const last = visit(child);\n if (last !== undefined && last === child.position!.end.line) {\n continued = last;\n inside = true;\n }\n }\n });\n return continued;\n };\n visit(document.tree);\n const result = { text, nested, next, descriptions };\n found.set(document.tree, result);\n return result;\n}\n"]}
1
+ {"version":3,"file":"misread-lists.js","sourceRoot":"","sources":["../../src/syntax/misread-lists.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,uCAAuC,CAAC;AAClE;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,CAAC;AA0DjD,qEAAqE;AACrE,MAAM,MAAM,GAAG,IAAI,GAAG,CAAgB,CAAC,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AACzF,MAAM,KAAK,GAAG,IAAI,OAAO,EAAsB,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,YAAY,CAAC,QAAkB;IAC7C,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;IAC5B,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,KAAK,SAAS,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO,CAAC;IAC7E,MAAM,IAAI,GAAG,IAAI,GAAG,EAAS,CAAC;IAC9B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAS,CAAC;IAChC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAS,CAAC;IAC9B,MAAM,YAAY,GAAG,IAAI,GAAG,EAAS,CAAC;IACtC,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,KAAK,UAAU,CAAC;IACjD,iFAAiF;IACjF,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAE,EAAE;QAClC,IAAI,KAAK,GAAG,MAAM,CAAC;QACnB,OAAO,KAAK,GAAG,CAAC,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI;YAAE,KAAK,EAAE,CAAC;QACtF,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,KAAK,IAAI,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;YAC9C,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;YAC7B,IAAI,EAAE,IAAI,MAAM,IAAI,SAAS,KAAK,GAAG,IAAI,SAAS,KAAK,IAAI;gBAAE,MAAM;YACnE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IACF,kEAAkE;IAClE,MAAM,SAAS,GAAG,CAAC,IAAW,EAAsB,EAAE;QACpD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC;QAC1C,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QACrF,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW;YAAE,OAAO,KAAK,CAAC;QAC5C,yEAAyE;QACzE,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG;YAClD,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC;QAC3D,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;IACF;;;;OAIG;IACH,MAAM,YAAY,GAAG,CAAC,IAAW,EAAE,MAAe,EAAsB,EAAE;QACxE,MAAM,GAAG,GAAG,IAAI,CAAC,QAAS,CAAC,GAAG,CAAC,MAAO,CAAC;QACvC,uEAAuE;QACvE,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAS,CAAC,KAAK,CAAC,MAAO,CAAC,CAAC;QACpD,MAAM,MAAM,GAAG,aAAa,CAAC;QAC7B,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,QAAS,CAAC,KAAK,CAAC,MAAO,CAAC;QAChD,KAAK,IAAI,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,IAAI,KAAK,CAAC,KAAK,GAAG,GAAG,EAAE,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9F,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YAChD,IAAI,OAAO,GAAG,SAAS,CAAC;YACxB,OAAO,OAAO,GAAG,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI;gBAAE,OAAO,EAAE,CAAC;YACxF,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAC9C,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YAChD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACnC,MAAM,OAAO,GAAG,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvD,IACE,QAAQ,CAAC,SAAS,GAAG,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC;gBACxC,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;oBAC/C,qCAAqC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAEtD,OAAO,SAAS,GAAG,MAAM,CAAC;QAC9B,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;IACF,uGAAuG;IACvG,MAAM,KAAK,GAAG,CAAC,MAAe,EAAE,MAAM,GAAG,KAAK,EAAsB,EAAE;QACpE,IAAI,KAAyB,CAAC;QAC9B,mGAAmG;QACnG,IAAI,SAA6B,CAAC;QAClC,gFAAgF;QAChF,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,gGAAgG;QAChG,IAAI,SAA6B,CAAC;QAClC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACvC,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC;YAC5C,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO;YACjC,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;YAC/B,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,IAAI,QAAQ,CAAC,MAAM,CAAC,GAAG,SAAS;oBAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;;oBAC/C,SAAS,GAAG,SAAS,CAAC;YAC7B,CAAC;YACD,IACE,KAAK;gBACL,KAAK,KAAK,SAAS;gBACnB,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,QAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EACtE,CAAC;gBACD,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACxB,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YACxE,CAAC;YACD,qEAAqE;YACrE,iDAAiD;YACjD,MAAM,QAAQ,GACZ,SAAS,KAAK,KAAK,CAAC,QAAS,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,KAAK,KAAK,SAAS,CAAC,CAAC;YACnF,MAAM,OAAO,GACX,KAAK,KAAK,SAAS;gBACnB,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,EAAE,CAAC,CAAC,IAAI,QAAQ,CAAC;gBAC9D,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC;YACtF,MAAM,IAAI,GAAG,QAAQ,IAAI,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACvF,MAAM,OAAO,GAAG,OAAO,IAAI,IAAI,KAAK,SAAS,CAAC;YAC9C,IAAI,OAAO,IAAI,QAAQ,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBAC/C,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,KAAM,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC;gBAC7D,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,GAAG,KAAK,CAAC;oBAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;qBACpF,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBAC7B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;oBAChB,KAAK,GAAG,SAAS,CAAC;gBACpB,CAAC;gBACD,IAAI,OAAO,EAAE,CAAC;oBACZ,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;oBAChB,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,MAAM,EAAE,MAAM,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC;YACD,SAAS;gBACP,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,CAAC;oBACtD,CAAC,CAAC,KAAK,CAAC,QAAS,CAAC,GAAG,CAAC,IAAI;oBAC1B,CAAC,CAAC,SAAS,CAAC;YAChB,MAAM,GAAG,KAAK,CAAC;YACf,IAAI,UAAU,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC;gBACjE,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,KAAK,CAAC,QAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;oBAC5D,SAAS,GAAG,IAAI,CAAC;oBACjB,MAAM,GAAG,IAAI,CAAC;gBAChB,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;IACF,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACrB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAS,CAAC;IAClC,MAAM,YAAY,GAAG,IAAI,GAAG,EAAS,CAAC;IACtC,IAAI,QAAQ,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QACpC;;;WAGG;QACH,MAAM,KAAK,GAAuB,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,CAAC,IAAW,EAAE,IAAa,EAAE,EAAE;YAC7C,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;;gBAE3E,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CACrC,OAAO,CAAC,KAAK,EAAE,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAClE,CAAC;QACN,CAAC,CAAC;QACF,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACzC,kGAAkG;QAClG,MAAM,MAAM,GAAG,CAAC,MAAc,EAAE,EAAE;YAChC,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;YACrC,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrD,CAAC,CAAC;QACF;;;;;WAKG;QACH,IAAI,IAAI,GAAG,KAAK,CAAC;QACjB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE;YAC9B,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACvC,IAAI,IAAI,IAAI,QAAQ,EAAE,QAAQ,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAChD,KAAK,IAAI,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE;oBACrF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;wBAAE,IAAI,GAAG,KAAK,CAAC;gBAClC,IAAI,IAAI,EAAE,CAAC;oBACT,kEAAkE;oBAClE,0CAA0C;oBAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;oBAC/C,IAAI,IAAI,GAAG,MAAM,CAAC;oBAClB,OAAO,IAAI,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,IAAI;wBAAE,IAAI,EAAE,CAAC;oBAClF,MAAM,KAAK,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;oBAClE,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;gBAC5F,CAAC;YACH,CAAC;YACD,6EAA6E;YAC7E,IACE,CAAC,IAAI;gBACL,IAAI,CAAC,IAAI,KAAK,MAAM;gBACpB,IAAI,CAAC,QAAQ;gBACb,CAAC,6EAA6E,CAAC,IAAI,CACjF,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CACvB;gBAED,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QACH;;;;;;WAMG;QACH,MAAM,QAAQ,GAAG,CAAC,IAAW,EAAS,EAAE;YACtC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC;YAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC;YACtC,IAAI,KAAK,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS;gBAAE,OAAO,EAAE,CAAC;YACxD,IACE,IAAI,CAAC,IAAI,KAAK,mBAAmB;gBACjC,IAAI,CAAC,IAAI,KAAK,iBAAiB;gBAC/B,IAAI,CAAC,IAAI,KAAK,OAAO;gBACrB,IAAI,CAAC,IAAI,KAAK,gBAAgB;gBAE9B,OAAO,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;YAC1C,uEAAuE;YACvE,4BAA4B;YAC5B,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;gBAAE,OAAO,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;YAClE,OAAO,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,CAAC,CAAC;QACF;;;;;;WAMG;QACH,IAAI,KAAyB,CAAC;QAC9B,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC;YACjC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC;YAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC;YACtC,IAAI,KAAK,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS;gBAAE,SAAS;YACvD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;gBAC3F,IAAI,IAAI,IAAI,MAAM;oBAAE,KAAK,GAAG,SAAS,CAAC;qBACjC,CAAC;oBACJ,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBACvB,iEAAiE;oBACjE,yCAAyC;oBACzC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;wBAAE,SAAS;oBACnC,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;oBAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC;oBAC/D,IAAI,KAAK,IAAI,CAAC;wBAAE,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;oBAC/D,SAAS;gBACX,CAAC;YACH,CAAC;YACD,MAAM,KAAK,GACT,IAAI,CAAC,IAAI,KAAK,OAAO;gBACnB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAC9C,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;oBACpD,CAAC,CAAC,CAAC,IAAI,CAAC;oBACR,CAAC,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;gBAClC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;gBAC5B,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;oBAAE,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC5C,OAAO,IAAI,CAAC;YACd,CAAC,CAAC,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;YACpD,IAAI,IAAI,KAAK,SAAS;gBAAE,SAAS;YACjC,kEAAkE;YAClE,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;gBAAE,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClD,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAC3D,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAClE,KAAK,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;IAC5E,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,MAAM,CAAC;AAChB,CAAC;AAKD;;;GAGG;AACH,SAAS,YAAY,CAAC,MAAc,EAAE,KAAa,EAAE,GAAW;IAC9D,MAAM,IAAI,GAAU,EAAE,CAAC;IACvB,KAAK,IAAI,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,CAAC;QAC/D,IAAI,KAAK,GAAG,EAAE,CAAC;QACf,OAAO,KAAK,GAAG,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG;YAAE,KAAK,EAAE,CAAC;QACrD,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,OAAO,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,KAAK,IAAI;YAAE,OAAO,EAAE,CAAC;QACpD,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC7C,IAAI,KAAK,GAAG,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC;QAClD,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,SAAS,YAAY,CAAC,MAAc,EAAE,KAAa,EAAE,GAAW;IAC9D,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IAC9C,0EAA0E;IAC1E,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,KAAK,IAAI,KAAK,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;QACtD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAE,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QACtC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC3B,CAAC;IACD,MAAM,IAAI,GAAU,EAAE,CAAC;IACvB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QACjD,IAAI,IAAI,CAAC,KAAK,CAAE,GAAG,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAE,CAAC,CAAC;;YACzC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAE,CAAC;IAC5B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,SAAS,OAAO,CAAC,MAAc,EAAE,IAAW;IAC1C,IAAI,IAAqB,CAAC;IAC1B,wEAAwE;IACxE,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC;IACjB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,OAAO;YAAE,OAAO,GAAG,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC;YACtC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,EAAE,CAAC;gBACrD,IAAI,GAAG,SAAS,CAAC;gBACjB,SAAS;YACX,CAAC;YACD,mCAAmC;YACnC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ;gBAAE,SAAS;QACzC,CAAC;QACD,IAAI,GAAG,GAAG,CAAC;QACX,WAAW,GAAG,OAAO,CAAC;IACxB,CAAC;IACD,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAClE,CAAC;AAED,wFAAwF;AACxF,SAAS,SAAS,CAAC,MAAc,EAAE,IAAY;IAC7C,KAAK,IAAI,EAAE,GAAG,IAAI,EAAE,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,EAAE,EAAE;QAC1C,IAAI,MAAM,CAAC,EAAE,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,EAAE,CAAC,KAAK,IAAI;YAAE,OAAO,EAAE,CAAC;IAC5D,OAAO,MAAM,CAAC,MAAM,CAAC;AACvB,CAAC","sourcesContent":["import type { Nodes, Parents, Root } from \"mdast\";\nimport type { Document } from \"../core/types.js\";\n\n/**\n * A list marker as CommonMark reads one at the start of a line's content: a\n * bullet, `-`, `*`, or `+`, or a number of one to nine digits followed by `.`\n * or `)`, and then a space, a tab, or the end of the line.\n */\nexport const listMarker = /^(?:[-+*]|\\d{1,9}[.)])(?:[ \\t\\r\\n]|$)/;\n/**\n * A line whose content, after blank space and block quote markers, starts with\n * `:` and a space or tab. In a paragraph, such a line opens a definition\n * description on Forgejo and Gitea.\n */\nexport const descriptionLine = /^[ \\t>]*:[ \\t]/m;\n\n/**\n * Text that the parser read where renderers may read a list, or on Forgejo and\n * Gitea a definition description, and the blocks after it.\n */\nexport interface MisreadLists {\n /**\n * Paragraphs, and headings underlined with `===` or `---`, whose text starts\n * with a list marker, and the text that renderers read as continuing it. In\n * the Obsidian dialect also those with a later line that Obsidian reads as\n * starting a list item where CommonMark reads text (issue #375).\n */\n text: ReadonlySet<Nodes>;\n /**\n * The blocks after such text, or after a description, in its container whose\n * first lines start further right than the text, up to one that does not.\n * Renderers may read them inside the list's last item or the description,\n * where their indentation counts from the item's text: an indented code block\n * can be a paragraph there.\n */\n nested: ReadonlySet<Nodes>;\n /**\n * The block after those below such text, which starts no further right than\n * the text. Renderers may read it as more items of the list.\n */\n next: ReadonlySet<Nodes>;\n /**\n * In the Forgejo and Gitea dialects, paragraphs with a line that opens a\n * definition description, as `Term` and `: 2. x` do. Those renderers read\n * the description as blocks, here an ordered list (issue #344).\n */\n descriptions: ReadonlySet<Nodes>;\n /**\n * In the Obsidian dialect, paragraphs, headings, and table cells whose text\n * holds a backtick that no run of the same length closes, which the parser\n * leaves as text, also in a highlight, an inline comment, or an image's\n * description. Obsidian's Live Preview shows the text after it as code, at\n * least to the end of its line, and Reading view pairs a run of two or more\n * with a later, shorter one, as in ``a ``` b `c` d`` (issue #362).\n *\n * After a run of three or more, Live Preview shows the blocks below as code\n * too, also out of a list item and across blank lines, up to a block with a\n * run of the same length outside an indented code block, which it closes\n * there, a fenced code block, or a list item. Those blocks are in the set as\n * well, with a table that holds such a run.\n */\n unclosedCode: ReadonlySet<Nodes>;\n /**\n * In the Obsidian dialect, the blocks that Reading view reads as more of an\n * HTML block above them. A line of blank space directly below an HTML block\n * that ends at a blank line continues the block, and so do the blocks after\n * it, up to an empty line (issue #358). Each counts from the start of its\n * first line, with the marker of a list item there.\n */\n htmlText: ReadonlySet<Nodes>;\n}\n\n/** Leaf blocks: their children, if they have any, are not blocks. */\nconst leaves = new Set<Nodes[\"type\"]>([\"paragraph\", \"heading\", \"table\", \"code\", \"html\"]);\nconst found = new WeakMap<Root, MisreadLists>();\n\n/**\n * Where renderers may read a list in text that the parser read as text.\n *\n * micromark refuses to start a list that does not start at 1, or an empty\n * item, where it would interrupt a paragraph, as CommonMark says, but also\n * where no paragraph is open: at the start of a list item, block quote, or\n * footnote definition below a paragraph, and after an indented code block\n * (issue #191). It reads the line as text there, where GitHub, commonmark.js,\n * and markdown-it read a list. By CommonMark's rules, text can start with a\n * list marker only below a link reference definition, as what remains of the\n * definition's lines; GitHub and commonmark.js read text there too, and\n * markdown-it a list. The paragraph of a task list item starts after its\n * checkbox, which renderers read as the start of the item's text, so it does\n * not count. Renderers read the `===` below such text as text, of the list\n * item or after an empty one, so a paragraph or heading on the next line\n * continues it too, and a block there is nested: a `---` would underline it.\n * Where such text ends a list item or block quote, renderers continue it\n * lazily into a paragraph or heading on the next line below the container.\n *\n * Forgejo and Gitea read a definition list, which the parser reads as text:\n * `Term` and a line `: 2. x` below it are a term and a description, and the\n * description holds blocks, here an ordered list, as a list item does. The\n * blocks indented below it in its container belong to it too (issue #344).\n *\n * Obsidian starts a list below a paragraph line where CommonMark does not:\n * Live Preview at an ordered marker with a number other than 1 and text after\n * it, except in a block quote, and Reading view at an empty item, `*`, `+`,\n * `- `, or `1.`, which Live Preview reads so for `+ ` and `- ` (issue #375).\n */\nexport function misreadLists(document: Document): MisreadLists {\n const known = found.get(document.tree);\n if (known) return known;\n const { source } = document;\n const forge = document.dialect === \"forgejo\" || document.dialect === \"gitea\";\n const text = new Set<Nodes>();\n const nested = new Set<Nodes>();\n const next = new Set<Nodes>();\n const descriptions = new Set<Nodes>();\n const obsidian = document.dialect === \"obsidian\";\n /** The column of the first character from `offset` on, after spaces and tabs. */\n const columnAt = (offset: number) => {\n let start = offset;\n while (start > 0 && source[start - 1] !== \"\\n\" && source[start - 1] !== \"\\r\") start--;\n let column = 0;\n for (let at = start; at < source.length; at++) {\n const character = source[at];\n if (at >= offset && character !== \" \" && character !== \"\\t\") break;\n column = character === \"\\t\" ? column + 4 - (column % 4) : column + 1;\n }\n return column;\n };\n /** Where a paragraph's or an underlined heading's text starts. */\n const textStart = (node: Nodes): number | undefined => {\n const start = node.position?.start.offset;\n if (start === undefined || node.position?.end.offset === undefined) return undefined;\n if (node.type === \"paragraph\") return start;\n // An underlined heading below link reference definitions starts at them.\n if (node.type === \"heading\" && source[start] !== \"#\")\n return node.children[0]?.position?.start.offset ?? start;\n return undefined;\n };\n /**\n * In the Obsidian dialect, the offset of the marker on the first line of\n * `node` after its first that Obsidian reads as starting a list item where\n * CommonMark reads text; `quoted` says whether `node` is in a block quote.\n */\n const obsidianItem = (node: Nodes, quoted: boolean): number | undefined => {\n const end = node.position!.end.offset!;\n // A marker four or more columns right of the text is more of the text.\n const text = columnAt(node.position!.start.offset!);\n const breaks = /\\r\\n|\\r|\\n/g;\n breaks.lastIndex = node.position!.start.offset!;\n for (let found = breaks.exec(source); found && found.index < end; found = breaks.exec(source)) {\n const lineStart = found.index + found[0].length;\n let lineEnd = lineStart;\n while (lineEnd < end && source[lineEnd] !== \"\\n\" && source[lineEnd] !== \"\\r\") lineEnd++;\n const line = source.slice(lineStart, lineEnd);\n const prefix = /^[ \\t>]*/.exec(line)![0].length;\n const content = line.slice(prefix);\n const ordered = /^(\\d{1,9})[.)][ \\t]+\\S/.exec(content);\n if (\n columnAt(lineStart + prefix) - text <= 3 &&\n ((ordered && Number(ordered[1]) !== 1 && !quoted) ||\n /^(?:[*+]|-(?=[ \\t])|0*1[.)])[ \\t]*$/.test(content))\n )\n return lineStart + prefix;\n }\n return undefined;\n };\n /** Returns the last line of misread text that ends `parent` and whose `===` renderers read as text. */\n const visit = (parent: Parents, quoted = false): number | undefined => {\n let reach: number | undefined;\n /** The last line of misread text whose `===` renderers read as text, if the last block is that. */\n let continued: number | undefined;\n /** Whether that text ends the last block, a container, rather than being it. */\n let inside = false;\n /** The column of the last definition description while the blocks after it may belong to it. */\n let described: number | undefined;\n parent.children.forEach((child, index) => {\n const offset = child.position?.start.offset;\n if (offset === undefined) return;\n const start = textStart(child);\n if (described !== undefined) {\n if (columnAt(offset) > described) nested.add(child);\n else described = undefined;\n }\n if (\n forge &&\n start !== undefined &&\n descriptionLine.test(source.slice(offset, child.position!.end.offset))\n ) {\n descriptions.add(child);\n described = Math.min(described ?? columnAt(offset), columnAt(offset));\n }\n // Renderers continue the text lazily on the line below the container\n // that it ends, but only with text (issue #343).\n const adjacent =\n continued === child.position!.start.line - 1 && (!inside || start !== undefined);\n const atStart =\n start !== undefined &&\n (listMarker.test(source.slice(start, start + 11)) || adjacent) &&\n !(index === 0 && parent.type === \"listItem\" && typeof parent.checked === \"boolean\");\n const item = obsidian && start !== undefined ? obsidianItem(child, quoted) : undefined;\n const misread = atStart || item !== undefined;\n if (misread || adjacent || reach !== undefined) {\n const column = columnAt(atStart ? start! : (item ?? offset));\n if ((adjacent && !misread) || (reach !== undefined && column > reach)) nested.add(child);\n else if (reach !== undefined) {\n next.add(child);\n reach = undefined;\n }\n if (misread) {\n text.add(child);\n reach = Math.min(reach ?? column, column);\n }\n }\n continued =\n misread && child.type === \"heading\" && child.depth === 1\n ? child.position!.end.line\n : undefined;\n inside = false;\n if (\"children\" in child && !leaves.has(child.type)) {\n const last = visit(child, quoted || child.type === \"blockquote\");\n if (last !== undefined && last === child.position!.end.line) {\n continued = last;\n inside = true;\n }\n }\n });\n return continued;\n };\n visit(document.tree);\n const htmlText = new Set<Nodes>();\n const unclosedCode = new Set<Nodes>();\n if (document.dialect === \"obsidian\") {\n /**\n * Leaf blocks in document order, and whether each starts a list item, also\n * inside a container that does, as in `- > a`.\n */\n const order: [Nodes, boolean][] = [];\n const collect = (node: Nodes, item: boolean) => {\n if (leaves.has(node.type) || !(\"children\" in node)) order.push([node, item]);\n else\n node.children.forEach((child, index) =>\n collect(child, index === 0 && (item || node.type === \"listItem\")),\n );\n };\n collect(document.tree, false);\n const lines = source.split(/\\r\\n|\\r|\\n/);\n /** Whether line `number`, counted from 1, holds blank space and more than block quote markers. */\n const spaced = (number: number) => {\n const line = lines[number - 1] ?? \"\";\n return /^[ \\t>]*$/.test(line) && /[^>]/.test(line);\n };\n /**\n * Whether the last leaf block is an HTML block that ends at a blank line, or\n * text that Obsidian reads as more of one, which the next block may continue.\n * Leaf blocks count, not containers, because an empty line inside a list\n * ends the HTML block there.\n */\n let open = false;\n order.forEach(([leaf], index) => {\n const previous = order[index - 1]?.[0];\n if (open && previous?.position && leaf.position) {\n for (let line = previous.position.end.line + 1; line < leaf.position.start.line; line++)\n if (!spaced(line)) open = false;\n if (open) {\n // From the start of its line: a list item's marker there, `- ` in\n // `- *a*`, is text of the HTML block too.\n const offset = leaf.position.start.offset ?? 0;\n let from = offset;\n while (from > 0 && source[from - 1] !== \"\\n\" && source[from - 1] !== \"\\r\") from--;\n const start = { ...leaf.position.start, offset: from, column: 1 };\n htmlText.add(from === offset ? leaf : { ...leaf, position: { ...leaf.position, start } });\n }\n }\n // Other HTML blocks end at their own end marker, as a comment does at `-->`.\n if (\n !open &&\n leaf.type === \"html\" &&\n leaf.position &&\n !/^<(?:!--|\\?|!\\[CDATA\\[|![A-Za-z]|(?:script|pre|style|textarea)(?:[\\s>]|$))/i.test(\n leaf.value.trimStart(),\n )\n )\n open = spaced(leaf.position.end.line + 1);\n });\n /**\n * The runs of backticks that nothing closes in the text of `node`, outside\n * code, math, and wikilinks. Live Preview starts code at them also inside a\n * highlight, an inline comment, and an image's description, whose source\n * the parser does not read as code spans; a backtick in a link's\n * destination or title starts none, but counts in an image's source.\n */\n const openRuns = (node: Nodes): Run[] => {\n const start = node.position?.start.offset;\n const end = node.position?.end.offset;\n if (start === undefined || end === undefined) return [];\n if (\n node.type === \"obsidianHighlight\" ||\n node.type === \"obsidianComment\" ||\n node.type === \"image\" ||\n node.type === \"imageReference\"\n )\n return unclosedRuns(source, start, end);\n // The parser reads every run that another closes as code, so every one\n // left in text is unclosed.\n if (node.type === \"text\") return backtickRuns(source, start, end);\n return \"children\" in node ? node.children.flatMap(openRuns) : [];\n };\n /**\n * The length of a run of three or more backticks whose code Live Preview\n * carries into the blocks below, up to a block with a run of the same\n * length, a fenced code block, or a list item. A run in a wikilink, in math,\n * or in an HTML block closes it too, because Live Preview reads none of\n * those inside the code.\n */\n let carry: number | undefined;\n for (const [leaf, item] of order) {\n const start = leaf.position?.start.offset;\n const end = leaf.position?.end.offset;\n if (start === undefined || end === undefined) continue;\n if (carry !== undefined) {\n const fenced = leaf.type === \"code\" && /^ {0,3}(?:```|~~~)/.test(source.slice(start, end));\n if (item || fenced) carry = undefined;\n else {\n unclosedCode.add(leaf);\n // Live Preview shows an indented code block there as more of the\n // code, and its backticks close nothing.\n if (leaf.type === \"code\") continue;\n const runs = backtickRuns(source, start, end);\n const close = runs.findIndex(([, length]) => length === carry);\n if (close >= 0) carry = carried(source, runs.slice(close + 1));\n continue;\n }\n }\n const parts =\n leaf.type === \"table\"\n ? leaf.children.flatMap((row) => row.children)\n : leaf.type === \"paragraph\" || leaf.type === \"heading\"\n ? [leaf]\n : [];\n const runs = parts.flatMap((part) => {\n const open = openRuns(part);\n if (open.length > 0) unclosedCode.add(part);\n return open;\n });\n const long = runs.find(([, length]) => length >= 3);\n if (long === undefined) continue;\n // Live Preview shows the rest of a table as code from such a run.\n if (leaf.type === \"table\") unclosedCode.add(leaf);\n const after = backtickRuns(source, long[0] + long[1], end);\n const close = after.findIndex(([, length]) => length === long[1]);\n carry = close < 0 ? long[1] : carried(source, after.slice(close + 1));\n }\n }\n const result = { text, nested, next, descriptions, unclosedCode, htmlText };\n found.set(document.tree, result);\n return result;\n}\n\n/** A run of backticks: its offset and its length. */\ntype Run = [number, number];\n\n/**\n * The runs of backticks from `start` to `end`. A backslash before a run\n * escapes its first backtick only.\n */\nfunction backtickRuns(source: string, start: number, end: number): Run[] {\n const runs: Run[] = [];\n for (let at = source.indexOf(\"`\", start); at >= 0 && at < end;) {\n let after = at;\n while (after < end && source[after] === \"`\") after++;\n let slashes = 0;\n while (source[at - 1 - slashes] === \"\\\\\") slashes++;\n const from = slashes % 2 === 0 ? at : at + 1;\n if (after > from) runs.push([from, after - from]);\n at = source.indexOf(\"`\", after);\n }\n return runs;\n}\n\n/**\n * The runs of backticks from `start` to `end` that no later run of the same\n * length there closes, as CommonMark pairs them into code spans.\n */\nfunction unclosedRuns(source: string, start: number, end: number): Run[] {\n const runs = backtickRuns(source, start, end);\n /** The index of the next run of the same length after each run, or -1. */\n const next: number[] = [];\n const later = new Map<number, number>();\n for (let index = runs.length - 1; index >= 0; index--) {\n const length = runs[index]![1];\n next[index] = later.get(length) ?? -1;\n later.set(length, index);\n }\n const open: Run[] = [];\n for (let index = 0; index < runs.length; index++) {\n if (next[index]! < 0) open.push(runs[index]!);\n else index = next[index]!;\n }\n return open;\n}\n\n/**\n * The length of the run of three or more backticks whose code Live Preview\n * carries past the last of `runs`, if any. Live Preview closes a run with the\n * next run of the same length; the code of a run of one or two backticks ends\n * with its line.\n */\nfunction carried(source: string, runs: Run[]): number | undefined {\n let open: Run | undefined;\n /** Where the line of the open run ends, and that of the current one. */\n let openLineEnd = 0;\n let lineEnd = -1;\n for (const run of runs) {\n if (run[0] >= lineEnd) lineEnd = lineBreak(source, run[0]);\n if (open !== undefined) {\n const sameLine = run[0] < openLineEnd;\n if (run[1] === open[1] && (open[1] >= 3 || sameLine)) {\n open = undefined;\n continue;\n }\n // Other runs are part of the code.\n if (open[1] >= 3 || sameLine) continue;\n }\n open = run;\n openLineEnd = lineEnd;\n }\n return open !== undefined && open[1] >= 3 ? open[1] : undefined;\n}\n\n/** The offset of the first line break at or after `from`, or the length of `source`. */\nfunction lineBreak(source: string, from: number): number {\n for (let at = from; at < source.length; at++)\n if (source[at] === \"\\n\" || source[at] === \"\\r\") return at;\n return source.length;\n}\n"]}
@@ -36,7 +36,8 @@ const tokenize = function (effects, ok, nok) {
36
36
  effects.consume(code);
37
37
  count++;
38
38
  if (code === closing.charCodeAt(1) && previous === closing.charCodeAt(0)) {
39
- if (count <= 2)
39
+ // `====` and `[[]]` are text, while Obsidian hides an empty comment, `%%%%`.
40
+ if (count <= 2 && opening !== "%%")
40
41
  return nok(code);
41
42
  effects.exit("obsidianCommentData");
42
43
  effects.exit("obsidianLiteral");
@@ -52,12 +53,16 @@ const tokenize = function (effects, ok, nok) {
52
53
  return start;
53
54
  };
54
55
  // Standalone comment blocks may cross blank lines. Keep their complete source opaque.
56
+ // Obsidian reads a comment as inline wherever a paragraph is open, so one that
57
+ // would interrupt a paragraph, or that text follows on the line where it
58
+ // closes, is left to the inline construct and continues the paragraph (#357).
55
59
  const tokenizeBlockComment = function (effects, ok, nok) {
60
+ const interrupt = this.interrupt;
56
61
  let opened = 0;
57
62
  let previous = null;
58
63
  let closed = false;
59
64
  const start = (code) => {
60
- if (code !== 37)
65
+ if (code !== 37 || interrupt)
61
66
  return nok(code);
62
67
  if (opened === 0) {
63
68
  effects.enter("obsidianBlockComment");
@@ -81,6 +86,9 @@ const tokenizeBlockComment = function (effects, ok, nok) {
81
86
  previous = null;
82
87
  return before;
83
88
  }
89
+ // Only blank space may follow the closing `%%` on its line.
90
+ if (closed && code !== 32 && code !== -1 && code !== -2)
91
+ return nok(code);
84
92
  effects.consume(code);
85
93
  if (code === 37 && previous === 37)
86
94
  closed = true;
@@ -1 +1 @@
1
- {"version":3,"file":"obsidian.js","sourceRoot":"","sources":["../../src/syntax/obsidian.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Literal } from \"mdast\";\nimport type { Extension, State, Tokenizer } from \"micromark-util-types\";\nimport type { Extension as TreeExtension } from \"mdast-util-from-markdown\";\n\n/** An Obsidian wikilink, `[[target|label]]`, or embed, `![[target]]`, in the Obsidian dialect. */\nexport interface WikiLink extends Literal {\n type: \"wikiLink\";\n /** The text between the brackets, with `\\|` read as `|`. */\n value: string;\n /** Whether it is an embed, written with `!` before the brackets. */\n embed: boolean;\n /** The part before the first `|`: a note name or path, and an optional `#heading` or `#^block`. */\n target: string;\n /** The part after the first `|`, when there is one. */\n label?: string;\n}\n/**\n * An Obsidian comment in the Obsidian dialect. `value` is the text between the\n * `%%` markers of a comment in running text, and the whole source of a comment\n * that stands as a block of its own, markers included.\n */\nexport interface ObsidianComment extends Literal {\n type: \"obsidianComment\";\n}\n/** An Obsidian highlight, `==text==`, in the Obsidian dialect. `value` is the text between the markers. */\nexport interface ObsidianHighlight extends Literal {\n type: \"obsidianHighlight\";\n}\ndeclare module \"mdast\" {\n interface RootContentMap {\n wikiLink: WikiLink;\n obsidianComment: ObsidianComment;\n obsidianHighlight: ObsidianHighlight;\n }\n interface PhrasingContentMap {\n wikiLink: WikiLink;\n obsidianComment: ObsidianComment;\n obsidianHighlight: ObsidianHighlight;\n }\n interface BlockContentMap {\n obsidianComment: ObsidianComment;\n }\n}\ndeclare module \"micromark-util-types\" {\n interface TokenTypeMap {\n obsidianLiteral: \"obsidianLiteral\";\n obsidianBlockComment: \"obsidianBlockComment\";\n obsidianCommentData: \"obsidianCommentData\";\n }\n}\n\n/** A tokenizer, not a pre-parse replacement: code, escapes, and fenced blocks stay opaque. */\nconst tokenize: Tokenizer = function (effects, ok, nok) {\n let opening = \"\";\n let closing = \"\";\n let index = 0;\n let previous: number | null = null;\n let count = 0;\n const start: State = (code) => {\n opening = code === 33 ? \"![[\" : code === 91 ? \"[[\" : code === 37 ? \"%%\" : \"==\";\n closing = opening.endsWith(\"[[\") ? \"]]\" : opening;\n effects.enter(\"obsidianLiteral\");\n effects.enter(\"obsidianCommentData\");\n return open(code);\n };\n const open: State = (code) => {\n if (code !== opening.charCodeAt(index)) return nok(code);\n effects.consume(code);\n index++;\n return index === opening.length ? body : open;\n };\n const body: State = (code) => {\n if (code === null || (opening !== \"%%\" && code < 0 && code !== -1 && code !== -2))\n return nok(code);\n if (code < -2) {\n // Micromark subtokenizes each physical line separately. Expose every\n // line ending so a multiline inline comment can span more than two chunks.\n effects.exit(\"obsidianCommentData\");\n effects.enter(\"lineEnding\");\n effects.consume(code);\n effects.exit(\"lineEnding\");\n previous = null;\n count++;\n return resume;\n }\n effects.consume(code);\n count++;\n if (code === closing.charCodeAt(1) && previous === closing.charCodeAt(0)) {\n if (count <= 2) return nok(code);\n effects.exit(\"obsidianCommentData\");\n effects.exit(\"obsidianLiteral\");\n return ok;\n }\n previous = code;\n return body;\n };\n const resume: State = (code) => {\n effects.enter(\"obsidianCommentData\");\n return body(code);\n };\n return start;\n};\n\n// Standalone comment blocks may cross blank lines. Keep their complete source opaque.\nconst tokenizeBlockComment: Tokenizer = function (effects, ok, nok) {\n let opened = 0;\n let previous: number | null = null;\n let closed = false;\n const start: State = (code) => {\n if (code !== 37) return nok(code);\n if (opened === 0) {\n effects.enter(\"obsidianBlockComment\");\n effects.enter(\"obsidianCommentData\");\n }\n effects.consume(code);\n opened++;\n return opened === 2 ? body : start;\n };\n const body: State = (code) => {\n if (code === null || (closed && code < -2)) {\n effects.exit(\"obsidianCommentData\");\n effects.exit(\"obsidianBlockComment\");\n return ok(code);\n }\n if (code < -2) {\n effects.exit(\"obsidianCommentData\");\n effects.enter(\"lineEnding\");\n effects.consume(code);\n effects.exit(\"lineEnding\");\n previous = null;\n return before;\n }\n effects.consume(code);\n if (code === 37 && previous === 37) closed = true;\n previous = code;\n return body;\n };\n const before: State = (code) => {\n if (code === null) {\n effects.exit(\"obsidianBlockComment\");\n return ok(code);\n }\n if (code < -2) {\n effects.enter(\"lineEnding\");\n effects.consume(code);\n effects.exit(\"lineEnding\");\n return before;\n }\n effects.enter(\"obsidianCommentData\");\n return body(code);\n };\n return start;\n};\n\nexport const obsidianSyntax: Extension = {\n flow: { 37: { name: \"obsidianBlockComment\", tokenize: tokenizeBlockComment, concrete: true } },\n text: Object.fromEntries(\n [33, 91, 37, 61].map((code) => [code, { name: \"obsidianLiteral\", tokenize }]),\n ),\n};\nexport const obsidianTree: TreeExtension = {\n enter: {\n obsidianBlockComment(token) {\n this.enter({ type: \"obsidianComment\", value: this.sliceSerialize(token) }, token);\n },\n obsidianLiteral(token) {\n const raw = this.sliceSerialize(token);\n const wiki = raw.startsWith(\"[[\") || raw.startsWith(\"![[\");\n const embed = raw.startsWith(\"!\");\n const value = raw.slice(wiki && embed ? 3 : 2, -2).replaceAll(\"\\\\|\", \"|\");\n const divider = value.indexOf(\"|\");\n const node: WikiLink | ObsidianComment | ObsidianHighlight = wiki\n ? {\n type: \"wikiLink\",\n value,\n embed,\n target: divider < 0 ? value : value.slice(0, divider),\n ...(divider >= 0 ? { label: value.slice(divider + 1) } : {}),\n }\n : { type: raw.startsWith(\"%%\") ? \"obsidianComment\" : \"obsidianHighlight\", value };\n this.enter(node, token);\n },\n },\n exit: {\n obsidianBlockComment(token) {\n this.exit(token);\n },\n obsidianLiteral(token) {\n this.exit(token);\n },\n },\n};\n"]}
1
+ {"version":3,"file":"obsidian.js","sourceRoot":"","sources":["../../src/syntax/obsidian.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Literal } from \"mdast\";\nimport type { Extension, State, Tokenizer } from \"micromark-util-types\";\nimport type { Extension as TreeExtension } from \"mdast-util-from-markdown\";\n\n/** An Obsidian wikilink, `[[target|label]]`, or embed, `![[target]]`, in the Obsidian dialect. */\nexport interface WikiLink extends Literal {\n type: \"wikiLink\";\n /** The text between the brackets, with `\\|` read as `|`. */\n value: string;\n /** Whether it is an embed, written with `!` before the brackets. */\n embed: boolean;\n /** The part before the first `|`: a note name or path, and an optional `#heading` or `#^block`. */\n target: string;\n /** The part after the first `|`, when there is one. */\n label?: string;\n}\n/**\n * An Obsidian comment in the Obsidian dialect. `value` is the text between the\n * `%%` markers of a comment in running text, and the whole source of a comment\n * that stands as a block of its own, markers included.\n */\nexport interface ObsidianComment extends Literal {\n type: \"obsidianComment\";\n}\n/** An Obsidian highlight, `==text==`, in the Obsidian dialect. `value` is the text between the markers. */\nexport interface ObsidianHighlight extends Literal {\n type: \"obsidianHighlight\";\n}\ndeclare module \"mdast\" {\n interface RootContentMap {\n wikiLink: WikiLink;\n obsidianComment: ObsidianComment;\n obsidianHighlight: ObsidianHighlight;\n }\n interface PhrasingContentMap {\n wikiLink: WikiLink;\n obsidianComment: ObsidianComment;\n obsidianHighlight: ObsidianHighlight;\n }\n interface BlockContentMap {\n obsidianComment: ObsidianComment;\n }\n}\ndeclare module \"micromark-util-types\" {\n interface TokenTypeMap {\n obsidianLiteral: \"obsidianLiteral\";\n obsidianBlockComment: \"obsidianBlockComment\";\n obsidianCommentData: \"obsidianCommentData\";\n }\n}\n\n/** A tokenizer, not a pre-parse replacement: code, escapes, and fenced blocks stay opaque. */\nconst tokenize: Tokenizer = function (effects, ok, nok) {\n let opening = \"\";\n let closing = \"\";\n let index = 0;\n let previous: number | null = null;\n let count = 0;\n const start: State = (code) => {\n opening = code === 33 ? \"![[\" : code === 91 ? \"[[\" : code === 37 ? \"%%\" : \"==\";\n closing = opening.endsWith(\"[[\") ? \"]]\" : opening;\n effects.enter(\"obsidianLiteral\");\n effects.enter(\"obsidianCommentData\");\n return open(code);\n };\n const open: State = (code) => {\n if (code !== opening.charCodeAt(index)) return nok(code);\n effects.consume(code);\n index++;\n return index === opening.length ? body : open;\n };\n const body: State = (code) => {\n if (code === null || (opening !== \"%%\" && code < 0 && code !== -1 && code !== -2))\n return nok(code);\n if (code < -2) {\n // Micromark subtokenizes each physical line separately. Expose every\n // line ending so a multiline inline comment can span more than two chunks.\n effects.exit(\"obsidianCommentData\");\n effects.enter(\"lineEnding\");\n effects.consume(code);\n effects.exit(\"lineEnding\");\n previous = null;\n count++;\n return resume;\n }\n effects.consume(code);\n count++;\n if (code === closing.charCodeAt(1) && previous === closing.charCodeAt(0)) {\n // `====` and `[[]]` are text, while Obsidian hides an empty comment, `%%%%`.\n if (count <= 2 && opening !== \"%%\") return nok(code);\n effects.exit(\"obsidianCommentData\");\n effects.exit(\"obsidianLiteral\");\n return ok;\n }\n previous = code;\n return body;\n };\n const resume: State = (code) => {\n effects.enter(\"obsidianCommentData\");\n return body(code);\n };\n return start;\n};\n\n// Standalone comment blocks may cross blank lines. Keep their complete source opaque.\n// Obsidian reads a comment as inline wherever a paragraph is open, so one that\n// would interrupt a paragraph, or that text follows on the line where it\n// closes, is left to the inline construct and continues the paragraph (#357).\nconst tokenizeBlockComment: Tokenizer = function (effects, ok, nok) {\n const interrupt = this.interrupt;\n let opened = 0;\n let previous: number | null = null;\n let closed = false;\n const start: State = (code) => {\n if (code !== 37 || interrupt) return nok(code);\n if (opened === 0) {\n effects.enter(\"obsidianBlockComment\");\n effects.enter(\"obsidianCommentData\");\n }\n effects.consume(code);\n opened++;\n return opened === 2 ? body : start;\n };\n const body: State = (code) => {\n if (code === null || (closed && code < -2)) {\n effects.exit(\"obsidianCommentData\");\n effects.exit(\"obsidianBlockComment\");\n return ok(code);\n }\n if (code < -2) {\n effects.exit(\"obsidianCommentData\");\n effects.enter(\"lineEnding\");\n effects.consume(code);\n effects.exit(\"lineEnding\");\n previous = null;\n return before;\n }\n // Only blank space may follow the closing `%%` on its line.\n if (closed && code !== 32 && code !== -1 && code !== -2) return nok(code);\n effects.consume(code);\n if (code === 37 && previous === 37) closed = true;\n previous = code;\n return body;\n };\n const before: State = (code) => {\n if (code === null) {\n effects.exit(\"obsidianBlockComment\");\n return ok(code);\n }\n if (code < -2) {\n effects.enter(\"lineEnding\");\n effects.consume(code);\n effects.exit(\"lineEnding\");\n return before;\n }\n effects.enter(\"obsidianCommentData\");\n return body(code);\n };\n return start;\n};\n\nexport const obsidianSyntax: Extension = {\n flow: { 37: { name: \"obsidianBlockComment\", tokenize: tokenizeBlockComment, concrete: true } },\n text: Object.fromEntries(\n [33, 91, 37, 61].map((code) => [code, { name: \"obsidianLiteral\", tokenize }]),\n ),\n};\nexport const obsidianTree: TreeExtension = {\n enter: {\n obsidianBlockComment(token) {\n this.enter({ type: \"obsidianComment\", value: this.sliceSerialize(token) }, token);\n },\n obsidianLiteral(token) {\n const raw = this.sliceSerialize(token);\n const wiki = raw.startsWith(\"[[\") || raw.startsWith(\"![[\");\n const embed = raw.startsWith(\"!\");\n const value = raw.slice(wiki && embed ? 3 : 2, -2).replaceAll(\"\\\\|\", \"|\");\n const divider = value.indexOf(\"|\");\n const node: WikiLink | ObsidianComment | ObsidianHighlight = wiki\n ? {\n type: \"wikiLink\",\n value,\n embed,\n target: divider < 0 ? value : value.slice(0, divider),\n ...(divider >= 0 ? { label: value.slice(divider + 1) } : {}),\n }\n : { type: raw.startsWith(\"%%\") ? \"obsidianComment\" : \"obsidianHighlight\", value };\n this.enter(node, token);\n },\n },\n exit: {\n obsidianBlockComment(token) {\n this.exit(token);\n },\n obsidianLiteral(token) {\n this.exit(token);\n },\n },\n};\n"]}
package/docs/design.md CHANGED
@@ -31,9 +31,10 @@ The comparison is only as good as the parser's reading:
31
31
  - It compares syntax trees, and does not run GitHub's, Forgejo's, Gitea's, or
32
32
  Obsidian's renderer. To find documents that renderers read otherwise than the
33
33
  parser, the tests format generated documents and CommonMark's examples and
34
- compare the HTML of commonmark.js and markdown-it before and after, and a
35
- weekly workflow does the same with GitHub's renderer. Each difference found is
36
- tracked as an issue.
34
+ compare the HTML of commonmark.js and markdown-it before and after, a weekly
35
+ workflow does the same with GitHub's renderer, and a check started by hand
36
+ compares Obsidian's Live Preview and Reading view, with Obsidian running in
37
+ Docker. Each difference found is tracked as an issue.
37
38
  - It reads the document in its dialect, so it cannot notice that the dialect is
38
39
  wrong. In CommonMark a table is an ordinary paragraph, and joining its lines
39
40
  changes nothing that CommonMark sees. This is why the tool [assumes a
@@ -146,7 +147,9 @@ Files:
146
147
  Syntax:
147
148
 
148
149
  - Obsidian inline comments that span several paragraphs are not fully read;
149
- suppress formatting around them or use comment blocks. Heading nesting paths
150
+ suppress formatting around them or use comment blocks. A comment on lines of
151
+ its own directly above text is read as a block before a paragraph, where
152
+ Obsidian reads one paragraph; both show the same text. Heading nesting paths
150
153
  in links, property aliases, PDF subpaths, and the syntax of community plugins
151
154
  are not supported.
152
155
  - Forgejo's and Gitea's own syntax, such as definition lists, backslash math,
package/docs/obsidian.md CHANGED
@@ -52,6 +52,38 @@ paragraph is left as written in the cases that
52
52
  are not consistent, or inline syntax that runs from the title into the body. A
53
53
  title that is too long is reported by `reportUnbreakable`.
54
54
 
55
+ ## Where Obsidian reads Markdown its own way
56
+
57
+ Obsidian's Reading view and Live Preview read some Markdown otherwise than
58
+ CommonMark, and otherwise than each other. Where formatting would change what a
59
+ note shows there, the tool keeps the text as written:
60
+
61
+ - A paragraph, heading, or table cell with a backtick that no run of backticks
62
+ closes, such as ``a ` b``, also in a highlight, an inline comment, or the text
63
+ of a link or image. Live Preview shows the text after it as code, at least to
64
+ the end of its line, and Reading view pairs a run of two or more backticks
65
+ with a later, shorter run. No rule changes such a block. A backtick in math or
66
+ a wikilink does not count.
67
+ - The blocks below a run of three or more backticks that nothing closes. Live
68
+ Preview shows them as code too, across blank lines and out of a list item, up
69
+ to a run of the same length outside an indented code block, a fenced code
70
+ block, or a list item. No rule changes them, nor a table that holds such a
71
+ run.
72
+ - A paragraph with a later line that starts a list item in Obsidian, where
73
+ CommonMark reads more of the paragraph: Live Preview starts a list at a number
74
+ other than 1 with text after it, as in `3. Step`, except in a block quote, and
75
+ Reading view at an empty item, `*`, `+`, `- `, or `1.`, as in `Text` and `- `
76
+ below it, which the parser reads as a heading. No rule changes such a
77
+ paragraph, nor the blocks below it that start further right than the marker,
78
+ which Live Preview reads inside the item, or the block after those.
79
+ - A line of blank space that holds a tab, which Reading view reads as more of
80
+ the paragraph above it, and one directly below an HTML block such as
81
+ `<div>…</div>`, which continues the block. The blocks below such a line are
82
+ more of the HTML block too, up to an empty line, and Reading view shows them
83
+ as written. No rule empties the line or changes those blocks. A comment, and
84
+ the other HTML blocks that end at their own end marker, such as `<pre>`, do
85
+ not continue.
86
+
55
87
  ## Vaults inside a larger workspace
56
88
 
57
89
  A note belongs to the nearest vault at or above its directory, wherever the
@@ -6,7 +6,7 @@ mdrefine needs Node.js 22.12 or newer. Install the package in the project that
6
6
  holds your documents:
7
7
 
8
8
  ```sh
9
- npm install --save-dev --save-exact mdrefine@0.2.4
9
+ npm install --save-dev --save-exact mdrefine@0.2.5
10
10
  npx --no-install mdtools --help
11
11
  ```
12
12