@heroiclands/package-build 22.21.0 → 22.22.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 (110) hide show
  1. package/CHANGELOG.md +191 -0
  2. package/assets/styles/content-base.css +162 -0
  3. package/bin/content-commands.mjs +26 -3
  4. package/bin/package-build.mjs +15 -2
  5. package/ci/content-format-reference.mjs +68 -1
  6. package/config.mjs +26 -0
  7. package/content-config.mjs +73 -4
  8. package/docs/api.md +36 -18
  9. package/docs/authoring/dates-and-calendars.md +4 -2
  10. package/docs/authoring/frontmatter.md +2 -2
  11. package/docs/authoring/links-and-markup.md +237 -28
  12. package/docs/configuration.md +27 -1
  13. package/docs/content-format.md +3 -1
  14. package/docs/guides/reference-pages.md +15 -0
  15. package/docs/reference/format-details.md +224 -46
  16. package/docs/reference/note-types.md +21 -4
  17. package/engine/actor-compiler.mjs +23 -0
  18. package/engine/anchored-sections.mjs +35 -4
  19. package/engine/anchors.mjs +10 -20
  20. package/engine/base-compiler.mjs +86 -21
  21. package/engine/base-styles.mjs +149 -0
  22. package/engine/bundles.mjs +0 -1
  23. package/engine/compendiums.mjs +8 -1
  24. package/engine/content-blocks.mjs +410 -0
  25. package/engine/content-captions.mjs +57 -8
  26. package/engine/content-footnotes.mjs +189 -0
  27. package/engine/content-format-check.mjs +15 -12
  28. package/engine/content-index.mjs +2 -2
  29. package/engine/content-links.mjs +14 -6
  30. package/engine/content-tables.mjs +45 -4
  31. package/engine/content-tasklists.mjs +189 -0
  32. package/engine/docs-checks.mjs +4 -4
  33. package/engine/extension-attributes.mjs +48 -2
  34. package/engine/frontmatter-lint.mjs +47 -64
  35. package/engine/frontmatter.mjs +3 -3
  36. package/engine/heading-attributes.mjs +308 -0
  37. package/engine/helpers.mjs +14 -13
  38. package/engine/homepage.mjs +8 -8
  39. package/engine/index.mjs +3 -0
  40. package/engine/infobox-render.mjs +15 -3
  41. package/engine/infobox.mjs +83 -8
  42. package/engine/journals.mjs +36 -17
  43. package/engine/macros.mjs +1 -1
  44. package/engine/markdown-expressions.mjs +178 -53
  45. package/engine/note-dates.mjs +49 -0
  46. package/engine/note-frontmatter.mjs +7 -16
  47. package/engine/note-vocabulary.mjs +172 -37
  48. package/engine/page-lists.mjs +358 -0
  49. package/engine/pdf-build.mjs +76 -42
  50. package/engine/pdf-render.mjs +422 -49
  51. package/engine/rank-ladder.mjs +198 -0
  52. package/engine/reckoning-markers.mjs +1 -1
  53. package/engine/retired-fields.mjs +8 -13
  54. package/engine/scenes.mjs +10 -3
  55. package/engine/site-build.mjs +41 -12
  56. package/engine/site-config.mjs +10 -1
  57. package/engine/site-index.mjs +18 -2
  58. package/engine/site-preview.mjs +18 -7
  59. package/engine/social-ties.mjs +52 -14
  60. package/engine/sql-tables.mjs +66 -9
  61. package/engine/standings.mjs +89 -6
  62. package/engine/system-block.mjs +12 -14
  63. package/engine/web-wikilinks.mjs +48 -1
  64. package/hm3/actors.mjs +6 -3
  65. package/manifest.mjs +13 -0
  66. package/package.json +1 -1
  67. package/sohl/actors.mjs +22 -99
  68. package/sohl/item-fields.mjs +4 -5
  69. package/sohl/items.mjs +1 -1
  70. package/sohl/note-schemas.mjs +11 -21
  71. package/types/config.d.mts +9 -0
  72. package/types/engine/actor-compiler.d.mts +11 -0
  73. package/types/engine/anchored-sections.d.mts +24 -0
  74. package/types/engine/base-compiler.d.mts +19 -0
  75. package/types/engine/base-styles.d.mts +93 -0
  76. package/types/engine/content-blocks.d.mts +87 -0
  77. package/types/engine/content-captions.d.mts +14 -1
  78. package/types/engine/content-footnotes.d.mts +73 -0
  79. package/types/engine/content-format-check.d.mts +8 -6
  80. package/types/engine/content-tables.d.mts +12 -4
  81. package/types/engine/content-tasklists.d.mts +72 -0
  82. package/types/engine/extension-attributes.d.mts +22 -1
  83. package/types/engine/frontmatter.d.mts +1 -1
  84. package/types/engine/heading-attributes.d.mts +174 -0
  85. package/types/engine/helpers.d.mts +7 -4
  86. package/types/engine/homepage.d.mts +7 -7
  87. package/types/engine/index.d.mts +1 -0
  88. package/types/engine/infobox-render.d.mts +6 -1
  89. package/types/engine/journals.d.mts +14 -7
  90. package/types/engine/markdown-expressions.d.mts +23 -0
  91. package/types/engine/note-frontmatter.d.mts +1 -4
  92. package/types/engine/note-vocabulary.d.mts +82 -6
  93. package/types/engine/page-lists.d.mts +126 -0
  94. package/types/engine/pdf-render.d.mts +72 -2
  95. package/types/engine/rank-ladder.d.mts +32 -0
  96. package/types/engine/retired-fields.d.mts +4 -6
  97. package/types/engine/site-build.d.mts +13 -1
  98. package/types/engine/site-config.d.mts +9 -0
  99. package/types/engine/site-index.d.mts +13 -1
  100. package/types/engine/site-preview.d.mts +1 -1
  101. package/types/engine/sql-tables.d.mts +31 -7
  102. package/types/engine/standings.d.mts +21 -3
  103. package/types/engine/system-block.d.mts +11 -12
  104. package/types/engine/web-wikilinks.d.mts +3 -1
  105. package/types/hm3/actors.d.mts +3 -3
  106. package/types/sohl/actors.d.mts +6 -7
  107. package/engine/content-admonitions.mjs +0 -114
  108. package/engine/content-secrets.mjs +0 -112
  109. package/types/engine/content-admonitions.d.mts +0 -24
  110. package/types/engine/content-secrets.d.mts +0 -17
