@heroiclands/package-build 25.2.0 → 25.2.1

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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # @heroiclands/package-build
2
2
 
3
+ ## 25.2.1
4
+
5
+ **Rendering and sites**
6
+
7
+ - Preview tables display linked names cleanly and keep their following columns aligned.
8
+ - Foundry journal page names show the readable text of headings containing names, links or emphasis.
9
+
3
10
  ## 25.2.0
4
11
 
5
12
  **Content and notes**
@@ -25,7 +25,7 @@ Start with [your first note](authoring/first-note.md). It explains the smallest
25
25
 
26
26
  ## The shared note
27
27
 
28
- A nonempty note body creates one system-agnostic Foundry JournalEntry. Content before the first H1 becomes an introduction page; every H1 starts another JournalEntryPage. A lower-level heading with an explicit `{#anchor}` starts a page too, so a link can address it. The same prose becomes a web page and can be selected for a book. The content index records the note and its frontmatter for queries and navigation.
28
+ A nonempty note body creates one system-agnostic Foundry JournalEntry. Content before the first H1 becomes an introduction page; every H1 starts another JournalEntryPage. A lower-level heading with an explicit `{#anchor}` starts a page too, so a link can address it. Each page name is its heading's visible text: spans, links and emphasis contribute their text without their markup. The same prose becomes a web page and can be selected for a book. The content index records the note and its frontmatter for queries and navigation.
29
29
 
30
30
  Leading `:` captions describe the next supported block; `:@` captions also number it. The optional type accepts `figure`, `table`, `verse`, `code`, `prose`, and `example`. Captions support identifiers, classes and named attributes; unsupported following blocks are errors. See [captions and numbered references](authoring/links-and-markup.md#captions-and-numbered-references).
31
31
 
@@ -37,7 +37,8 @@ source. A host that holds the package's content index builds an index with
37
37
  wikilink is a link, a link to a concealed note is concealed, an embed draws its
38
38
  picture, marked text is mapped and set in its face, an icon is drawn, and a
39
39
  caption is numbered with its asset's role, so a map is a **Map**. A query, which
40
- a buffer cannot run, stays highlighted source in both views.
40
+ a buffer cannot run, stays highlighted source in both views. Table cells keep
41
+ wikilinks and their labels together, including links inside marked spans.
41
42
 
42
43
  With an index, a marked-text run that cannot be set produces an error finding
43
44
  and sets the result's `ok` to `false`. The preview still returns recoverable
@@ -116,9 +116,9 @@ function namedBlockLines(markdown, syntax) {
116
116
  * code blocks are respected so `# foo` inside ``` or ~~~ blocks doesn't
117
117
  * trigger a split. Content before the first H1 (if non-empty) becomes a
118
118
  * leading page. Each H1 yields a page whose name is the heading
119
- * text (with any `{#anchor-id}` suffix stripped out and surfaced as
120
- * `anchorSlug`). The classes the heading declares come along as `classes`, so
121
- * a surface that honours one has it without reading the suffix again.
119
+ * text without inline markup (with any `{#anchor-id}` suffix stripped out and
120
+ * surfaced as `anchorSlug`). The classes the heading declares come along as
121
+ * `classes`, so a surface that honours one has it without reading the suffix again.
122
122
  *
123
123
  * `leadName` names that leading page. A journal note's is "Introduction",
124
124
  * because it introduces the pages that follow. An item doc's is the item — a
@@ -220,7 +220,7 @@ export function splitPages(body, leadName = "Introduction", resolveRole, syntax)
220
220
  anchorSlug: null,
221
221
  level: section.level,
222
222
  classes: section.classes,
223
- continues: item.slug || item.label || captionPageName(item.caption),
223
+ continues: item.slug || item.label || pageNameText(item.caption),
224
224
  lines: [],
225
225
  };
226
226
  }
