mdrefine 0.2.2 → 0.2.3
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/CHANGELOG.md +23 -0
- package/CONTRIBUTING.md +5 -0
- package/README.md +1 -1
- package/dist/rules/blocks.d.ts +9 -0
- package/dist/rules/blocks.js +22 -0
- package/dist/rules/blocks.js.map +1 -1
- package/dist/rules/links.js +25 -4
- package/dist/rules/links.js.map +1 -1
- package/dist/rules/style.js +4 -3
- package/dist/rules/style.js.map +1 -1
- package/dist/syntax/misread-lists.d.ts +2 -0
- package/dist/syntax/misread-lists.js +17 -3
- package/dist/syntax/misread-lists.js.map +1 -1
- package/docs/design.md +15 -9
- package/docs/quick-start.md +1 -1
- package/docs/rules.md +17 -8
- package/package.json +1 -1
|
@@ -42,5 +42,7 @@ export interface MisreadLists {
|
|
|
42
42
|
* not count. Renderers read the `===` below such text as text, of the list
|
|
43
43
|
* item or after an empty one, so a paragraph or heading on the next line
|
|
44
44
|
* continues it too, and a block there is nested: a `---` would underline it.
|
|
45
|
+
* Where such text ends a list item or block quote, renderers continue it
|
|
46
|
+
* lazily into a paragraph or heading on the next line below the container.
|
|
45
47
|
*/
|
|
46
48
|
export declare function misreadLists(document: Document): MisreadLists;
|
|
@@ -23,6 +23,8 @@ const found = new WeakMap();
|
|
|
23
23
|
* not count. Renderers read the `===` below such text as text, of the list
|
|
24
24
|
* item or after an empty one, so a paragraph or heading on the next line
|
|
25
25
|
* continues it too, and a block there is nested: a `---` would underline it.
|
|
26
|
+
* Where such text ends a list item or block quote, renderers continue it
|
|
27
|
+
* lazily into a paragraph or heading on the next line below the container.
|
|
26
28
|
*/
|
|
27
29
|
export function misreadLists(document) {
|
|
28
30
|
const known = found.get(document.tree);
|
|
@@ -58,16 +60,21 @@ export function misreadLists(document) {
|
|
|
58
60
|
return node.children[0]?.position?.start.offset ?? start;
|
|
59
61
|
return undefined;
|
|
60
62
|
};
|
|
63
|
+
/** Returns the last line of misread text that ends `parent` and whose `===` renderers read as text. */
|
|
61
64
|
const visit = (parent) => {
|
|
62
65
|
let reach;
|
|
63
66
|
/** The last line of misread text whose `===` renderers read as text, if the last block is that. */
|
|
64
67
|
let continued;
|
|
68
|
+
/** Whether that text ends the last block, a container, rather than being it. */
|
|
69
|
+
let inside = false;
|
|
65
70
|
parent.children.forEach((child, index) => {
|
|
66
71
|
const offset = child.position?.start.offset;
|
|
67
72
|
if (offset === undefined)
|
|
68
73
|
return;
|
|
69
74
|
const start = textStart(child);
|
|
70
|
-
|
|
75
|
+
// Renderers continue the text lazily on the line below the container
|
|
76
|
+
// that it ends, but only with text (issue #343).
|
|
77
|
+
const adjacent = continued === child.position.start.line - 1 && (!inside || start !== undefined);
|
|
71
78
|
const misread = start !== undefined &&
|
|
72
79
|
(listMarker.test(source.slice(start, start + 11)) || adjacent) &&
|
|
73
80
|
!(index === 0 && parent.type === "listItem" && typeof parent.checked === "boolean");
|
|
@@ -88,9 +95,16 @@ export function misreadLists(document) {
|
|
|
88
95
|
misread && child.type === "heading" && child.depth === 1
|
|
89
96
|
? child.position.end.line
|
|
90
97
|
: undefined;
|
|
91
|
-
|
|
92
|
-
|
|
98
|
+
inside = false;
|
|
99
|
+
if ("children" in child && !leaves.has(child.type)) {
|
|
100
|
+
const last = visit(child);
|
|
101
|
+
if (last !== undefined && last === child.position.end.line) {
|
|
102
|
+
continued = last;
|
|
103
|
+
inside = true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
93
106
|
});
|
|
107
|
+
return continued;
|
|
94
108
|
};
|
|
95
109
|
visit(document.tree);
|
|
96
110
|
const result = { text, nested, next };
|
|
@@ -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/** Text that the parser read where renderers may read a list, and the blocks after it. */\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 in its container whose first lines start\n * further right than the text, up to one that does not. Renderers may read\n * them inside the list's last item, where their indentation counts from the\n * item's text: an indented code block can be a paragraph there.\n */\n nested: ReadonlySet<Nodes>;\n /**\n * The block after those, which starts no further right than the text.\n * Renderers may read it as more items of the list.\n */\n next: 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 */\nexport function misreadLists(document: Document): MisreadLists {\n const known = found.get(document.tree);\n if (known) return known;\n const { source } = document;\n const text = new Set<Nodes>();\n const nested = new Set<Nodes>();\n const next = 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 const visit = (parent: Parents) => {\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 parent.children.forEach((child, index) => {\n const offset = child.position?.start.offset;\n if (offset === undefined) return;\n const start = textStart(child);\n const adjacent = continued === child.position!.start.line - 1;\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 if (\"children\" in child && !leaves.has(child.type)) visit(child);\n });\n };\n visit(document.tree);\n const result = { text, nested, next };\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":"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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/** Text that the parser read where renderers may read a list, and the blocks after it. */\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 in its container whose first lines start\n * further right than the text, up to one that does not. Renderers may read\n * them inside the list's last item, where their indentation counts from the\n * item's text: an indented code block can be a paragraph there.\n */\n nested: ReadonlySet<Nodes>;\n /**\n * The block after those, which starts no further right than the text.\n * Renderers may read it as more items of the list.\n */\n next: 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 */\nexport function misreadLists(document: Document): MisreadLists {\n const known = found.get(document.tree);\n if (known) return known;\n const { source } = document;\n const text = new Set<Nodes>();\n const nested = new Set<Nodes>();\n const next = 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 parent.children.forEach((child, index) => {\n const offset = child.position?.start.offset;\n if (offset === undefined) return;\n const start = textStart(child);\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 };\n found.set(document.tree, result);\n return result;\n}\n"]}
|
package/docs/design.md
CHANGED
|
@@ -52,14 +52,15 @@ The comparison is only as good as the parser's reading:
|
|
|
52
52
|
there are left out, plugins' too, and so are their findings. The list rules
|
|
53
53
|
also leave a list there, or directly after it, as written, because another
|
|
54
54
|
marker or indentation could join it to that list or move it out of the list,
|
|
55
|
-
and `style/block-spacing` adds no blank line that would make the list loose
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
55
|
+
and `style/block-spacing` adds no blank line that would make the list loose,
|
|
56
|
+
or that would end text that renderers continue on the line below the list. The
|
|
57
|
+
same holds below a link reference definition, where the parser and GitHub read
|
|
58
|
+
such a line as text and markdown-it reads a list. Below an empty list item
|
|
59
|
+
(`-`), the parser takes the `[x]` that begins the next line for a checkbox
|
|
60
|
+
that belongs to no item, where GitHub shows the text `[x]`, so a blank line
|
|
61
|
+
between them, as `style/block-spacing` would add, is refused as a change of
|
|
62
|
+
meaning. The parser also keeps the spaces and tabs that start a code span's
|
|
63
|
+
next line, where CommonMark and GitHub leave them out, so that a span
|
|
63
64
|
`npm run` continued by an indented `build` reads `npm run build`, and it
|
|
64
65
|
takes a space or line ending off each end of a span before its line endings
|
|
65
66
|
become spaces, where CommonMark takes spaces off after. The comparison reads a
|
|
@@ -73,7 +74,12 @@ The comparison is only as good as the parser's reading:
|
|
|
73
74
|
lines of another table as text, where GitHub shows a table, so `style/wrap`
|
|
74
75
|
and `style/block-spacing` leave text whose second line is a table delimiter
|
|
75
76
|
row as written ([issue
|
|
76
|
-
#283](https://github.com/viell-dev/slop-markdown-tools/issues/283)).
|
|
77
|
+
#283](https://github.com/viell-dev/slop-markdown-tools/issues/283)). A fenced
|
|
78
|
+
code block without its closing fence runs to the end of its list item, and
|
|
79
|
+
CommonMark and GitHub count the blank lines at the end of the item as code,
|
|
80
|
+
where the parser does not, so `style/block-spacing` adds no blank line below
|
|
81
|
+
such a list ([issue
|
|
82
|
+
#350](https://github.com/viell-dev/slop-markdown-tools/issues/350)).
|
|
77
83
|
- Front matter needs a closing line. A first line of `---` or `+++` that no
|
|
78
84
|
later line closes is read as renderers read it, as a thematic break or text,
|
|
79
85
|
with the lists and block quotes below it; the parser's front matter extension
|
package/docs/quick-start.md
CHANGED
package/docs/rules.md
CHANGED
|
@@ -245,7 +245,9 @@ label shows its target as text, and a note embed is not the same thing as a
|
|
|
245
245
|
Markdown image. A new wikilink decodes percent escapes, because Obsidian takes
|
|
246
246
|
its text as the note's name: `[x](My%20Note.md)` becomes `[[My Note.md|x]]`. A
|
|
247
247
|
destination that does not decode, or whose name would hold `|`, `[`, `]`, `#`,
|
|
248
|
-
or `^`, stays as written.
|
|
248
|
+
or `^`, stays as written. In a table cell, a `|` that the rule writes, between a
|
|
249
|
+
new wikilink's target and label or in a new Markdown label, is escaped as `\|`,
|
|
250
|
+
because one that is not escaped ends the cell.
|
|
249
251
|
|
|
250
252
|
With `"style": "markdown"`, before:
|
|
251
253
|
|
|
@@ -293,11 +295,14 @@ only when the new destination leads to the same file and fragment.
|
|
|
293
295
|
A relative path also gets `./` when it would otherwise name a different file at
|
|
294
296
|
the vault's root. A destination that already has the configured spelling keeps
|
|
295
297
|
its percent-encoding; a new path encodes `%` and `#`, so that it names the same
|
|
296
|
-
file
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
is
|
|
298
|
+
file, and in a table cell writes a `|` in a name as `\|`, because one that is
|
|
299
|
+
not escaped ends the cell. In a wikilink only the destination changes: the `|`
|
|
300
|
+
or `\|` after it, the label, and an embed's size stay as written. Absolute
|
|
301
|
+
filesystem paths are never written. These are left as written: a wikilink
|
|
302
|
+
without a label, whose target is also its visible text; reference definitions,
|
|
303
|
+
which are checked but not rewritten; autolinks; and links whose target is
|
|
304
|
+
uncertain because a directory could not be read or the workspace root is only
|
|
305
|
+
part of a vault (see [Obsidian
|
|
301
306
|
vaults](obsidian.md#a-workspace-root-inside-a-vault)).
|
|
302
307
|
|
|
303
308
|
With `{ "style": "relative", "leadingDot": true }` in `README.md`, before:
|
|
@@ -677,7 +682,9 @@ or what a comment applies to:
|
|
|
677
682
|
blocks of a list item makes the list loose, which changes how it renders.
|
|
678
683
|
- Front matter and the block below it.
|
|
679
684
|
- A list that ends inside an HTML comment or another HTML block without its end
|
|
680
|
-
marker, which would take the blank line in.
|
|
685
|
+
marker, which would take the blank line in. The same goes for a list whose
|
|
686
|
+
last item ends in a fenced code block without its closing fence: renderers put
|
|
687
|
+
the blank line into the code, although the parser does not.
|
|
681
688
|
- A heading or list directly below an HTML comment or below a
|
|
682
689
|
`mdtools-disable-next-line` directive, which apply to the line below them.
|
|
683
690
|
- The line that opens a callout or alert, such as `> [!NOTE]`, and the block
|
|
@@ -691,7 +698,9 @@ or what a comment applies to:
|
|
|
691
698
|
- Text that the parser reads where renderers read a list, such as `- 2. Step`
|
|
692
699
|
directly below text: the list or quote that starts with it, the blocks
|
|
693
700
|
indented below it, and a list after them, which renderers read as part of that
|
|
694
|
-
list
|
|
701
|
+
list, and text on the line directly below the list item or quote that it ends,
|
|
702
|
+
which renderers read as more of it (see [how it
|
|
703
|
+
works](design.md#safety-model)).
|
|
695
704
|
- Directly below a table that ends in a list item or block quote: text whose
|
|
696
705
|
second line is a table delimiter row. The parser reads a table there as text,
|
|
697
706
|
where GitHub reads a table, and a blank line would make it a table for the
|