@@ -1,114 +0,0 @@
1
- /* SPDX-License-Identifier: GPL-3.0-or-later */
2
-
3
- import MarkdownIt from "markdown-it";
4
- import footnotePlugin from "markdown-it-footnote";
5
- import deflistPlugin from "markdown-it-deflist";
6
- import { parseExtensionAttributes } from "./extension-attributes.mjs";
7
-
8
- const parser = new MarkdownIt({ html: true }).use(footnotePlugin).use(deflistPlugin);
9
- const OPEN = /^:::(info|warn)(?:\s+(.*))?\s*$/;
10
- const CLOSE = /^:::\s*$/;
11
- const STYLES = Object.freeze({
12
- info: { label: "Info", icon: "ℹ", color: "#2f6f9f", background: "#eef6fb" },
13
- warn: { label: "Warning", icon: "⚠", color: "#9a6700", background: "#fff5db" },
14
- });
15
-
16
- /** Find inline info and warning blocks without interpreting code examples. */
17
- export function scanAdmonitions(source) {
18
- const lines = String(source ?? "").split("\n");
19
- const blocks = [];
20
- const errors = [];
21
- let opening = null;
22
- let codeFence = null;
23
- for (let i = 0; i < lines.length; i++) {
24
- const line = lines[i];
25
- const fence = /^ {0,3}(`{3,}|~{3,})/.exec(line);
26
- if (codeFence) {
27
- if (fence && fence[1][0] === codeFence[0] && fence[1].length >= codeFence.length)
28
- codeFence = null;
29
- continue;
30
- }
31
- if (fence) {
32
- codeFence = fence[1];
33
- continue;
34
- }
35
- const open = OPEN.exec(line);
36
- if (open) {
37
- if (opening) {
38
- errors.push({
39
- line: i + 1,
40
- column: 1,
41
- message: "nested info and warning blocks are not supported",
42
- });
43
- continue;
44
- }
45
- const raw = open[2]?.trim() ?? "";
46
- let id = "";
47
- if (raw) {
48
- if (!/^\{[^}\n]*\}$/.test(raw))
49
- errors.push({
50
- line: i + 1,
51
- column: 1,
52
- message: "block attributes need {#id} syntax",
53
- });
54
- else {
55
- const attrs = parseExtensionAttributes(raw.slice(1, -1));
56
- id = attrs.id;
57
- for (const message of attrs.problems)
58
- errors.push({ line: i + 1, column: 1, message });
59
- if (attrs.classes.length || Object.keys(attrs.values).length)
60
- errors.push({
61
- line: i + 1,
62
- column: 1,
63
- message: "info and warn accept only an id",
64
- });
65
- }
66
- }
67
- opening = { start: i, kind: open[1], id };
68
- continue;
69
- }
70
- if (CLOSE.test(line) && opening) {
71
- const body = lines
72
- .slice(opening.start + 1, i)
73
- .join("\n")
74
- .trim();
75
- if (!body)
76
- errors.push({
77
- line: opening.start + 1,
78
- column: 1,
79
- message: `${opening.kind} block is empty`,
80
- });
81
- blocks.push({ ...opening, end: i, body });
82
- opening = null;
83
- }
84
- }
85
- if (opening)
86
- errors.push({
87
- line: opening.start + 1,
88
- column: 1,
89
- message: `${opening.kind} block needs a closing ::: line`,
90
- });
91
- return { blocks, errors };
92
- }
93
-
94
- /** Render info and warning blocks as styled, labelled HTML. */
95
- export function renderAdmonitions(source, renderMarkdown = parser.render.bind(parser)) {
96
- const { blocks, errors } = scanAdmonitions(source);
97
- if (errors.length) return { markdown: source, errors };
98
- const lines = String(source ?? "").split("\n");
99
- const output = [];
100
- let cursor = 0;
101
- for (const block of blocks) {
102
- const style = STYLES[block.kind];
103
- output.push(...lines.slice(cursor, block.start));
104
- output.push(
105
- `<aside${block.id ? ` id="${block.id}"` : ""} class="sohl-admonition sohl-admonition-${block.kind}" style="border-left: 3px solid ${style.color}; background: ${style.background}; padding: 0.5em 0.8em; margin: 0.75em 0;">`,
106
- `<p><strong><span aria-hidden="true">${style.icon}</span> ${style.label}</strong></p>`,
107
- renderMarkdown(block.body).trim(),
108
- "</aside>",
109
- );
110
- cursor = block.end + 1;
111
- }
112
- output.push(...lines.slice(cursor));
113
- return { markdown: output.join("\n"), errors: [] };
114
- }
@@ -1,112 +0,0 @@
1
- /*
2
- * SPDX-License-Identifier: GPL-3.0-or-later
3
- */
4
-
5
- import crypto from "node:crypto";
6
- import markdownit from "markdown-it";
7
- import footnotePlugin from "markdown-it-footnote";
8
- import deflistPlugin from "markdown-it-deflist";
9
-
10
- const webMarkdown = markdownit({ html: true }).use(footnotePlugin).use(deflistPlugin);
11
-
12
- /**
13
- * Render whole-line `:::secret` blocks for one publishing surface.
14
- * The source line of each syntax error is relative to the supplied body.
15
- *
16
- * @param {string} source - Markdown containing secret blocks.
17
- * @param {"foundry"|"web"|"book"} target - Publishing surface.
18
- * @param {(markdown: string) => string} [renderMarkdown] - Foundry's configured renderer.
19
- * @returns {{markdown: string, errors: Array<{line: number, column: number, message: string}>}}
20
- */
21
- export function renderSecretBlocks(
22
- source,
23
- target,
24
- renderMarkdown = webMarkdown.render.bind(webMarkdown),
25
- ) {
26
- const lines = String(source ?? "").split("\n");
27
- const result = [];
28
- const errors = [];
29
- let opening = -1;
30
- let body = [];
31
- let codeFence = null;
32
-
33
- for (let index = 0; index < lines.length; index++) {
34
- const line = lines[index];
35
- const fence = line.match(/^ {0,3}(`{3,}|~{3,})/);
36
- if (codeFence) {
37
- if (fence && fence[1][0] === codeFence[0] && fence[1].length >= codeFence.length) {
38
- codeFence = null;
39
- }
40
- if (opening >= 0) body.push(line);
41
- else result.push(line);
42
- continue;
43
- }
44
- if (fence) {
45
- codeFence = fence[1];
46
- if (opening >= 0) body.push(line);
47
- else result.push(line);
48
- continue;
49
- }
50
- if (/^:::secret[ \t]*$/.test(line)) {
51
- if (opening >= 0) {
52
- errors.push({
53
- line: index + 1,
54
- column: 1,
55
- message: "nested secret blocks are not supported",
56
- });
57
- body.push(line);
58
- } else {
59
- opening = index;
60
- body = [];
61
- }
62
- continue;
63
- }
64
- if (/^:::[ \t]*$/.test(line)) {
65
- if (opening < 0) {
66
- errors.push({
67
- line: index + 1,
68
- column: 1,
69
- message: "secret block has no opening :::secret line",
70
- });
71
- result.push(line);
72
- continue;
73
- }
74
- const inner = body.join("\n").trim();
75
- if (target === "book") {
76
- result.push("", "**GM note**", "", inner, "");
77
- } else {
78
- const html = renderMarkdown(inner).trim();
79
- if (target === "foundry") {
80
- const id = crypto
81
- .createHash("sha256")
82
- .update(`${opening}:${inner}`)
83
- .digest("hex")
84
- .slice(0, 12);
85
- result.push(
86
- "",
87
- `<section class="secret" id="secret-${id}">`,
88
- html,
89
- "</section>",
90
- "",
91
- );
92
- } else {
93
- result.push("", "<details><summary>Spoiler</summary>", html, "</details>", "");
94
- }
95
- }
96
- opening = -1;
97
- body = [];
98
- continue;
99
- }
100
- if (opening >= 0) body.push(line);
101
- else result.push(line);
102
- }
103
- if (opening >= 0) {
104
- errors.push({
105
- line: opening + 1,
106
- column: 1,
107
- message: "secret block needs a closing ::: line",
108
- });
109
- result.push(":::secret", ...body);
110
- }
111
- return { markdown: result.join("\n"), errors };
112
- }
@@ -1,24 +0,0 @@
1
- /** Find inline info and warning blocks without interpreting code examples. */
2
- export function scanAdmonitions(source: any): {
3
- blocks: {
4
- end: number;
5
- body: string;
6
- start: number;
7
- kind: string;
8
- id: string;
9
- }[];
10
- errors: {
11
- line: number;
12
- column: number;
13
- message: string;
14
- }[];
15
- };
16
- /** Render info and warning blocks as styled, labelled HTML. */
17
- export function renderAdmonitions(source: any, renderMarkdown?: (src: string, env?: import("markdown-it").Env) => string): {
18
- markdown: any;
19
- errors: {
20
- line: number;
21
- column: number;
22
- message: string;
23
- }[];
24
- };
@@ -1,17 +0,0 @@
1
- /**
2
- * Render whole-line `:::secret` blocks for one publishing surface.
3
- * The source line of each syntax error is relative to the supplied body.
4
- *
5
- * @param {string} source - Markdown containing secret blocks.
6
- * @param {"foundry"|"web"|"book"} target - Publishing surface.
7
- * @param {(markdown: string) => string} [renderMarkdown] - Foundry's configured renderer.
8
- * @returns {{markdown: string, errors: Array<{line: number, column: number, message: string}>}}
9
- */
10
- export function renderSecretBlocks(source: string, target: "foundry" | "web" | "book", renderMarkdown?: (markdown: string) => string): {
11
- markdown: string;
12
- errors: Array<{
13
- line: number;
14
- column: number;
15
- message: string;
16
- }>;
17
- };