@descent-vtt/spec-graph 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/CHANGELOG.md +477 -0
  2. package/README.md +109 -17
  3. package/dist/cli.d.ts +2 -2
  4. package/dist/cli.js +38 -19
  5. package/dist/cli.js.map +1 -1
  6. package/dist/directives.d.ts +9 -2
  7. package/dist/directives.js +15 -4
  8. package/dist/directives.js.map +1 -1
  9. package/dist/extract.d.ts +1 -1
  10. package/dist/extract.js +50 -16
  11. package/dist/extract.js.map +1 -1
  12. package/dist/glob.d.ts +44 -44
  13. package/dist/glob.js +152 -116
  14. package/dist/glob.js.map +1 -1
  15. package/dist/identity.d.ts +12 -4
  16. package/dist/identity.js +32 -8
  17. package/dist/identity.js.map +1 -1
  18. package/dist/index.d.ts +3 -3
  19. package/dist/index.js +4 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/lifecycle.js +10 -2
  22. package/dist/lifecycle.js.map +1 -1
  23. package/dist/markdown.d.ts +53 -161
  24. package/dist/markdown.js +42 -864
  25. package/dist/markdown.js.map +1 -1
  26. package/dist/report.d.ts +23 -0
  27. package/dist/report.js +80 -0
  28. package/dist/report.js.map +1 -1
  29. package/dist/rules.js +48 -14
  30. package/dist/rules.js.map +1 -1
  31. package/dist/sections.d.ts +1 -1
  32. package/dist/sections.js +18 -4
  33. package/dist/sections.js.map +1 -1
  34. package/dist/select.d.ts +2 -2
  35. package/dist/select.js +3 -3
  36. package/dist/select.js.map +1 -1
  37. package/dist/source.d.ts +6 -19
  38. package/dist/source.js +4 -70
  39. package/dist/source.js.map +1 -1
  40. package/dist/types.d.ts +23 -3
  41. package/dist/types.js +1 -1
  42. package/dist/types.js.map +1 -1
  43. package/dist/vendor/spec-core/markdown/frontmatter.d.ts +103 -0
  44. package/dist/vendor/spec-core/markdown/frontmatter.js +459 -0
  45. package/dist/vendor/spec-core/markdown/frontmatter.js.map +1 -0
  46. package/dist/vendor/spec-core/markdown/headings.d.ts +45 -0
  47. package/dist/vendor/spec-core/markdown/headings.js +199 -0
  48. package/dist/vendor/spec-core/markdown/headings.js.map +1 -0
  49. package/dist/vendor/spec-core/markdown/index.d.ts +5 -0
  50. package/dist/vendor/spec-core/markdown/index.js +4 -0
  51. package/dist/vendor/spec-core/markdown/index.js.map +1 -0
  52. package/dist/vendor/spec-core/markdown/layout.d.ts +39 -0
  53. package/dist/vendor/spec-core/markdown/layout.js +28 -0
  54. package/dist/vendor/spec-core/markdown/layout.js.map +1 -0
  55. package/dist/vendor/spec-core/markdown/links.d.ts +22 -0
  56. package/dist/vendor/spec-core/markdown/links.js +364 -0
  57. package/dist/vendor/spec-core/markdown/links.js.map +1 -0
  58. package/dist/vendor/spec-core/markdown/lists.d.ts +22 -0
  59. package/dist/vendor/spec-core/markdown/lists.js +127 -0
  60. package/dist/vendor/spec-core/markdown/lists.js.map +1 -0
  61. package/dist/vendor/spec-core/markdown/scan.d.ts +36 -0
  62. package/dist/vendor/spec-core/markdown/scan.js +439 -0
  63. package/dist/vendor/spec-core/markdown/scan.js.map +1 -0
  64. package/dist/vendor/spec-core/markdown/syntax.d.ts +75 -0
  65. package/dist/vendor/spec-core/markdown/syntax.js +181 -0
  66. package/dist/vendor/spec-core/markdown/syntax.js.map +1 -0
  67. package/dist/vendor/spec-core/markdown/tables.d.ts +18 -0
  68. package/dist/vendor/spec-core/markdown/tables.js +86 -0
  69. package/dist/vendor/spec-core/markdown/tables.js.map +1 -0
  70. package/dist/vendor/spec-core/markdown/types.d.ts +287 -0
  71. package/dist/vendor/spec-core/markdown/types.js +9 -0
  72. package/dist/vendor/spec-core/markdown/types.js.map +1 -0
  73. package/dist/vendor/spec-core/path/index.d.ts +1 -0
  74. package/dist/vendor/spec-core/path/index.js +2 -0
  75. package/dist/vendor/spec-core/path/index.js.map +1 -0
  76. package/dist/vendor/spec-core/path/posix.d.ts +83 -0
  77. package/dist/vendor/spec-core/path/posix.js +150 -0
  78. package/dist/vendor/spec-core/path/posix.js.map +1 -0
  79. package/dist/vendor/spec-core/pattern/automaton.d.ts +129 -0
  80. package/dist/vendor/spec-core/pattern/automaton.js +340 -0
  81. package/dist/vendor/spec-core/pattern/automaton.js.map +1 -0
  82. package/dist/vendor/spec-core/pattern/charset.d.ts +58 -0
  83. package/dist/vendor/spec-core/pattern/charset.js +116 -0
  84. package/dist/vendor/spec-core/pattern/charset.js.map +1 -0
  85. package/dist/vendor/spec-core/pattern/glob.d.ts +121 -0
  86. package/dist/vendor/spec-core/pattern/glob.js +481 -0
  87. package/dist/vendor/spec-core/pattern/glob.js.map +1 -0
  88. package/dist/vendor/spec-core/pattern/index.d.ts +6 -0
  89. package/dist/vendor/spec-core/pattern/index.js +4 -0
  90. package/dist/vendor/spec-core/pattern/index.js.map +1 -0
  91. package/dist/{regex.d.ts → vendor/spec-core/pattern/regex.d.ts} +20 -29
  92. package/dist/{regex.js → vendor/spec-core/pattern/regex.js} +40 -49
  93. package/dist/vendor/spec-core/pattern/regex.js.map +1 -0
  94. package/dist/vendor/spec-core/text/index.d.ts +2 -0
  95. package/dist/vendor/spec-core/text/index.js +2 -0
  96. package/dist/vendor/spec-core/text/index.js.map +1 -0
  97. package/dist/vendor/spec-core/text/lines.d.ts +72 -0
  98. package/dist/vendor/spec-core/text/lines.js +156 -0
  99. package/dist/vendor/spec-core/text/lines.js.map +1 -0
  100. package/dist/yaml.d.ts +44 -12
  101. package/dist/yaml.js +115 -206
  102. package/dist/yaml.js.map +1 -1
  103. package/package.json +3 -2
  104. package/src/vendor/spec-core/LICENSE +21 -0
  105. package/src/vendor/spec-core/README.md +8 -0
  106. package/dist/regex.js.map +0 -1
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Headings, their GitHub anchors, and the sections they open.
3
+ *
4
+ * A heading is found in the structure mask, so one written in a code sample
5
+ * or a comment is not one, and its text is read from the prose mask, so a
6
+ * code span in it is kept and a comment after it is not.
7
+ */
8
+ import { isMarkdown, isSpaceOrTab, visibleLead } from './layout.js';
9
+ import { atxLevel, isThematicBreak, leadIndex, listMarker, setextUnderline } from './syntax.js';
10
+ /**
11
+ * GitHub's slug of a heading's text: lower case, punctuation dropped, every
12
+ * whitespace character a hyphen.
13
+ *
14
+ * spec-graph's slug, with two of its steps taken out because a later step
15
+ * did their work: it dropped Markdown's punctuation and then all punctuation,
16
+ * and trimmed before and after. What remains gives the same slug for every
17
+ * text. It drops `_`, which GitHub keeps.
18
+ */
19
+ export function slugify(text) {
20
+ return (text
21
+ .toLowerCase()
22
+ .replace(/[^\p{L}\p{N}\s-]/gu, '')
23
+ .trim()
24
+ // GitHub hyphenates every whitespace character, so a run of two spaces
25
+ // left behind by stripped punctuation becomes two hyphens, not one.
26
+ .replace(/\s/g, '-'));
27
+ }
28
+ /**
29
+ * ATX headings: `#` to `######` opening a line, after at most three spaces.
30
+ *
31
+ * Only a line whose first character is visible in the structure mask is read,
32
+ * and the mask blanks every line of front matter, code and raw-text HTML.
33
+ */
34
+ export function findAtxHeadings(layout) {
35
+ const out = [];
36
+ const strip = commentStripper(layout);
37
+ for (const line of layout.lines) {
38
+ const level = atxLevel(line.content);
39
+ if (level === 0 || !visibleLead(layout, line))
40
+ continue;
41
+ const opened = line.contentStart + leadIndex(line.content) + level;
42
+ const [textStart, textEnd] = atxText(layout.prose, opened, line.end);
43
+ out.push(heading('atx', level, strip(textStart, textEnd), textStart, textEnd, line, line));
44
+ }
45
+ return out;
46
+ }
47
+ /**
48
+ * The text of an ATX heading: trimmed, without a closing sequence. A closing
49
+ * run of `#` counts only after a space or a tab, so `# C#` is about C#. The
50
+ * character at `to` ends the line, and is not a space.
51
+ */
52
+ function atxText(prose, from, to) {
53
+ let start = from;
54
+ while (isSpaceOrTab(prose, start))
55
+ start += 1;
56
+ let end = to;
57
+ while (end > start && isSpaceOrTab(prose, end - 1))
58
+ end -= 1;
59
+ let hashes = end;
60
+ while (hashes > start && prose.charCodeAt(hashes - 1) === 35)
61
+ hashes -= 1;
62
+ // Before a closing run there is the space it needs, or the space after the
63
+ // opening run when the heading is nothing else.
64
+ if (isSpaceOrTab(prose, hashes - 1)) {
65
+ end = hashes;
66
+ while (end > start && isSpaceOrTab(prose, end - 1))
67
+ end -= 1;
68
+ }
69
+ return [start, end];
70
+ }
71
+ /**
72
+ * Every heading in order, ATX and setext, with GitHub's anchors.
73
+ *
74
+ * A setext heading is a paragraph line underlined with `=` or `-`. The line
75
+ * above the underline must be one a paragraph can hold: not a heading, a list
76
+ * item, a thematic break, a table row, blank, or indented four columns.
77
+ * Otherwise `---` is a thematic break, and a table or a list followed by one
78
+ * would gain a heading nobody wrote.
79
+ */
80
+ export function findHeadings(layout, atx, tables) {
81
+ const { lines } = layout;
82
+ const taken = new Set();
83
+ for (const h of atx)
84
+ taken.add(h.line);
85
+ for (const table of tables)
86
+ for (let line = table.line; line <= table.endLine; line += 1)
87
+ taken.add(line);
88
+ const setext = [];
89
+ const strip = commentStripper(layout);
90
+ for (let i = 0; i + 1 < lines.length; i += 1) {
91
+ const above = lines[i];
92
+ const under = lines[i + 1];
93
+ if (taken.has(above.line) || !paragraphLine(layout, above))
94
+ continue;
95
+ if (!isMarkdown(under) || under.quoteDepth !== above.quoteDepth)
96
+ continue;
97
+ const mark = setextUnderline(under.content);
98
+ if (mark === null || !visibleLead(layout, under))
99
+ continue;
100
+ let textStart = above.contentStart;
101
+ while (isSpaceOrTab(layout.prose, textStart))
102
+ textStart += 1;
103
+ let textEnd = above.end;
104
+ while (isSpaceOrTab(layout.prose, textEnd - 1))
105
+ textEnd -= 1;
106
+ setext.push(heading('setext', mark === '=' ? 1 : 2, strip(textStart, textEnd), textStart, textEnd, above, under));
107
+ // The underline is part of this heading, not the text of the next.
108
+ i += 1;
109
+ }
110
+ const all = [...atx, ...setext].sort((a, b) => a.line - b.line);
111
+ const occurrences = new Map();
112
+ return all.map((h) => ({ ...h, anchor: anchorOf(occurrences, h.slug) }));
113
+ }
114
+ /** A line that can be the text of a setext heading. */
115
+ function paragraphLine(layout, line) {
116
+ if (!isMarkdown(line) || line.blank || line.comment || line.indent >= 4)
117
+ return false;
118
+ return !(visibleLead(layout, line) && (listMarker(line.content) !== null || isThematicBreak(line.content)));
119
+ }
120
+ /**
121
+ * GitHub's anchor for a slug: the slug itself the first time, then with `-1`,
122
+ * `-2` and so on, skipping any suffixed form a heading already took.
123
+ */
124
+ function anchorOf(occurrences, slug) {
125
+ let anchor = slug;
126
+ while (occurrences.has(anchor)) {
127
+ const count = occurrences.get(slug) + 1;
128
+ occurrences.set(slug, count);
129
+ anchor = `${slug}-${count}`;
130
+ }
131
+ occurrences.set(anchor, 0);
132
+ return anchor;
133
+ }
134
+ function heading(form, level, text, textStart, textEnd, first, last) {
135
+ return {
136
+ form,
137
+ level,
138
+ text,
139
+ slug: slugify(text),
140
+ start: first.contentStart,
141
+ end: last.end,
142
+ textStart,
143
+ textEnd,
144
+ line: first.line,
145
+ endLine: last.line,
146
+ };
147
+ }
148
+ /**
149
+ * The text between two offsets with the comments inside it taken out, as a
150
+ * renderer shows it. Called with increasing offsets, so it walks the comments
151
+ * once.
152
+ */
153
+ function commentStripper(layout) {
154
+ const { comments, text } = layout;
155
+ let c = 0;
156
+ return (start, end) => {
157
+ let out = '';
158
+ for (let at = start; at < end; at += 1) {
159
+ while (c < comments.length && comments[c].end <= at)
160
+ c += 1;
161
+ const comment = comments[c];
162
+ if (comment === undefined || comment.start > at)
163
+ out += text.charAt(at);
164
+ }
165
+ return out;
166
+ };
167
+ }
168
+ /**
169
+ * Each heading of `level` or deeper with everything under it, up to the next
170
+ * heading at its level or above.
171
+ */
172
+ export function sectionsOf(scan, level = 1) {
173
+ const { headings, index, text } = scan;
174
+ const out = [];
175
+ for (let h = 0; h < headings.length; h += 1) {
176
+ const heading = headings[h];
177
+ if (heading.level < level)
178
+ continue;
179
+ let next;
180
+ for (let k = h + 1; k < headings.length && next === undefined; k += 1) {
181
+ const candidate = headings[k];
182
+ if (candidate.level <= heading.level)
183
+ next = candidate;
184
+ }
185
+ out.push({
186
+ heading,
187
+ start: index.lineStart(heading.line),
188
+ bodyStart: heading.endLine < index.lineCount ? index.lineStart(heading.endLine + 1) : text.length,
189
+ end: next === undefined ? text.length : index.lineStart(next.line),
190
+ endLine: next === undefined ? index.lineCount + 1 : next.line,
191
+ });
192
+ }
193
+ return out;
194
+ }
195
+ /** The first level-one heading, which is what a reader takes as the title. */
196
+ export function titleOf(scan) {
197
+ return scan.headings.find((h) => h.level === 1);
198
+ }
199
+ //# sourceMappingURL=headings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headings.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/markdown/headings.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Headings, their GitHub anchors, and the sections they open.\n *\n * A heading is found in the structure mask, so one written in a code sample\n * or a comment is not one, and its text is read from the prose mask, so a\n * code span in it is kept and a comment after it is not.\n */\n\nimport { isMarkdown, isSpaceOrTab, visibleLead, type Layout } from './layout.js';\nimport { atxLevel, isThematicBreak, leadIndex, listMarker, setextUnderline } from './syntax.js';\nimport type { Heading, HeadingForm, HtmlComment, MarkdownScan, ScannedLine, Section, Table } from './types.js';\n\n/**\n * GitHub's slug of a heading's text: lower case, punctuation dropped, every\n * whitespace character a hyphen.\n *\n * spec-graph's slug, with two of its steps taken out because a later step\n * did their work: it dropped Markdown's punctuation and then all punctuation,\n * and trimmed before and after. What remains gives the same slug for every\n * text. It drops `_`, which GitHub keeps.\n */\nexport function slugify(text: string): string {\n return (\n text\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}\\s-]/gu, '')\n .trim()\n // GitHub hyphenates every whitespace character, so a run of two spaces\n // left behind by stripped punctuation becomes two hyphens, not one.\n .replace(/\\s/g, '-')\n );\n}\n\n/** A heading before GitHub's anchors are counted, which needs every heading. */\nexport type Unanchored = Omit<Heading, 'anchor'>;\n\n/**\n * ATX headings: `#` to `######` opening a line, after at most three spaces.\n *\n * Only a line whose first character is visible in the structure mask is read,\n * and the mask blanks every line of front matter, code and raw-text HTML.\n */\nexport function findAtxHeadings(layout: Layout): Unanchored[] {\n const out: Unanchored[] = [];\n const strip = commentStripper(layout);\n for (const line of layout.lines) {\n const level = atxLevel(line.content);\n if (level === 0 || !visibleLead(layout, line)) continue;\n const opened = line.contentStart + leadIndex(line.content) + level;\n const [textStart, textEnd] = atxText(layout.prose, opened, line.end);\n out.push(heading('atx', level, strip(textStart, textEnd), textStart, textEnd, line, line));\n }\n return out;\n}\n\n/**\n * The text of an ATX heading: trimmed, without a closing sequence. A closing\n * run of `#` counts only after a space or a tab, so `# C#` is about C#. The\n * character at `to` ends the line, and is not a space.\n */\nfunction atxText(prose: string, from: number, to: number): [number, number] {\n let start = from;\n while (isSpaceOrTab(prose, start)) start += 1;\n let end = to;\n while (end > start && isSpaceOrTab(prose, end - 1)) end -= 1;\n let hashes = end;\n while (hashes > start && prose.charCodeAt(hashes - 1) === 35) hashes -= 1;\n // Before a closing run there is the space it needs, or the space after the\n // opening run when the heading is nothing else.\n if (isSpaceOrTab(prose, hashes - 1)) {\n end = hashes;\n while (end > start && isSpaceOrTab(prose, end - 1)) end -= 1;\n }\n return [start, end];\n}\n\n/**\n * Every heading in order, ATX and setext, with GitHub's anchors.\n *\n * A setext heading is a paragraph line underlined with `=` or `-`. The line\n * above the underline must be one a paragraph can hold: not a heading, a list\n * item, a thematic break, a table row, blank, or indented four columns.\n * Otherwise `---` is a thematic break, and a table or a list followed by one\n * would gain a heading nobody wrote.\n */\nexport function findHeadings(layout: Layout, atx: readonly Unanchored[], tables: readonly Table[]): Heading[] {\n const { lines } = layout;\n const taken = new Set<number>();\n for (const h of atx) taken.add(h.line);\n for (const table of tables) for (let line = table.line; line <= table.endLine; line += 1) taken.add(line);\n\n const setext: Unanchored[] = [];\n const strip = commentStripper(layout);\n for (let i = 0; i + 1 < lines.length; i += 1) {\n const above = lines[i] as ScannedLine;\n const under = lines[i + 1] as ScannedLine;\n if (taken.has(above.line) || !paragraphLine(layout, above)) continue;\n if (!isMarkdown(under) || under.quoteDepth !== above.quoteDepth) continue;\n const mark = setextUnderline(under.content);\n if (mark === null || !visibleLead(layout, under)) continue;\n let textStart = above.contentStart;\n while (isSpaceOrTab(layout.prose, textStart)) textStart += 1;\n let textEnd = above.end;\n while (isSpaceOrTab(layout.prose, textEnd - 1)) textEnd -= 1;\n setext.push(heading('setext', mark === '=' ? 1 : 2, strip(textStart, textEnd), textStart, textEnd, above, under));\n // The underline is part of this heading, not the text of the next.\n i += 1;\n }\n\n const all = [...atx, ...setext].sort((a, b) => a.line - b.line);\n const occurrences = new Map<string, number>();\n return all.map((h) => ({ ...h, anchor: anchorOf(occurrences, h.slug) }));\n}\n\n/** A line that can be the text of a setext heading. */\nfunction paragraphLine(layout: Layout, line: ScannedLine): boolean {\n if (!isMarkdown(line) || line.blank || line.comment || line.indent >= 4) return false;\n return !(visibleLead(layout, line) && (listMarker(line.content) !== null || isThematicBreak(line.content)));\n}\n\n/**\n * GitHub's anchor for a slug: the slug itself the first time, then with `-1`,\n * `-2` and so on, skipping any suffixed form a heading already took.\n */\nfunction anchorOf(occurrences: Map<string, number>, slug: string): string {\n let anchor = slug;\n while (occurrences.has(anchor)) {\n const count = (occurrences.get(slug) as number) + 1;\n occurrences.set(slug, count);\n anchor = `${slug}-${count}`;\n }\n occurrences.set(anchor, 0);\n return anchor;\n}\n\nfunction heading(\n form: HeadingForm,\n level: number,\n text: string,\n textStart: number,\n textEnd: number,\n first: ScannedLine,\n last: ScannedLine,\n): Unanchored {\n return {\n form,\n level,\n text,\n slug: slugify(text),\n start: first.contentStart,\n end: last.end,\n textStart,\n textEnd,\n line: first.line,\n endLine: last.line,\n };\n}\n\n/**\n * The text between two offsets with the comments inside it taken out, as a\n * renderer shows it. Called with increasing offsets, so it walks the comments\n * once.\n */\nfunction commentStripper(layout: Layout): (start: number, end: number) => string {\n const { comments, text } = layout;\n let c = 0;\n return (start, end) => {\n let out = '';\n for (let at = start; at < end; at += 1) {\n while (c < comments.length && (comments[c] as HtmlComment).end <= at) c += 1;\n const comment = comments[c];\n if (comment === undefined || comment.start > at) out += text.charAt(at);\n }\n return out;\n };\n}\n\n/**\n * Each heading of `level` or deeper with everything under it, up to the next\n * heading at its level or above.\n */\nexport function sectionsOf(scan: MarkdownScan, level = 1): Section[] {\n const { headings, index, text } = scan;\n const out: Section[] = [];\n for (let h = 0; h < headings.length; h += 1) {\n const heading = headings[h] as Heading;\n if (heading.level < level) continue;\n let next: Heading | undefined;\n for (let k = h + 1; k < headings.length && next === undefined; k += 1) {\n const candidate = headings[k] as Heading;\n if (candidate.level <= heading.level) next = candidate;\n }\n out.push({\n heading,\n start: index.lineStart(heading.line),\n bodyStart: heading.endLine < index.lineCount ? index.lineStart(heading.endLine + 1) : text.length,\n end: next === undefined ? text.length : index.lineStart(next.line),\n endLine: next === undefined ? index.lineCount + 1 : next.line,\n });\n }\n return out;\n}\n\n/** The first level-one heading, which is what a reader takes as the title. */\nexport function titleOf(scan: MarkdownScan): Heading | undefined {\n return scan.headings.find((h) => h.level === 1);\n}\n"]}
@@ -0,0 +1,5 @@
1
+ export { linesOf, scanMarkdown } from './scan.js';
2
+ export { sectionsOf, slugify, titleOf } from './headings.js';
3
+ export { findEntry, frontMatterCloses, frontMatterKind, isNull, keyName, parseInline, readFrontMatter, removeEntry, renderScalar, setEntry, } from './frontmatter.js';
4
+ export type { FrontMatter, FrontMatterEntry, FrontMatterProblem, ReadOptions, YamlScalar, YamlValue, } from './frontmatter.js';
5
+ export type { Block, BlockKind, FrontMatterBlock, FrontMatterKind, Heading, HeadingForm, HtmlComment, Link, LinkForm, ListItem, MarkdownScan, MaskKind, Masks, ScannedLine, Section, Table, TableCell, TableRow, } from './types.js';
@@ -0,0 +1,4 @@
1
+ export { linesOf, scanMarkdown } from './scan.js';
2
+ export { sectionsOf, slugify, titleOf } from './headings.js';
3
+ export { findEntry, frontMatterCloses, frontMatterKind, isNull, keyName, parseInline, readFrontMatter, removeEntry, renderScalar, setEntry, } from './frontmatter.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/markdown/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,MAAM,EACN,OAAO,EACP,WAAW,EACX,eAAe,EACf,WAAW,EACX,YAAY,EACZ,QAAQ,GACT,MAAM,kBAAkB,CAAC","sourcesContent":["export { linesOf, scanMarkdown } from './scan.js';\nexport { sectionsOf, slugify, titleOf } from './headings.js';\nexport {\n findEntry,\n frontMatterCloses,\n frontMatterKind,\n isNull,\n keyName,\n parseInline,\n readFrontMatter,\n removeEntry,\n renderScalar,\n setEntry,\n} from './frontmatter.js';\nexport type {\n FrontMatter,\n FrontMatterEntry,\n FrontMatterProblem,\n ReadOptions,\n YamlScalar,\n YamlValue,\n} from './frontmatter.js';\nexport type {\n Block,\n BlockKind,\n FrontMatterBlock,\n FrontMatterKind,\n Heading,\n HeadingForm,\n HtmlComment,\n Link,\n LinkForm,\n ListItem,\n MarkdownScan,\n MaskKind,\n Masks,\n ScannedLine,\n Section,\n Table,\n TableCell,\n TableRow,\n} from './types.js';\n"]}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * What the readers of headings, list items, links and tables work from: the
3
+ * lines as the block pass classified them, and the masks.
4
+ */
5
+ import type { LineIndex } from '../text/index.js';
6
+ import type { Block, HtmlComment, ScannedLine } from './types.js';
7
+ export interface Layout {
8
+ readonly text: string;
9
+ readonly index: LineIndex;
10
+ readonly lines: readonly ScannedLine[];
11
+ readonly blocks: readonly Block[];
12
+ readonly comments: readonly HtmlComment[];
13
+ readonly structure: string;
14
+ readonly prose: string;
15
+ /**
16
+ * The lines, by number, that start inside a code span or comment opened on
17
+ * an earlier line, so nothing on them opens a block.
18
+ */
19
+ readonly covered: ReadonlySet<number>;
20
+ /**
21
+ * The lines, by number, that would continue a paragraph on the line before
22
+ * them: not blank, opening nothing of their own, and not after a heading.
23
+ * Only asked of a line after one that is not blank.
24
+ */
25
+ readonly continues: ReadonlySet<number>;
26
+ }
27
+ /** A line whose content is Markdown: not front matter, code or raw-text HTML. */
28
+ export declare function isMarkdown(line: ScannedLine): boolean;
29
+ /** Offset of a line's first non-blank character, or its end when it is blank. */
30
+ export declare function leadOffset(line: ScannedLine): number;
31
+ /**
32
+ * Whether a line's first non-blank character is structure. A heading or a
33
+ * list marker is only one when it is the first thing on its line, and the
34
+ * first thing on a line that closes a comment or a code span is the end of
35
+ * that comment or span, whatever follows it.
36
+ */
37
+ export declare function visibleLead(layout: Layout, line: ScannedLine): boolean;
38
+ /** Whether the character at an offset of a text is a space or a tab. */
39
+ export declare function isSpaceOrTab(text: string, at: number): boolean;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * What the readers of headings, list items, links and tables work from: the
3
+ * lines as the block pass classified them, and the masks.
4
+ */
5
+ import { leadIndex } from './syntax.js';
6
+ /** A line whose content is Markdown: not front matter, code or raw-text HTML. */
7
+ export function isMarkdown(line) {
8
+ return !line.frontMatter && !line.code && !line.html;
9
+ }
10
+ /** Offset of a line's first non-blank character, or its end when it is blank. */
11
+ export function leadOffset(line) {
12
+ return line.contentStart + leadIndex(line.content);
13
+ }
14
+ /**
15
+ * Whether a line's first non-blank character is structure. A heading or a
16
+ * list marker is only one when it is the first thing on its line, and the
17
+ * first thing on a line that closes a comment or a code span is the end of
18
+ * that comment or span, whatever follows it.
19
+ */
20
+ export function visibleLead(layout, line) {
21
+ return layout.structure.charCodeAt(leadOffset(line)) !== 32;
22
+ }
23
+ /** Whether the character at an offset of a text is a space or a tab. */
24
+ export function isSpaceOrTab(text, at) {
25
+ const ch = text.charCodeAt(at);
26
+ return ch === 32 || ch === 9;
27
+ }
28
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/markdown/layout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAwBxC,iFAAiF;AACjF,MAAM,UAAU,UAAU,CAAC,IAAiB;IAC1C,OAAO,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACvD,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,UAAU,CAAC,IAAiB;IAC1C,OAAO,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACrD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,IAAiB;IAC3D,OAAO,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;AAC9D,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,EAAU;IACnD,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAC/B,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AAC/B,CAAC","sourcesContent":["/**\n * What the readers of headings, list items, links and tables work from: the\n * lines as the block pass classified them, and the masks.\n */\n\nimport type { LineIndex } from '../text/index.js';\nimport { leadIndex } from './syntax.js';\nimport type { Block, HtmlComment, ScannedLine } from './types.js';\n\nexport interface Layout {\n readonly text: string;\n readonly index: LineIndex;\n readonly lines: readonly ScannedLine[];\n readonly blocks: readonly Block[];\n readonly comments: readonly HtmlComment[];\n readonly structure: string;\n readonly prose: string;\n /**\n * The lines, by number, that start inside a code span or comment opened on\n * an earlier line, so nothing on them opens a block.\n */\n readonly covered: ReadonlySet<number>;\n /**\n * The lines, by number, that would continue a paragraph on the line before\n * them: not blank, opening nothing of their own, and not after a heading.\n * Only asked of a line after one that is not blank.\n */\n readonly continues: ReadonlySet<number>;\n}\n\n/** A line whose content is Markdown: not front matter, code or raw-text HTML. */\nexport function isMarkdown(line: ScannedLine): boolean {\n return !line.frontMatter && !line.code && !line.html;\n}\n\n/** Offset of a line's first non-blank character, or its end when it is blank. */\nexport function leadOffset(line: ScannedLine): number {\n return line.contentStart + leadIndex(line.content);\n}\n\n/**\n * Whether a line's first non-blank character is structure. A heading or a\n * list marker is only one when it is the first thing on its line, and the\n * first thing on a line that closes a comment or a code span is the end of\n * that comment or span, whatever follows it.\n */\nexport function visibleLead(layout: Layout, line: ScannedLine): boolean {\n return layout.structure.charCodeAt(leadOffset(line)) !== 32;\n}\n\n/** Whether the character at an offset of a text is a space or a tab. */\nexport function isSpaceOrTab(text: string, at: number): boolean {\n const ch = text.charCodeAt(at);\n return ch === 32 || ch === 9;\n}\n"]}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Links, images and reference definitions, read from the structure mask so
3
+ * that nothing in code or a comment is one.
4
+ *
5
+ * Six forms: inline `[text](dest "title")`, full and collapsed reference
6
+ * `[text][label]` and `[label][]`, shortcut `[label]`, autolink `<https://x>`,
7
+ * wiki `[[target|text]]`, and the definition `[label]: dest` the reference
8
+ * forms are read through. Each may be an image, written with a leading `!`.
9
+ *
10
+ * Brackets are paired once per paragraph with a stack, and the tables that
11
+ * say where a destination or a title ends are built once per paragraph, so
12
+ * no bracket searches the text again for its partner. A document of nothing
13
+ * but brackets costs its length.
14
+ *
15
+ * A paragraph ends at `to`, and the character there is a line terminator,
16
+ * which no loop here acts on; nor is any lookup made at the first three
17
+ * offsets of a paragraph, before the shortest `[](` could end. Mutants that
18
+ * move a bound onto those places change no answer, and are equivalent.
19
+ */
20
+ import { type Layout } from './layout.js';
21
+ import type { Link } from './types.js';
22
+ export declare function findLinks(layout: Layout): Link[];