@@ -231,7 +231,7 @@ export function splitPages(body, leadName = "Introduction", resolveRole, syntax)
231
231
  if (figure) {
232
232
  closeCurrent();
233
233
  current = {
234
- name: figure.label || captionPageName(figure.caption),
234
+ name: figure.label || pageNameText(figure.caption),
235
235
  anchorSlug: figure.id || null,
236
236
  level: 1,
237
237
  classes: section.classes.includes(WITHHELD_CLASS) ? [WITHHELD_CLASS] : [],
@@ -243,7 +243,7 @@ export function splitPages(body, leadName = "Introduction", resolveRole, syntax)
243
243
  if (opening) {
244
244
  closeCurrent();
245
245
  current = {
246
- name: opening.text,
246
+ name: pageNameText(opening.text),
247
247
  anchorSlug: opening.id || null,
248
248
  level: opening.level,
249
249
  classes: opening.classes,
@@ -384,20 +384,20 @@ export function journalPageId(entryId, page) {
384
384
  }
385
385
 
386
386
  /**
387
- * The name of the page a caption begins: the caption's visible text.
387
+ * The name of a page a heading or caption begins: its visible text.
388
388
  *
389
- * Foundry shows a page name as plain text, so a caption's markup — emphasis, a
389
+ * Foundry shows a page name as plain text, so inline markup — emphasis, a
390
390
  * code span, a Markdown link, or the `@UUID[...]{label}` a resolved wikilink
391
391
  * has already become, inside its wrapping `<span>` — reduces to the text a
392
392
  * reader sees, the same text a reference to the caption displays. The markup
393
393
  * itself stays in the page's content, where it renders.
394
394
  *
395
- * @param {string} caption - The figure's caption, as the journal pass sees it.
395
+ * @param {string} markdown - A heading or caption, as the journal pass sees it.
396
396
  * @returns {string} Its visible text, whitespace collapsed.
397
397
  */
398
- function captionPageName(caption) {
399
- if (!caption) return "";
400
- const [inline] = md.parseInline(caption, {});
398
+ function pageNameText(markdown) {
399
+ if (!markdown) return "";
400
+ const [inline] = md.parseInline(markdown, {});
401
401
  const text = (inline?.children ?? [])
402
402
  .map((token) =>
403
403
  token.type === "text" || token.type === "code_inline" ? token.content
@@ -501,7 +501,7 @@ function buildFigurePageFields(figure, page, pageId, footnoteNumbers, resolveRol
501
501
  // image's own render takes when no configuration resolves it.
502
502
  }
503
503
  return {
504
- name: figure.label || captionPageName(figure.caption),
504
+ name: figure.label || pageNameText(figure.caption),
505
505
  type: "image",
506
506
  src,
507
507
  image: figure.hasCaption ? { caption: figure.caption } : {},
@@ -520,7 +520,7 @@ function buildFigurePageFields(figure, page, pageId, footnoteNumbers, resolveRol
520
520
  runs,
521
521
  );
522
522
  return {
523
- name: figure.label || captionPageName(figure.caption),
523
+ name: figure.label || pageNameText(figure.caption),
524
524
  type: "text",
525
525
  text: {
526
526
  format: 1,
@@ -67,7 +67,8 @@ export const PREVIEW_HELPERS = Object.freeze({
67
67
  */
68
68
  export const INERT_BRACKET = "\uE000";
69
69
 
70
- const escapeHtml = new MarkdownIt().utils.escapeHtml;
70
+ const syntax = new MarkdownIt();
71
+ const escapeHtml = syntax.utils.escapeHtml;
71
72
  // An authored `<` stands as a private-use character until the HTML is written;
72
73
  // source is shown as it was authored.
73
74
  const escape = (value) => escapeHtml(String(value ?? "").replaceAll(INERT_BRACKET, "<"));
@@ -185,16 +186,16 @@ function withTrailingAttributes(rest, raw) {
185
186
  }
186
187
 
187
188
  /**
188
- * The cells of one table row, keeping a pipe inside a wikilink, a code span or
189
- * an extension's braces in its cell.
189
+ * The cells of one table row, keeping pipes inside balanced brackets, code
190
+ * spans and extension braces in their cell.
190
191
  *
191
192
  * @param {string} line - One table line.
192
193
  * @returns {string[]} The trimmed cells, without the empty edges.
193
194
  */
194
195
  function tableCells(line) {
195
196
  const result = [];
197
+ const state = new syntax.inline.State(line, syntax, {}, []);
196
198
  let cell = "",
197
- wiki = false,
198
199
  code = "",
199
200
  quote = false,
200
201
  braces = 0;
@@ -204,7 +205,15 @@ function tableCells(line) {
204
205
  cell += char + line[++at];
205
206
  continue;
206
207
  }
207
- if (char === "`" && !wiki) {
208
+ if (char === "[" && !code && !braces) {
209
+ const end = syntax.helpers.parseLinkLabel(state, at, false);
210
+ if (end >= 0) {
211
+ cell += line.slice(at, end + 1);
212
+ at = end;
213
+ continue;
214
+ }
215
+ }
216
+ if (char === "`") {
208
217
  const marks = /^`+/.exec(line.slice(at))[0];
209
218
  if (!code) code = marks;
210
219
  else if (code === marks) code = "";
@@ -213,13 +222,11 @@ function tableCells(line) {
213
222
  continue;
214
223
  }
215
224
  if (!code) {
216
- if (line.slice(at, at + 2) === "[[") wiki = true;
217
- if (line.slice(at - 1, at + 1) === "]]") wiki = false;
218
225
  if (char === '"' && braces) quote = !quote;
219
226
  if (!quote && char === "{") braces++;
220
227
  if (!quote && char === "}" && braces) braces--;
221
228
  }
222
- if (char === "|" && !wiki && !code && !braces) {
229
+ if (char === "|" && !code && !braces) {
223
230
  result.push(cell.trim());
224
231
  cell = "";
225
232
  } else cell += char;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heroiclands/package-build",
3
- "version": "25.2.0",
3
+ "version": "25.2.1",
4
4
  "description": "Shared toolchain for building and shipping a HeroicLands Foundry VTT package \u2014 content compilation, manifest, localization, staging, bundle, release and deployment.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "type": "module",
@@ -3,9 +3,9 @@
3
3
  * code blocks are respected so `# foo` inside ``` or ~~~ blocks doesn't
4
4
  * trigger a split. Content before the first H1 (if non-empty) becomes a
5
5
  * leading page. Each H1 yields a page whose name is the heading
6
- * text (with any `{#anchor-id}` suffix stripped out and surfaced as
7
- * `anchorSlug`). The classes the heading declares come along as `classes`, so
8
- * a surface that honours one has it without reading the suffix again.
6
+ * text without inline markup (with any `{#anchor-id}` suffix stripped out and
7
+ * surfaced as `anchorSlug`). The classes the heading declares come along as
8
+ * `classes`, so a surface that honours one has it without reading the suffix again.
9
9
  *
10
10
  * `leadName` names that leading page. A journal note's is "Introduction",
11
11
  * because it introduces the pages that follow. An item doc's is the item — a