@heroiclands/package-build 23.11.0 → 23.12.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.
Files changed (62) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +1 -0
  3. package/assets/preview/check-sanitizer.go +68 -0
  4. package/assets/preview/gitea-theme.js +36 -0
  5. package/assets/preview/gitea.ini +127 -0
  6. package/assets/styles/content-base.css +119 -16
  7. package/bin/content-commands.mjs +2 -2
  8. package/bin/package-build-preview.mjs +75 -0
  9. package/content-config.mjs +11 -0
  10. package/docs/api.md +105 -46
  11. package/docs/authoring/links-and-markup.md +52 -14
  12. package/docs/commands.md +46 -2
  13. package/docs/configuration.md +21 -4
  14. package/docs/design.md +4 -3
  15. package/docs/guides/book.md +10 -6
  16. package/docs/reference/format-details.md +44 -40
  17. package/docs/reference/note-types.md +0 -1
  18. package/docs/reference/theme-pages.md +1 -1
  19. package/docs/source-preview.md +172 -0
  20. package/engine/base-compiler.mjs +7 -8
  21. package/engine/being-age.mjs +19 -105
  22. package/engine/calendar-notes.mjs +3 -25
  23. package/engine/compile-corpus.mjs +2 -1
  24. package/engine/content-format.yaml +0 -1
  25. package/engine/content-index.mjs +9 -9
  26. package/engine/content-spans.mjs +28 -6
  27. package/engine/current-date.mjs +37 -0
  28. package/engine/definition-list.mjs +58 -0
  29. package/engine/first-use.mjs +4 -2
  30. package/engine/frontmatter-lint.mjs +7 -2
  31. package/engine/helpers.mjs +2 -0
  32. package/engine/index.mjs +2 -0
  33. package/engine/infobox.mjs +1 -5
  34. package/engine/note-vocabulary.mjs +2 -2
  35. package/engine/npc-generate.mjs +7 -6
  36. package/engine/pdf-render.mjs +37 -4
  37. package/engine/preview-current-date.mjs +60 -0
  38. package/engine/site-build.mjs +5 -5
  39. package/engine/site-index.mjs +5 -2
  40. package/engine/site-preview.mjs +641 -325
  41. package/hugo-theme/layouts/_default/list.html +1 -1
  42. package/hugo-theme/layouts/blog/list.html +1 -1
  43. package/hugo-theme/layouts/blog-post/single.html +1 -1
  44. package/hugo-theme/layouts/partials/dictionary-lists.html +53 -0
  45. package/hugo-theme/layouts/partials/page-body.html +1 -1
  46. package/hugo-theme/static/css/style.css +22 -8
  47. package/package.json +8 -2
  48. package/types/content-config.d.mts +8 -0
  49. package/types/engine/base-compiler.d.mts +1 -1
  50. package/types/engine/being-age.d.mts +10 -44
  51. package/types/engine/calendar-notes.d.mts +2 -6
  52. package/types/engine/compile-corpus.d.mts +2 -1
  53. package/types/engine/content-index.d.mts +3 -1
  54. package/types/engine/content-spans.d.mts +4 -2
  55. package/types/engine/current-date.d.mts +9 -0
  56. package/types/engine/definition-list.d.mts +8 -0
  57. package/types/engine/frontmatter-lint.d.mts +6 -2
  58. package/types/engine/index.d.mts +2 -0
  59. package/types/engine/npc-generate.d.mts +2 -2
  60. package/types/engine/preview-current-date.d.mts +8 -0
  61. package/types/engine/site-index.d.mts +5 -1
  62. package/types/engine/site-preview.d.mts +40 -33
@@ -19,7 +19,7 @@
19
19
  <div class="single-content">
20
20
  {{ if .Content }}
21
21
  <div class="single-body" data-pagefind-body>
22
- {{ .Content }}
22
+ {{ partial "dictionary-lists.html" .Content }}
23
23
  </div>
24
24
  {{ end }}
25
25
 
@@ -4,7 +4,7 @@
4
4
  <div class="single-content">
5
5
  {{ if .Content }}
6
6
  <div class="single-body">
7
- {{ .Content }}
7
+ {{ partial "dictionary-lists.html" .Content }}
8
8
  </div>
9
9
  {{ end }}
10
10
 
@@ -22,7 +22,7 @@
22
22
  </div>
23
23
 
24
24
  <div class="single-body" data-pagefind-body>
25
- {{ .Content }}
25
+ {{ partial "dictionary-lists.html" .Content }}
26
26
  </div>
27
27
 
28
28
  {{ partial "related.html" . }}
