@heroiclands/package-build 25.3.0 → 25.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +1 -1
- package/assets/styles/content-base.css +32 -0
- package/docs/api.md +30 -6
- package/docs/authoring/links-and-markup.md +136 -53
- package/docs/commands.md +2 -2
- package/docs/content-format.md +14 -6
- package/docs/diagnostics.md +12 -11
- package/docs/guides/writing-in-invented-scripts.md +62 -35
- package/docs/reference/format-details.md +6 -6
- package/docs/reference/note-types.md +15 -15
- package/docs/reference/theme-pages.md +26 -18
- package/engine/anchors.mjs +14 -0
- package/engine/code-fences.mjs +15 -6
- package/engine/content-blocks.mjs +4 -2
- package/engine/content-figures.mjs +19 -5
- package/engine/content-footnotes.mjs +60 -1
- package/engine/content-index.mjs +1 -1
- package/engine/content-render.mjs +59 -43
- package/engine/content-scripts.mjs +204 -42
- package/engine/content-spans.mjs +73 -5
- package/engine/content-verse.mjs +320 -192
- package/engine/first-use.mjs +43 -12
- package/engine/heading-attributes.mjs +2 -1
- package/engine/journals.mjs +8 -1
- package/engine/markdown-blocks.mjs +3 -2
- package/engine/markup-validation.mjs +17 -0
- package/engine/name-markup.mjs +1 -0
- package/engine/note-vocabulary.mjs +2 -2
- package/engine/pdf-render.mjs +34 -23
- package/engine/prose-lint.mjs +14 -2
- package/engine/run-rows.mjs +1 -1
- package/engine/sql-tables.mjs +1 -1
- package/engine/verse-format.mjs +77 -0
- package/engine/verse-metre.mjs +18 -9
- package/engine/verse-regions.mjs +181 -0
- package/engine/wikilink-pattern.mjs +31 -0
- package/engine/wikilink-syntax.mjs +2 -16
- package/package.json +1 -1
- package/site-theme/static/css/style.css +24 -0
- package/types/engine/code-fences.d.mts +1 -3
- package/types/engine/content-footnotes.d.mts +23 -0
- package/types/engine/content-scripts.d.mts +4 -3
- package/types/engine/content-spans.d.mts +3 -1
- package/types/engine/content-verse.d.mts +69 -74
- package/types/engine/name-markup.d.mts +5 -0
- package/types/engine/verse-format.d.mts +9 -0
- package/types/engine/verse-metre.d.mts +4 -4
- package/types/engine/verse-regions.d.mts +78 -0
- package/types/engine/wikilink-pattern.d.mts +17 -0
- package/types/engine/wikilink-syntax.d.mts +1 -41
package/engine/content-spans.mjs
CHANGED
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
import MarkdownIt from "markdown-it";
|
|
15
15
|
import { alertMarkdownPlugin } from "./content-alerts.mjs";
|
|
16
16
|
import { slugify } from "./content-slug.mjs";
|
|
17
|
-
import { scanVerse } from "./content-verse.mjs";
|
|
17
|
+
import { scanVerse, parseVerse, inlineVerseFindings } from "./content-verse.mjs";
|
|
18
|
+
import { verseDivPlugin } from "./verse-regions.mjs";
|
|
19
|
+
import { codeRegions } from "./code-fences.mjs";
|
|
20
|
+
import { footnoteLabels } from "./content-footnotes.mjs";
|
|
18
21
|
import footnotePlugin from "markdown-it-footnote";
|
|
19
22
|
import { parseExtensionAttributes, refusedAttributes } from "./extension-attributes.mjs";
|
|
20
23
|
import { inlineText } from "./name-markup.mjs";
|
|
@@ -25,8 +28,9 @@ import { cartoucheProblems, glyphProblems } from "./content-glyphs.mjs";
|
|
|
25
28
|
* @param {object} [options] - Surface presentation.
|
|
26
29
|
* @param {boolean} [options.source] - Emit opaque authored source tokens for buffer preview.
|
|
27
30
|
* @param {boolean} [options.spoilers] - Add focusable CSS spoiler wrappers (Foundry).
|
|
31
|
+
* @param {(token: any, state: any) => void} [options.verseInline] - Populate an opaque quoted-verse token during inline parsing.
|
|
28
32
|
*/
|
|
29
|
-
export function spanMarkdownPlugin(md, { spoilers = false, source = false } = {}) {
|
|
33
|
+
export function spanMarkdownPlugin(md, { spoilers = false, source = false, verseInline } = {}) {
|
|
30
34
|
{
|
|
31
35
|
md.renderer.rules.span_open = (tokens, index, options, env, renderer) => {
|
|
32
36
|
const token = tokens[index];
|
|
@@ -110,7 +114,10 @@ export function spanMarkdownPlugin(md, { spoilers = false, source = false } = {}
|
|
|
110
114
|
state.src[start - 1] === "[" &&
|
|
111
115
|
!["lang", "font", "enc"].some((key) => Object.hasOwn(parsed.values, key)) &&
|
|
112
116
|
!parsed.classes.some(
|
|
113
|
-
(name) =>
|
|
117
|
+
(name) =>
|
|
118
|
+
name === "verse" ||
|
|
119
|
+
name === "script" ||
|
|
120
|
+
/^font-(?:mono|serif|sans)$/.test(name),
|
|
114
121
|
)
|
|
115
122
|
)
|
|
116
123
|
return false;
|
|
@@ -141,7 +148,12 @@ export function spanMarkdownPlugin(md, { spoilers = false, source = false } = {}
|
|
|
141
148
|
state.pos = finish;
|
|
142
149
|
return true;
|
|
143
150
|
}
|
|
144
|
-
const
|
|
151
|
+
const verse = parsed.classes.includes("verse") && typeof verseInline === "function";
|
|
152
|
+
const token = state.push(
|
|
153
|
+
verse ? "verse_inline" : "span_open",
|
|
154
|
+
emphasis ?? "span",
|
|
155
|
+
verse ? 0 : 1,
|
|
156
|
+
);
|
|
145
157
|
token.meta = {
|
|
146
158
|
span: true,
|
|
147
159
|
start,
|
|
@@ -164,6 +176,11 @@ export function spanMarkdownPlugin(md, { spoilers = false, source = false } = {}
|
|
|
164
176
|
if (parsed.classes.length) token.attrSet("class", parsed.classes.join(" "));
|
|
165
177
|
for (const [key, value] of Object.entries(parsed.values))
|
|
166
178
|
if (!refusedAttributes({ [key]: value }).length) token.attrSet(key, value);
|
|
179
|
+
if (verse) {
|
|
180
|
+
verseInline(token, state);
|
|
181
|
+
state.pos = finish;
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
167
184
|
const nested = [];
|
|
168
185
|
state.md.inline.parse(state.src.slice(start + 1, end), state.md, state.env, nested);
|
|
169
186
|
for (const child of nested)
|
|
@@ -184,6 +201,7 @@ export function spanMarkdownPlugin(md, { spoilers = false, source = false } = {}
|
|
|
184
201
|
}
|
|
185
202
|
|
|
186
203
|
const parser = new MarkdownIt({ html: true })
|
|
204
|
+
.use(verseDivPlugin)
|
|
187
205
|
.use(footnotePlugin)
|
|
188
206
|
.use(alertMarkdownPlugin)
|
|
189
207
|
.use(spanMarkdownPlugin);
|
|
@@ -296,8 +314,58 @@ export function scanSpans(source) {
|
|
|
296
314
|
for (const poem of scanVerse(text, { checkWorks: false }).blocks) {
|
|
297
315
|
const children = [];
|
|
298
316
|
parser.inline.parse(poem.body, parser, env, children);
|
|
299
|
-
collect(children, (pos) =>
|
|
317
|
+
collect(children, (pos) => poem.bodyStart + pos);
|
|
300
318
|
}
|
|
319
|
+
const raw = text.split("");
|
|
320
|
+
for (const region of codeRegions(text))
|
|
321
|
+
for (let offset = region.start; offset < region.end; offset++)
|
|
322
|
+
if (!/[\r\n]/.test(raw[offset])) raw[offset] = " ";
|
|
323
|
+
const rawText = raw.join("");
|
|
324
|
+
const quoted = [];
|
|
325
|
+
parser.inline.parse(rawText, parser, env, quoted);
|
|
326
|
+
const verseTokens = quoted.filter(
|
|
327
|
+
(token) =>
|
|
328
|
+
token.meta?.span &&
|
|
329
|
+
(token.attrGet("class") ?? "").split(/\s+/).includes("verse") &&
|
|
330
|
+
!spans.some((span) => span.start === token.meta.start && span.end === token.meta.end),
|
|
331
|
+
);
|
|
332
|
+
collect(verseTokens, (pos) => pos);
|
|
333
|
+
for (const match of rawText.matchAll(/\{[^{}\r\n]*(?:\}|$)/gm)) {
|
|
334
|
+
if (
|
|
335
|
+
!parseExtensionAttributes(match[0].slice(1).replace(/\}$/, "")).classes.includes(
|
|
336
|
+
"verse",
|
|
337
|
+
)
|
|
338
|
+
)
|
|
339
|
+
continue;
|
|
340
|
+
if (rawText[match.index - 1] !== "]") continue;
|
|
341
|
+
if (
|
|
342
|
+
spans.some(
|
|
343
|
+
(span) =>
|
|
344
|
+
span.contentEnd + 1 === match.index &&
|
|
345
|
+
span.end >= match.index + match[0].length,
|
|
346
|
+
)
|
|
347
|
+
)
|
|
348
|
+
continue;
|
|
349
|
+
const { line, column } = located(match.index, match.index + match[0].length);
|
|
350
|
+
errors.push({
|
|
351
|
+
line,
|
|
352
|
+
column,
|
|
353
|
+
message:
|
|
354
|
+
"an inline .verse quotation needs balanced brackets and closing {…} attributes",
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
for (const span of spans)
|
|
358
|
+
if (
|
|
359
|
+
span.attrs.some(
|
|
360
|
+
([key, value]) => key === "class" && value.split(/\s+/).includes("verse"),
|
|
361
|
+
)
|
|
362
|
+
) {
|
|
363
|
+
span.verseModel = parseVerse(span.text, {
|
|
364
|
+
inline: true,
|
|
365
|
+
footnotes: footnoteLabels(text),
|
|
366
|
+
});
|
|
367
|
+
errors.push(...inlineVerseFindings(span, text));
|
|
368
|
+
}
|
|
301
369
|
spans.sort((a, b) => a.start - b.start);
|
|
302
370
|
errors.sort((a, b) => a.line - b.line || a.column - b.column);
|
|
303
371
|
return {
|