@@ -0,0 +1,53 @@
1
+ {{- /* Group the final Goldmark HTML. Quote-aware tokens preserve attributes,
2
+ literal examples, comments and raw blocks; a stack gives each nested list
3
+ its own rows. Existing grouped lists keep their authored divs. */ -}}
4
+ {{- $source := string . -}}
5
+ {{- if not (findRE `(?i)<dl(?:\s|>)` $source) -}}{{- return ($source | safeHTML) -}}{{- end -}}
6
+ {{- $pattern := `(?is)<!--.*?-->|<script\b(?:[^"'<>]|"[^"]*"|'[^']*')*>.*?</script\s*>|<style\b(?:[^"'<>]|"[^"]*"|'[^']*')*>.*?</style\s*>|<pre\b(?:[^"'<>]|"[^"]*"|'[^']*')*>.*?</pre\s*>|<textarea\b(?:[^"'<>]|"[^"]*"|'[^']*')*>.*?</textarea\s*>|<![^>]*>|</?[a-z][a-z0-9:-]*(?:[^"'<>]|"[^"]*"|'[^']*')*>|[^<]+|<` -}}
7
+ {{- $parts := slice -}}
8
+ {{- $lists := slice -}}
9
+ {{- $elements := slice -}}
10
+ {{- $tokens := findRE $pattern $source -}}
11
+ {{- range $i, $token := $tokens -}}
12
+ {{- if and (gt (len $lists) 0) (gt $i 0) (lt (add $i 1) (len $tokens)) (findRE `^\s+$` $token) (findRE `(?i)^</dt\s*>$` (index $tokens (sub $i 1))) (findRE `(?i)^<dd(?:\s|>)` (index $tokens (add $i 1))) -}}
13
+ {{- $token = "" -}}
14
+ {{- end -}}
15
+ {{- if and (gt (len $lists) 0) (gt $i 0) (lt (add $i 1) (len $tokens)) (findRE `^\s+$` $token) (findRE `(?i)^<dd(?:\s[^>]*)?>$` (index $tokens (sub $i 1))) (findRE `(?i)^<p(?:\s|>)` (index $tokens (add $i 1))) -}}
16
+ {{- $token = "" -}}
17
+ {{- end -}}
18
+ {{- $tag := "" -}}
19
+ {{- $opaque := findRE `(?i)^<(?:!--|script\b|style\b|pre\b|textarea\b)` $token -}}
20
+ {{- if and (not $opaque) (findRE `(?i)^</?[a-z]` $token) -}}
21
+ {{- $tag = lower (replaceRE `(?is)^</?([a-z][a-z0-9:-]*).*` "$1" $token) -}}
22
+ {{- $closing := hasPrefix $token "</" -}}
23
+ {{- if and (eq $tag "dl") (not $closing) -}}
24
+ {{- $list := newScratch -}}
25
+ {{- $list.Set "row" false -}}
26
+ {{- $lists = $lists | append $list -}}
27
+ {{- if or (findRE `(?i)\sclass\s*=\s*["'](?:[^"']*\s)?dictionary(?:\s|["'])` $token) (findRE `(?i)\sclass\s*=\s*dictionary(?:\s|>)` $token) -}}
28
+ {{- else if findRE `(?i)\sclass\s*=\s*["']` $token -}}
29
+ {{- $token = replaceRE `(?i)(\sclass\s*=\s*["'])` "${1}dictionary " $token -}}
30
+ {{- else if findRE `(?i)\sclass\s*=` $token -}}
31
+ {{- $token = replaceRE `(?i)(\sclass\s*=\s*)([^\s>]+)` `${1}"dictionary ${2}"` $token -}}
32
+ {{- else -}}
33
+ {{- $token = replaceRE `(?i)^<dl` `<dl class="dictionary"` $token -}}
34
+ {{- end -}}
35
+ {{- else if and (eq $tag "dt") (not $closing) (gt (len $lists) 0) (eq (index $elements (sub (len $elements) 1)) "dl") -}}
36
+ {{- $list := index $lists (sub (len $lists) 1) -}}
37
+ {{- if $list.Get "row" -}}{{- $parts = $parts | append "</div>" -}}{{- end -}}
38
+ {{- $parts = $parts | append "<div>" -}}
39
+ {{- $list.Set "row" true -}}
40
+ {{- else if and (eq $tag "dl") $closing (gt (len $lists) 0) -}}
41
+ {{- $list := index $lists (sub (len $lists) 1) -}}
42
+ {{- if $list.Get "row" -}}{{- $parts = $parts | append "</div>" -}}{{- end -}}
43
+ {{- $lists = first (sub (len $lists) 1) $lists -}}
44
+ {{- end -}}
45
+ {{- if $closing -}}
46
+ {{- if gt (len $elements) 0 -}}{{- $elements = first (sub (len $elements) 1) $elements -}}{{- end -}}
47
+ {{- else if not (or (findRE `/\s*>$` $token) (in (slice "area" "base" "br" "col" "embed" "hr" "img" "input" "link" "meta" "param" "source" "track" "wbr") $tag)) -}}
48
+ {{- $elements = $elements | append $tag -}}
49
+ {{- end -}}
50
+ {{- end -}}
51
+ {{- $parts = $parts | append $token -}}
52
+ {{- end -}}
53
+ {{- return (delimit $parts "" | safeHTML) -}}
@@ -67,7 +67,7 @@
67
67
  {{ end }}
68
68
 
69
69
  <div class="single-body" data-pagefind-body>
70
- {{ .Content }}
70
+ {{ partial "dictionary-lists.html" .Content }}
71
71
  </div>
72
72
 
73
73
  {{ partial "related.html" . }}
@@ -2955,20 +2955,21 @@ summary.info-sidebar-title::after {
2955
2955
  }
2956
2956
  }
2957
2957
 
2958
- /* GitHub-style author alerts remain open and inherit the prose foreground. */
2958
+ /* Author alerts use the dark palette of this site's single-mode theme. */
2959
2959
  .single-content .alert {
2960
2960
  border-inline-start: 0.25rem solid var(--pb-alert-color);
2961
- padding: 0.5rem 1rem;
2961
+ border-radius: 0.375rem;
2962
+ padding: 1rem;
2962
2963
  margin: 1rem 0;
2963
- color: inherit;
2964
- background: transparent;
2964
+ color: #e6edf3;
2965
+ background: var(--pb-alert-background);
2965
2966
  }
2966
2967
  .single-content .alert-title {
2967
2968
  display: flex;
2968
2969
  align-items: center;
2969
2970
  gap: 0.5em;
2970
2971
  margin: 0 0 0.5rem;
2971
- font-weight: 600;
2972
+ font-weight: 700;
2972
2973
  color: var(--pb-alert-color);
2973
2974
  }
2974
2975
  .single-content .alert-icon {
@@ -2981,16 +2982,20 @@ summary.info-sidebar-title::after {
2981
2982
  margin-bottom: 0;
2982
2983
  }
2983
2984
  .single-content .alert-note {
2984
- --pb-alert-color: #4493f8;
2985
+ --pb-alert-color: #58a6ff;
2986
+ --pb-alert-background: #101a28;
2985
2987
  }
2986
2988
  .single-content .alert-tip {
2987
- --pb-alert-color: #3fb950;
2989
+ --pb-alert-color: #7ee787;
2990
+ --pb-alert-background: #102018;
2988
2991
  }
2989
2992
  .single-content .alert-important {
2990
- --pb-alert-color: #ab7df8;
2993
+ --pb-alert-color: #c4b0ff;
2994
+ --pb-alert-background: #1c172a;
2991
2995
  }
2992
2996
  .single-content .alert-warning {
2993
2997
  --pb-alert-color: #d29922;
2998
+ --pb-alert-background: #241d10;
2994
2999
  }
2995
3000
 
2996
3001
  /* Inline spoiler controls remain inline, with links outside the button. */
@@ -3008,3 +3013,12 @@ summary.info-sidebar-title::after {
3008
3013
  }
3009
3014
  .inline-secret-toggle:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
3010
3015
  .inline-secret-content { margin-inline-start: 0.25em; }
3016
+
3017
+ /* Authored definition lists use dictionary rows; profile grids remain separate. */
3018
+ .single-body .dictionary { --indent:150px; --gap:.75em; margin:0; display:block; }
3019
+ .single-body .dictionary > div { padding-left:var(--indent); text-indent:calc(-1 * var(--indent)); margin-bottom:.5em; }
3020
+ .single-body .dictionary > div > dt { display:inline-block; min-width:calc(var(--indent) - var(--gap)); margin-right:var(--gap); font-weight:bold; white-space:nowrap; text-indent:0; text-align:left; }
3021
+ .single-body .dictionary > div > dd { display:inline; margin:0; font-weight:normal; }
3022
+ .single-body .dictionary > div > dd > :is(p, ul, ol, dl, blockquote, pre, table, div) { text-indent:0; }
3023
+ .single-body .dictionary > div > dd > p:first-child { display:inline; }
3024
+ @media (max-width:600px) { .single-body .dictionary { --indent:100px; } }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heroiclands/package-build",
3
- "version": "23.11.0",
3
+ "version": "23.12.1",
4
4
  "description": "Shared toolchain for building and shipping a HeroicLands Foundry VTT package — content compilation, manifest, localization, staging, bundle, release and deployment.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "type": "module",
@@ -35,6 +35,11 @@
35
35
  "types": "./types/hm3/*.d.mts",
36
36
  "import": "./hm3/*.mjs"
37
37
  },
38
+ "./preview": {
39
+ "types": "./types/engine/site-preview.d.mts",
40
+ "import": "./engine/site-preview.mjs",
41
+ "default": "./engine/site-preview.mjs"
42
+ },
38
43
  "./content-config": {
39
44
  "types": "./types/content-config.d.mts",
40
45
  "import": "./content-config.mjs"
@@ -95,7 +100,8 @@
95
100
  "./package.json": "./package.json"
96
101
  },
97
102
  "bin": {
98
- "package-build": "./bin/package-build.mjs"
103
+ "package-build": "./bin/package-build.mjs",
104
+ "package-build-preview": "./bin/package-build-preview.mjs"
99
105
  },
100
106
  "files": [
101
107
  "CHANGELOG-content-build.md",
@@ -628,6 +628,10 @@ export type ContentBuildConfigInput = {
628
628
  * depends on the working directory.
629
629
  */
630
630
  rootDir: string;
631
+ /**
632
+ * Setting-wide neutral current date; defaults to "720.1".
633
+ */
634
+ currentDate?: string | undefined;
631
635
  /**
632
636
  * Content package name — the address
633
637
  * namespace every note in this
@@ -748,6 +752,10 @@ export type ContentBuildConfigInput = {
748
752
  * The normalized, frozen configuration the toolchain reads.
749
753
  */
750
754
  export type ContentBuildConfig = {
755
+ /**
756
+ * Setting-wide neutral current date.
757
+ */
758
+ currentDate: string;
751
759
  rootDir: string;
752
760
  contentPackage: string;
753
761
  /**
@@ -358,7 +358,7 @@ export class BasePackCompiler {
358
358
  reportsCorpusProblems: boolean | undefined;
359
359
  linkIndex: any;
360
360
  sqlTables: any;
361
- worldPresent: unknown;
361
+ currentDate: string | undefined;
362
362
  /**
363
363
  * Report every finding {@link BasePackCompiler#convertBody} collected
364
364
  * across its passes, and decline the note if there were any.
@@ -15,11 +15,9 @@ export function parseAgeMagnitude(raw: unknown): {
15
15
  *
16
16
  * @param {unknown} bornRaw - The being's authored `born`, or `undefined`/`null`
17
17
  * where it wrote none.
18
- * @param {unknown} presentRaw - The package's `data.present`, as
19
- * {@link module:engine/calendar-notes.worldInvariants} read it, or
20
- * `undefined`/`null` where the package states none.
18
+ * @param {unknown} presentRaw - The configured neutral current date.
21
19
  * @returns {number|null} The age, or `null` where `born` is `unknown` or
22
- * absent, where no present is declared, or where either date fails to parse.
20
+ * absent or future, or where either date fails to parse.
23
21
  */
24
22
  export function computeAge(bornRaw: unknown, presentRaw: unknown, dateContext?: {}): number | null;
25
23
  /**
@@ -35,58 +33,26 @@ export function computeAge(bornRaw: unknown, presentRaw: unknown, dateContext?:
35
33
  * itself untouched.
36
34
  *
37
35
  * @param {object} fm - A note's frontmatter, as freshly parsed.
38
- * @param {unknown} presentRaw - The package's declared present, or
39
- * `undefined`/`null` where it states none.
36
+ * @param {unknown} presentRaw - The configured neutral current date.
40
37
  * @returns {void}
41
38
  */
42
39
  export function applyComputedBeingAge(fm: object, presentRaw: unknown, dateContext?: {}): void;
43
40
  /**
44
- * A being's `data.present`, read from every `place` note a batch of records or
45
- * frontmatter objects carries.
46
- *
47
- * Two shapes reach this by way of two thin adapters, because the callers that
48
- * need a present hold their notes two different ways: a flat index record
49
- * (`type` and `data` at the top level) and a raw walk's `{frontmatter}` pair.
50
- * Neither shape is the `{fm, type}` pair {@link worldInvariants} reads, so each
51
- * adapter states the one conversion its caller needs rather than asking every
52
- * caller to know it.
53
- *
54
- * @param {readonly object[]|undefined} records - Flat index records — a
55
- * content-index record, or anything else spreading a note's frontmatter to
56
- * its own top level.
57
- * @returns {unknown} The present, or `null` where no `place` note in the batch
58
- * declares one.
59
- */
60
- export function presentAmongRecords(records: readonly object[] | undefined): unknown;
61
- /**
62
- * The present read from a batch of raw frontmatter objects.
63
- *
64
- * @param {readonly (object|null|undefined)[]|undefined} frontmatters - One
65
- * entry per note walked, as parsed — never a record.
66
- * @returns {unknown} The present, or `null` where none is declared.
67
- */
68
- export function presentAmongFrontmatters(frontmatters: readonly (object | null | undefined)[] | undefined): unknown;
69
- /**
70
- * Check a being's authored `age` against what `born` and the package's present
71
- * compute.
41
+ * Check an authored age against the birth date and configured current date.
72
42
  *
73
43
  * Registered as `being`'s whole-note `check` in `note-vocabulary.mjs`, run the
74
44
  * way `checkPlace` and `checkCalendarNote` are — beside every other check the
75
45
  * closed `data:` container earns, with the same `index`.
76
46
  *
77
- * Two silences, both deliberate: beside `born: unknown` or an absent `born`
78
- * there is nothing to disagree with, and a package that declares no present
79
- * computes no age to disagree with either — both cases are read by
80
- * {@link computeAge} returning `null`, and neither says a word.
47
+ * An unknown or absent birth date supplies no computed age to compare.
81
48
  *
82
- * @param {object} note - The note, as the link index hands it over —
83
- * {@link module:engine/calendar-notes.worldInvariants}'s `index.notes` shape.
49
+ * @param {object} note - The note, as the link index hands it over.
84
50
  * @param {object} [opts]
85
- * @param {object} [opts.index] - The link index, holding the package's `place`
86
- * notes. Its absence skips the check, the way a reference check with no
87
- * index skips reporting every reference as dead.
51
+ * @param {object} [opts.index] - Calendar context for authored birth dates.
52
+ * @param {string} [opts.currentDate="720.1"] - The configured neutral current date.
88
53
  * @returns {object[]} Findings — at most one `warning`, naming both values.
89
54
  */
90
- export function checkBeingAge(note: object, { index }?: {
55
+ export function checkBeingAge(note: object, { index, currentDate }?: {
91
56
  index?: object | undefined;
57
+ currentDate?: string | undefined;
92
58
  }): object[];
@@ -5,13 +5,12 @@
5
5
  * note has no year, and every question that depends on one goes unasked.
6
6
  *
7
7
  * @param {object} [index] - The link index, holding every note in the package.
8
- * @returns {{year: object|null, present: unknown, moon: object|null,
8
+ * @returns {{year: object|null, moon: object|null,
9
9
  * body: object|null, moonName: string|null, yearNote: object|null,
10
10
  * moonNote: object|null}} What the package's notes state.
11
11
  */
12
12
  export function worldInvariants(index?: object): {
13
13
  year: object | null;
14
- present: unknown;
15
14
  moon: object | null;
16
15
  body: object | null;
17
16
  moonName: string | null;
@@ -41,9 +40,6 @@ export function checkCalendarDateFormats(note: any): {
41
40
  * - a moon with no year is refused, because a cycle measured in days has
42
41
  * nothing to be measured against.
43
42
  *
44
- * `data.present` is read through the parser a note's dates go through, with the
45
- * corpus in hand, so a present written in an era resolves where it is written.
46
- *
47
43
  * @param {object} note - The note, as the link index hands it over.
48
44
  * @param {object} [opts]
49
45
  * @param {object} [opts.index] - The link index, holding every note.
@@ -185,7 +181,7 @@ export const CALENDAR_FIELDS: readonly object[];
185
181
  * The `data:` keys a world or a celestial body may write.
186
182
  *
187
183
  * Four groups, and which note carries which is a fact about the body rather
188
- * than a convention: a planet states its own size, tilt, year and present; a
184
+ * than a convention: a planet states its own size, tilt and year; a
189
185
  * moon states its own size, orbit and cycle.
190
186
  *
191
187
  * @type {readonly object[]}
@@ -16,7 +16,7 @@
16
16
  * the index refuses is a note the compile must still *report*, exactly as the
17
17
  * compile loop reported it when the loop was the first to see it.
18
18
  * @param {import("./content-session.mjs").ContentSession} [opts.session] - Captured context shared with other operations.
19
- * @returns {Promise<{records: object[], parsed: Map<string, object>, linkIndex: object, sqlTables: Map<string, object[]>|undefined, problems: object[], syntax?: import("./content-session.mjs").ContentSyntax}>} The corpus,
19
+ * @returns {Promise<{currentDate: string, records: object[], parsed: Map<string, object>, linkIndex: object, sqlTables: Map<string, object[]>|undefined, problems: object[], syntax?: import("./content-session.mjs").ContentSyntax}>} The corpus,
20
20
  * its indexes, and the notes it could not record.
21
21
  */
22
22
  export function buildCompileCorpus({ contentBase, assetsBase, skipDirectories, router, config, problems, session, }: {
@@ -28,6 +28,7 @@ export function buildCompileCorpus({ contentBase, assetsBase, skipDirectories, r
28
28
  problems?: object[] | undefined;
29
29
  session?: import("./content-session.mjs").ContentSession | undefined;
30
30
  }): Promise<{
31
+ currentDate: string;
31
32
  records: object[];
32
33
  parsed: Map<string, object>;
33
34
  linkIndex: object;
@@ -234,6 +234,7 @@ export function resolveCultures(records: Array<Record<string, any>>, { contentPa
234
234
  * asserts that it does not exist. The same holds for a culture conflict: a
235
235
  * reader receives each as a finding, and the emitter throws once, listing
236
236
  * every one.
237
+ * @param {string} [options.currentDate="720.1"] - Setting-wide neutral current date.
237
238
  * @param {(key: string) => ({culture?: unknown}|undefined)} [options.foreignRecord] -
238
239
  * Another package's entry for a canonical address, read for a parent that
239
240
  * package publishes; see {@link resolveCultures}.
@@ -246,13 +247,14 @@ export function resolveCultures(records: Array<Record<string, any>>, { contentPa
246
247
  * @returns {Array<Record<string, any>>} The records, in a total order that does
247
248
  * not depend on directory-read order.
248
249
  */
249
- export function collectContentIndex(contentBase: string, { contentPackage, skipDirectories, assetsBase, manifest, problems, addressContext, foreignRecord, parsed, sources, syntax, nameTypes, }: {
250
+ export function collectContentIndex(contentBase: string, { contentPackage, currentDate, skipDirectories, assetsBase, manifest, problems, addressContext, foreignRecord, parsed, sources, syntax, nameTypes, }: {
250
251
  contentPackage: string;
251
252
  skipDirectories: readonly string[];
252
253
  assetsBase?: string | undefined;
253
254
  manifest?: object | undefined;
254
255
  addressContext?: object | undefined;
255
256
  problems?: object[] | undefined;
257
+ currentDate?: string | undefined;
256
258
  foreignRecord?: ((key: string) => ({
257
259
  culture?: unknown;
258
260
  } | undefined)) | undefined;
@@ -1,9 +1,11 @@
1
1
  /** Add bracket spans after recognized Markdown links and footnotes.
2
2
  * @param {import("markdown-it")} md - Markdown parser to extend.
3
3
  * @param {object} [options] - Surface presentation.
4
- * @param {boolean} [options.spoilers] - Add visible static Secret labels (Foundry).
4
+ * @param {boolean} [options.source] - Emit opaque authored source tokens for buffer preview.
5
+ * @param {boolean} [options.spoilers] - Add focusable CSS spoiler wrappers (Foundry).
5
6
  */
6
- export function spanMarkdownPlugin(md: typeof import("markdown-it"), { spoilers }?: {
7
+ export function spanMarkdownPlugin(md: typeof import("markdown-it"), { spoilers, source }?: {
8
+ source?: boolean | undefined;
7
9
  spoilers?: boolean | undefined;
8
10
  }): void;
9
11
  /** Read span anchors and located attribute diagnostics outside literal code.
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Validate a quoted neutral date and preserve its authored day digits.
3
+ * @param {unknown} [value] - Explicit configuration or adapter override.
4
+ * @returns {string} Validated neutral date; undefined selects the default.
5
+ * @throws {TypeError} An explicit value is not a valid neutral date string.
6
+ */
7
+ export function normalizeCurrentDate(value?: unknown): string;
8
+ /** Default day on the neutral setting timeline. */
9
+ export const DEFAULT_CURRENT_DATE: "720.1";
@@ -0,0 +1,8 @@
1
+ /** Semantic dictionary rows for HTML definition lists. @module */
2
+ /**
3
+ * Group each term and its definitions without reparsing their Markdown tokens.
4
+ * Register after markdown-it-deflist; nested blocks and footnotes retain their
5
+ * document context.
6
+ * @param {import("markdown-it")} md - An HTML Markdown parser with definition lists.
7
+ */
8
+ export function dictionaryListPlugin(md: typeof import("markdown-it")): void;
@@ -32,6 +32,7 @@ export function systemAddressFindings(note: object, { index, schemas, systems }?
32
32
  * @param {object} note - A note from the link index (`{fm, file, raw, type}`).
33
33
  * @param {object} opts
34
34
  * @param {Record<string, readonly object[]>} opts.schemas - Type → declaration.
35
+ * @param {string} [opts.currentDate="720.1"] - Setting-wide neutral date for age checks.
35
36
  * @param {object} [opts.index] - The link index, for the reference check, which
36
37
  * runs through its `shortcodeHit`. Its absence skips that check rather than
37
38
  * reporting every reference as dead.
@@ -59,8 +60,9 @@ export function systemAddressFindings(note: object, { index, schemas, systems }?
59
60
  * about those keys.
60
61
  * @returns {object[]} Findings, each with a locator where one is obtainable.
61
62
  */
62
- export function lintNote(note: object, { schemas, index, vocabulary, packs, emittedArt, addressContext, systems, }: {
63
+ export function lintNote(note: object, { schemas, index, currentDate, vocabulary, packs, emittedArt, addressContext, systems, }: {
63
64
  schemas: Record<string, readonly object[]>;
65
+ currentDate?: string | undefined;
64
66
  index?: object | undefined;
65
67
  vocabulary?: Record<string, object> | undefined;
66
68
  emittedArt?: ((type: string) => {
@@ -77,6 +79,7 @@ export function lintNote(note: object, { schemas, index, vocabulary, packs, emit
77
79
  * @param {object} index - From `buildLinkIndex`.
78
80
  * @param {object} opts
79
81
  * @param {Record<string, readonly object[]>} opts.schemas - Type → declaration.
82
+ * @param {string} [opts.currentDate="720.1"] - Setting-wide neutral date for age checks.
80
83
  * @param {Record<string, object>} [opts.vocabulary] - Type → the closed regions
81
84
  * it declares; see {@link lintNote}.
82
85
  * @param {boolean} [opts.references=true] - Whether to check references.
@@ -90,8 +93,9 @@ export function lintNote(note: object, { schemas, index, vocabulary, packs, emit
90
93
  * @returns {{findings: object[], notes: number}} The findings, and how many
91
94
  * notes were inspected.
92
95
  */
93
- export function lintFrontmatter(index: object, { schemas, vocabulary, packs, emittedArt, references, systems }: {
96
+ export function lintFrontmatter(index: object, { schemas, vocabulary, packs, emittedArt, references, systems, currentDate }: {
94
97
  schemas: Record<string, readonly object[]>;
98
+ currentDate?: string | undefined;
95
99
  vocabulary?: Record<string, object> | undefined;
96
100
  references?: boolean | undefined;
97
101
  systems?: Readonly<Record<string, SystemBlockSpec>> | undefined;
@@ -39,6 +39,8 @@ export * as cultureChoice from "./culture-choice.mjs";
39
39
  export * as reckoningMarkers from "./reckoning-markers.mjs";
40
40
  export * as calendarNotes from "./calendar-notes.mjs";
41
41
  export * as calendarArtifacts from "./calendar-artifacts.mjs";
42
+ export * as definitionList from "./definition-list.mjs";
43
+ export * as currentDate from "./current-date.mjs";
42
44
  export * as beingAge from "./being-age.mjs";
43
45
  export * as contentSlug from "./content-slug.mjs";
44
46
  export * as contentAddress from "./content-address.mjs";
@@ -59,7 +59,7 @@ export function appearanceParagraph({ name, age, gender, height, frame, appearan
59
59
  * about a name that does not fit.
60
60
  * @param {string} [context.seed] - Text joined to the spec's own seed, to draw a
61
61
  * different person from the same spec.
62
- * @param {unknown} [context.present] - The package's present, or `null`.
62
+ * @param {unknown} [context.currentDate] - The setting's neutral current date, defaulting to "720.1".
63
63
  * @param {object} [context.dateContext] - The reckoning context the present
64
64
  * and `born` are read in, with `daysPerYear`.
65
65
  * @param {{icon?: unknown, species?: unknown, packFolder?: unknown}} [context.defaults] -
@@ -75,7 +75,7 @@ export function generateNpc(spec: object, context: {
75
75
  names: object;
76
76
  language?: string | undefined;
77
77
  seed?: string | undefined;
78
- present?: unknown;
78
+ currentDate?: unknown;
79
79
  dateContext?: object | undefined;
80
80
  defaults?: {
81
81
  icon?: unknown;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Read only currentDate from the nearest package configuration.
3
+ * YAML does not load the full build configuration. An MJS configuration executes
4
+ * its own module, as any caller opting into a code configuration expects.
5
+ * @param {string} root - Directory at which configuration discovery starts.
6
+ * @returns {Promise<string>} Validated neutral current date.
7
+ */
8
+ export function readPreviewCurrentDate(root: string): Promise<string>;
@@ -4,6 +4,8 @@
4
4
  * @param {readonly SiteEntry[]} entries - Every page the site will publish,
5
5
  * each already knowing its own `url`.
6
6
  * @param {object} [options] - Cross-package inputs.
7
+ * @param {string} [options.package] - The builder's own content package.
8
+ * @param {string} [options.currentDate="720.1"] - Setting-wide neutral date for recurring events.
7
9
  * @param {Map<string, {package: string, type?: string}>} [options.foreignIndex]
8
10
  * The merged index from `loadForeignIndexes`. Omit when the build publishes
9
11
  * no cross-package links.
@@ -16,7 +18,9 @@
16
18
  * @param {import("./content-session.mjs").ContentSyntax} [options.syntax] - Exact-text scanner projections.
17
19
  * @returns {SiteIndex} The index, and what could not be addressed unambiguously.
18
20
  */
19
- export function buildSiteIndex(entries: readonly SiteEntry[], { foreignIndex, noIndexPackages, package: builderPackage, records, foreignReferences, syntax, }?: {
21
+ export function buildSiteIndex(entries: readonly SiteEntry[], { foreignIndex, noIndexPackages, package: builderPackage, currentDate, records, foreignReferences, syntax, }?: {
22
+ package?: string | undefined;
23
+ currentDate?: string | undefined;
20
24
  foreignIndex?: Map<string, {
21
25
  package: string;
22
26
  type?: string;
@@ -1,34 +1,41 @@
1
- /** Prepare saved project state once, then render live text without writing a site. */
2
- export function prepareSitePreview({ config }?: {
3
- config?: import("../content-config.mjs").ContentBuildConfig | undefined;
4
- }): Promise<{
5
- /** Render the active buffer. Other local and foreign notes remain saved. */
6
- render(file: any, text: any): Promise<{
7
- ok: boolean;
8
- findings: {
9
- file: string;
10
- severity: string;
11
- message: string;
12
- }[];
13
- markdown?: undefined;
14
- frontmatter?: undefined;
15
- } | {
16
- ok: boolean;
17
- findings: {
18
- path: string;
19
- link: string;
20
- file: string;
21
- severity: string;
22
- }[];
23
- markdown?: undefined;
24
- frontmatter?: undefined;
25
- } | {
26
- ok: boolean;
27
- markdown: string;
28
- frontmatter: any;
29
- findings: never[];
30
- }>;
31
- /** Re-read saved notes and dependency indexes after a save. */
32
- refresh(): Promise<void>;
33
- close(): Promise<void>;
1
+ /**
2
+ * Render one complete buffer with no configuration, index, filesystem or database.
3
+ * @param {string} text - Markdown, optionally beginning with YAML frontmatter.
4
+ * @param {{dark?: boolean, infobox?: boolean, file?: string, currentDate?: string}} [options] - Explicit palette, profile visibility, diagnostic filename and neutral current date (default "720.1").
5
+ * @returns {{ok: boolean, html: string, frontmatter: object, findings: object[]}} HTML and metadata with locally calculable ages; unavailable ages remain absent or null.
6
+ */
7
+ export function renderPreview(text: string, { dark, infobox, file, currentDate }?: {
8
+ dark?: boolean;
9
+ infobox?: boolean;
10
+ file?: string;
11
+ currentDate?: string;
12
+ }): {
13
+ ok: boolean;
14
+ html: string;
15
+ frontmatter: object;
16
+ findings: object[];
17
+ };
18
+ /**
19
+ * Opt in to reading only the project's currentDate setting; never called by renderPreview.
20
+ * @param {string} root - Directory from which to find the nearest package configuration.
21
+ * @returns {Promise<string>} Validated neutral date, or the shared default when no setting is present.
22
+ */
23
+ export function readPreviewCurrentDate(root: string): Promise<string>;
24
+ /** Both explicit palettes, scoped to the preview container. */
25
+ export function previewStyles(): string;
26
+ /** Explicit dependency policy: a new registered helper requires a preview decision. */
27
+ export const PREVIEW_HELPERS: Readonly<{
28
+ eq: "local";
29
+ gt: "local";
30
+ gte: "local";
31
+ lt: "local";
32
+ lte: "local";
33
+ not: "local";
34
+ and: "local";
35
+ or: "local";
36
+ words: "local";
37
+ digits: "local";
38
+ sql: "dependent";
39
+ dateformat: "dependent";
40
+ ref: "reference";
34
41
  }>;