@heroiclands/package-build 23.12.5 → 23.12.6
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 +10 -0
- package/content-config.mjs +26 -0
- package/docs/api.md +8 -5
- package/docs/authoring/dates-and-calendars.md +29 -1
- package/docs/authoring/links-and-markup.md +3 -3
- package/docs/configuration.md +27 -3
- package/docs/guides/module-project.md +1 -1
- package/docs/reference/format-details.md +62 -17
- package/docs/reference/note-types.md +9 -10
- package/engine/content-format.yaml +0 -2
- package/engine/content-index.mjs +21 -2
- package/engine/content-links.mjs +3 -0
- package/engine/event-rows.mjs +63 -18
- package/engine/event-views.mjs +28 -15
- package/engine/index-records.mjs +1 -0
- package/engine/infobox.mjs +4 -8
- package/engine/markdown-expressions.mjs +72 -17
- package/engine/note-calendars.mjs +314 -0
- package/engine/note-vocabulary.mjs +11 -16
- package/engine/reckoning-markers.mjs +63 -3
- package/engine/sql-tables.mjs +9 -3
- package/package.json +1 -1
- package/types/content-config.d.mts +12 -0
- package/types/engine/content-index.d.mts +7 -1
- package/types/engine/event-rows.d.mts +16 -1
- package/types/engine/event-views.d.mts +2 -1
- package/types/engine/note-calendars.d.mts +60 -0
- package/types/engine/reckoning-markers.d.mts +32 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @heroiclands/package-build
|
|
2
2
|
|
|
3
|
+
## 23.12.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
A package can name a default calendar with `defaultCalendar` in its configuration, and it replaces the world note's calendar as the one dates fall back to.
|
|
8
|
+
|
|
9
|
+
A note's dates print in its own `data.calendar`, which any note may now set, else its culture's, else for a place its parents', else the default. A place whose parents keep different calendars is a build error until it names its own.
|
|
10
|
+
|
|
11
|
+
Chronologies and the other event sections print every date in the calendar of the page showing them, and `dateformat` with no calendar named uses the note's.
|
|
12
|
+
|
|
3
13
|
## 23.12.5
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
package/content-config.mjs
CHANGED
|
@@ -571,6 +571,10 @@ export function publishesContentPages(config) {
|
|
|
571
571
|
* resolved against it, so the build never
|
|
572
572
|
* depends on the working directory.
|
|
573
573
|
* @property {string} [currentDate] Setting-wide neutral current date; defaults to "720.1".
|
|
574
|
+
* @property {string} [defaultCalendar] Shortcode of the `lore` note with
|
|
575
|
+
* `subType: calendar` that prints the
|
|
576
|
+
* dates of a note no other rule gives a
|
|
577
|
+
* calendar.
|
|
574
578
|
* @property {string} contentPackage Content package name — the address
|
|
575
579
|
* namespace every note in this
|
|
576
580
|
* repository is published under.
|
|
@@ -646,6 +650,8 @@ export function publishesContentPages(config) {
|
|
|
646
650
|
*
|
|
647
651
|
* @typedef {object} ContentBuildConfig
|
|
648
652
|
* @property {string} currentDate Setting-wide neutral current date.
|
|
653
|
+
* @property {string|null} defaultCalendar The calendar of last resort's
|
|
654
|
+
* shortcode, `null` when none is named.
|
|
649
655
|
* @property {string} rootDir
|
|
650
656
|
* @property {string} contentPackage
|
|
651
657
|
* @property {string|null} foundryPackage `null` for a `documentation`
|
|
@@ -730,6 +736,7 @@ const CONFIG_KEYS = [
|
|
|
730
736
|
"rootDir",
|
|
731
737
|
"contentPackage",
|
|
732
738
|
"currentDate",
|
|
739
|
+
"defaultCalendar",
|
|
733
740
|
"foundryPackage",
|
|
734
741
|
"homepage",
|
|
735
742
|
"authors",
|
|
@@ -912,6 +919,24 @@ function fail(field, problem) {
|
|
|
912
919
|
throw Object.assign(new TypeError(`package-build config: \`${field}\` ${problem}.`), { field });
|
|
913
920
|
}
|
|
914
921
|
|
|
922
|
+
/**
|
|
923
|
+
* The configured `defaultCalendar`: a calendar note's shortcode, or `null`.
|
|
924
|
+
* Whether it names a calendar note is checked against the content tree when
|
|
925
|
+
* the content index is built.
|
|
926
|
+
*
|
|
927
|
+
* @param {unknown} value - The configured value.
|
|
928
|
+
* @returns {string|null} The shortcode.
|
|
929
|
+
*/
|
|
930
|
+
function normalizeDefaultCalendar(value) {
|
|
931
|
+
if (value === undefined || value === null) return null;
|
|
932
|
+
if (typeof value !== "string" || !isAddressSegment(value))
|
|
933
|
+
fail(
|
|
934
|
+
"defaultCalendar",
|
|
935
|
+
"must be the shortcode of a calendar note — lowercase letters and digits",
|
|
936
|
+
);
|
|
937
|
+
return /** @type {string} */ (value);
|
|
938
|
+
}
|
|
939
|
+
|
|
915
940
|
/**
|
|
916
941
|
* @param {object} object
|
|
917
942
|
* @param {readonly string[]} allowed
|
|
@@ -2973,6 +2998,7 @@ export function defineConfig(config) {
|
|
|
2973
2998
|
fail("currentDate", error.message);
|
|
2974
2999
|
}
|
|
2975
3000
|
})(),
|
|
3001
|
+
defaultCalendar: normalizeDefaultCalendar(input.defaultCalendar),
|
|
2976
3002
|
contentPackage: requireContentPackage(input.contentPackage, docEntryTypes, {
|
|
2977
3003
|
rootDir,
|
|
2978
3004
|
packageKind,
|
package/docs/api.md
CHANGED
|
@@ -723,7 +723,7 @@ resolved value: the culture a place or affiliation inherits through
|
|
|
723
723
|
|
|
724
724
|
### `engine.markdownExpressions`
|
|
725
725
|
|
|
726
|
-
`renderMarkdownExpressions(body, { fm, dates, sqlResults, figures, file, bodyLine })` expands scalar frontmatter references and registered Handlebars helpers outside Markdown code. The `dateformat` helper uses `formatDateInCalendar
|
|
726
|
+
`renderMarkdownExpressions(body, { fm, dates, sqlResults, figures, file, bodyLine })` expands scalar frontmatter references and registered Handlebars helpers outside Markdown code. The `dateformat` helper uses `formatDateInCalendar`, in the calendar it names or else the note's resolved calendar, which it reads from `dates.noteCalendars` — the map a reckoning context built over content-index records carries; `gt`, `gte`, `lt`, `lte`, `eq`, `and`, `or`, and `not` evaluate explicit comparisons. The `sql` helper reads a prepared scalar result, which must contain one row and one column. The `ref` helper links to a captioned item by its anchor — `"#thorn"` on the same note — in `number` (the default, and admitted explicitly), `full` or `title` form; `figures` is a `Map` of this note's own figures, by id, to `{label, caption, hasCaption}`, and an address naming another note is reported as unresolved rather than looked up. `sqlQueriesInMarkdown` discovers SQL calls, including nested calls; `prepareInlineSqlExpressions` evaluates them through the same DuckDB connection as SQL tables. `EXPRESSION_HELPERS` is the one list of helpers: the engine registers from it and the authoring document is checked against it, so each name there carries the parameters it takes and a sentence on what it does. The renderer returns `{ markdown, findings }`, with source positions for invalid expressions. Site, Foundry and PDF passes invoke it after generated tables expand and before links resolve. Hugo shortcodes remain literal for the site renderer.
|
|
727
727
|
|
|
728
728
|
| Export | Signature | Returns | Use it when |
|
|
729
729
|
| --------------------------- | ------------------------------------------ | ---------------------- | ------------------------------------------------ |
|
|
@@ -736,10 +736,13 @@ resolved value: the culture a place or affiliation inherits through
|
|
|
736
736
|
|
|
737
737
|
The corpus registry anchors each calendar's year 1, day 1 to its canonical `data.epoch` and maps every declared era to that calendar. Exactly one `start: null` era covers earlier years and counts backwards; exactly one `start: 1` era begins the forward count. Other starts are distinct positive calendar years. Numeric order determines bounds, irrespective of array order. Duplicate starts and markers, missing required eras, and invalid epochs are findings. Short qualifiers are ambiguous when they name eras in several packages; a full Address selects one.
|
|
738
738
|
|
|
739
|
-
| Export | Signature | Returns
|
|
740
|
-
| ------------------------- | --------------------------------------------- |
|
|
741
|
-
| `resolveReckoningMarkers` | `resolveReckoningMarkers(index, daysPerYear)` | `{eras, markers, findings}`
|
|
742
|
-
| `reckoningContext` | `reckoningContext(index)` | `{eras, markers, daysPerYear, findings}` | sharing one resolved date context across checks on a corpus
|
|
739
|
+
| Export | Signature | Returns | Use it when |
|
|
740
|
+
| ------------------------- | --------------------------------------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
741
|
+
| `resolveReckoningMarkers` | `resolveReckoningMarkers(index, daysPerYear)` | `{eras, markers, findings}` | resolving authored eras, their markers, and their bounds |
|
|
742
|
+
| `reckoningContext` | `reckoningContext(index)` | `{eras, markers, daysPerYear, findings, noteCalendars}` | sharing one resolved date context across checks on a corpus |
|
|
743
|
+
| `noteCalendarMap` | `noteCalendarMap(notes)` | `Map<string, string>` | reading each record's `resolvedCalendar` by note, as `reckoningContext` carries it in `noteCalendars` |
|
|
744
|
+
| `noteCalendarKey` | `noteCalendarKey(fm)` | `string \| undefined` | finding a note's entry in `noteCalendars` by its type and shortcode |
|
|
745
|
+
| `calendarAddress` | `calendarAddress(value)` | `string \| undefined` | reading a record's `resolvedCalendar`, tuple or string, as its canonical Address |
|
|
743
746
|
|
|
744
747
|
### `engine.calendarNotes`
|
|
745
748
|
|
|
@@ -84,7 +84,35 @@ package-build dateto commoncal 326.114 --format long
|
|
|
84
84
|
|
|
85
85
|
The CLI `datefrom` command requires a day and reads the default (`std`, or first) pattern. `dateto` prints the era covering the canonical day. A clock time makes a date exact; a year or day without one spans the stated interval. `data.epoch` and `data.moon.newOn` require a day. The [detailed date rules](../reference/format-details.md#dates-and-calendars) describe precision and bounds.
|
|
86
86
|
|
|
87
|
-
In prose, `{{dateformat "commoncal" data.born}}` prints a date in the chosen calendar
|
|
87
|
+
In prose, `{{dateformat "commoncal" data.born}}` prints a date in the chosen calendar, and `{{dateformat data.born}}` prints it in the note's own calendar. A last argument chooses another named pattern: `{{dateformat "commoncal" data.born "long"}}`, or `{{dateformat data.born "long"}}`.
|
|
88
|
+
|
|
89
|
+
## Choose the calendar a note's dates print in
|
|
90
|
+
|
|
91
|
+
Every note reads its dates in one calendar. The infobox's birth and death dates, `dateformat` with no calendar named, and every date in the event sections the build adds to the note's page all print in it. It is the first of:
|
|
92
|
+
|
|
93
|
+
1. the note's own `data.calendar`, which any note may set and which always wins;
|
|
94
|
+
2. its culture's calendar — the `data.calendar` of the culture note its `data.culture` names;
|
|
95
|
+
3. for a place, its parents' calendar — the calendar each place in its `data.parents` reads in, by these same rules;
|
|
96
|
+
4. the package's `defaultCalendar`, set in the [configuration](../configuration.md#defaultcalendar);
|
|
97
|
+
5. otherwise none, and a date prints as it was written.
|
|
98
|
+
|
|
99
|
+
```yaml
|
|
100
|
+
# package-build.config.yaml
|
|
101
|
+
defaultCalendar: commoncal
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```yaml
|
|
105
|
+
# A town in a province that keeps the Vylarian count
|
|
106
|
+
type: place
|
|
107
|
+
subType: settlement
|
|
108
|
+
shortcode: brenford
|
|
109
|
+
data:
|
|
110
|
+
parents: [vylaria]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Brenford names no calendar and no culture, so it reads in Vylaria's. A place whose parents read in **different** calendars is a build error at its `data.parents`, naming the place and each calendar; give the place its own `data.calendar` to settle it. A parent, or a culture, that only reaches the default counts for nothing, so a place among parents that all fall through to `defaultCalendar` takes the default without an error.
|
|
114
|
+
|
|
115
|
+
An event section prints every date in the calendar of the page showing it, whichever note the event is written on: Brenford's chronology reads in Vylaria's count even where an event comes from a history kept in the common calendar. The [format reference](../reference/format-details.md#a-notes-calendar) gives the rules in full.
|
|
88
116
|
|
|
89
117
|
## Write a recurring date
|
|
90
118
|
|
|
@@ -1342,7 +1342,7 @@ The first call lists every page tagged `key-concept` alphabetically by title. Th
|
|
|
1342
1342
|
An expression in `{{ }}` is replaced by a value, inline in a sentence. The note's own frontmatter is the context, so a field is read by the path a note writes it at.
|
|
1343
1343
|
|
|
1344
1344
|
```markdown
|
|
1345
|
-
{{name.full}} was born on {{dateformat data.
|
|
1345
|
+
{{name.full}} was born on {{dateformat data.born}}.
|
|
1346
1346
|
There are {{words (sql "SELECT COUNT(*) FROM notes WHERE type = 'being'")}} beings.
|
|
1347
1347
|
```
|
|
1348
1348
|
|
|
@@ -1373,14 +1373,14 @@ There are {{words (sql "SELECT COUNT(*) FROM notes WHERE type = 'being'")}} bein
|
|
|
1373
1373
|
| `words` | `number` | The number spelled out for running prose — `1200` becomes one thousand two hundred. Whole numbers only; a decimal is a finding, and `digits` takes one. |
|
|
1374
1374
|
| `digits` | `number` | The number as a grouped numeral — `1200` becomes 1,200, and a fractional part is kept. |
|
|
1375
1375
|
| `sql` | `"query"` | The single value a query returns, for use inside a sentence. The query is a quoted string, the same SQL a table fence takes. |
|
|
1376
|
-
| `dateformat` | `calendar date ["format"]`
|
|
1376
|
+
| `dateformat` | `[calendar] date ["format"]` | A date written in a calendar. The calendar is an Address or its shortcode; left out, it is the note's own calendar — its `data.calendar`, else its culture's, else for a place its parents', else the configured `defaultCalendar` — and a note with none prints the date as written. The date is the value a note carries, and the optional last argument names an output pattern. |
|
|
1377
1377
|
| `ref` | `address [form="number"\|"full"\|"title"] \| address field="when"\|"until"\|"kind"\|"summary"\|"name"` | A link to a captioned item, by its anchor — `"#thorn"` on this note, `"note-address#thorn"` on another. `form` is `number` (the default, and admitted explicitly), rendering "Figure 13"; `full`, the number and the caption; or `title`, the caption alone. Always renders as a link to the figure, and a link inside the caption contributes only its label text. The number rendered is the one the figure carries on the surface doing the rendering, whichever note names it. With `field` in place of `form`, the address names an event — `"place-ironfells#sack"`, `"#sack"` on this note, or `"lore-founding"` for a note holding one event — and the reference prints that event's `when`, `until`, `kind`, `summary` or `name` as plain text, never a link; a date prints as the note format prints any date. |
|
|
1378
1378
|
|
|
1379
1379
|
<!-- expression-helpers:end -->
|
|
1380
1380
|
|
|
1381
1381
|
A helper that is given the wrong kind of value reports it rather than printing something wrong: `words` refuses a decimal, the four comparisons refuse anything that is not a finite number, and `dateformat` refuses a date it cannot resolve in the calendar it was given.
|
|
1382
1382
|
|
|
1383
|
-
See [date rules](dates-and-calendars.md) for what `dateformat` accepts and the patterns its
|
|
1383
|
+
See [date rules](dates-and-calendars.md) for what `dateformat` accepts, the calendar it uses when none is named, and the patterns its last argument names.
|
|
1384
1384
|
|
|
1385
1385
|
### An event's date, inline
|
|
1386
1386
|
|
package/docs/configuration.md
CHANGED
|
@@ -54,7 +54,7 @@ around its own evaluation.
|
|
|
54
54
|
|
|
55
55
|
### Quick reference
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
25 top-level keys. `rootDir` is not one of them — a data configuration never
|
|
58
58
|
writes it — and is documented under [Derived values](#derived-values) instead,
|
|
59
59
|
alongside `foundryPackage`, `homepage`, `author` and `itemBuilders`, whose
|
|
60
60
|
data-configuration behaviour is also derivation rather than ordinary
|
|
@@ -63,6 +63,7 @@ authoring.
|
|
|
63
63
|
| Key | Type | Required | Default |
|
|
64
64
|
| ------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------- |
|
|
65
65
|
| [`currentDate`](#currentdate) | quoted neutral date string | no | `"720.1"` |
|
|
66
|
+
| [`defaultCalendar`](#defaultcalendar) | calendar note shortcode | no | — |
|
|
66
67
|
| [`contentPackage`](#contentpackage) | string | yes | — |
|
|
67
68
|
| [`foundryPackage`](#foundrypackage) | string | yes (`.mjs` only — derived in YAML); refused in a `documentation` package | — |
|
|
68
69
|
| [`homepage`](#homepage) | string | no (`.mjs` only — derived in YAML) | `null` |
|
|
@@ -88,7 +89,7 @@ authoring.
|
|
|
88
89
|
|
|
89
90
|
Any key outside this list is refused:
|
|
90
91
|
|
|
91
|
-
> `` `<key>` is not a recognized option (expected one of: rootDir, contentPackage, currentDate, foundryPackage, homepage, authors, packageKind, stats, itemBuilders, paths, skipDirectories, forbidGeneratedArt, icons, packs, docs, site, pdf, compatibility, relationships, systems, requiresSystem, packageBuild, publish, changelog). ``
|
|
92
|
+
> `` `<key>` is not a recognized option (expected one of: rootDir, contentPackage, currentDate, defaultCalendar, foundryPackage, homepage, authors, packageKind, stats, itemBuilders, paths, skipDirectories, forbidGeneratedArt, icons, packs, docs, site, pdf, compatibility, relationships, systems, requiresSystem, packageBuild, publish, changelog). ``
|
|
92
93
|
|
|
93
94
|
(`rootDir` appears in that list because it is a key `defineConfig` itself
|
|
94
95
|
accepts — an `.mjs` configuration authors it directly. A YAML configuration
|
|
@@ -195,7 +196,7 @@ build writes its `name` as `params.author`. `null` when `authors` is empty.
|
|
|
195
196
|
as an unknown key, at the key's own line, because `authors` is the one list a
|
|
196
197
|
package names its people in:
|
|
197
198
|
|
|
198
|
-
> ``package-build config: `author` is not a recognized option (expected one of: rootDir, contentPackage, currentDate, foundryPackage, homepage, authors, packageKind, stats, itemBuilders, paths, skipDirectories, forbidGeneratedArt, icons, packs, docs, site, pdf, compatibility, relationships, systems, requiresSystem, packageBuild, publish, changelog).``
|
|
199
|
+
> ``package-build config: `author` is not a recognized option (expected one of: rootDir, contentPackage, currentDate, defaultCalendar, foundryPackage, homepage, authors, packageKind, stats, itemBuilders, paths, skipDirectories, forbidGeneratedArt, icons, packs, docs, site, pdf, compatibility, relationships, systems, requiresSystem, packageBuild, publish, changelog).``
|
|
199
200
|
|
|
200
201
|
`package.json`'s own `author` is npm's and is not read.
|
|
201
202
|
|
|
@@ -313,6 +314,29 @@ day. Named calendars, `unknown`, numeric YAML values and malformed dates are
|
|
|
313
314
|
configuration errors located at `currentDate`. Birth dates can still use named
|
|
314
315
|
calendars when the output has the relevant calendar context.
|
|
315
316
|
|
|
317
|
+
### `defaultCalendar`
|
|
318
|
+
|
|
319
|
+
**Type:** string · optional · no default.
|
|
320
|
+
|
|
321
|
+
The shortcode of the `lore` note with `subType: calendar` that prints the dates
|
|
322
|
+
of every note no other rule gives a calendar. A note reads its dates in its own
|
|
323
|
+
`data.calendar`, else its culture's, else — for a place — its parents', and
|
|
324
|
+
only then in this one; with no `defaultCalendar` and nothing else to go on, a
|
|
325
|
+
date prints as it was written. The
|
|
326
|
+
[format reference](reference/format-details.md#a-notes-calendar) gives the
|
|
327
|
+
rules in full.
|
|
328
|
+
|
|
329
|
+
```yaml
|
|
330
|
+
contentPackage: thalorna
|
|
331
|
+
defaultCalendar: commoncal
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
A value that is not a lowercase alphanumeric shortcode is a configuration
|
|
335
|
+
error at load. A shortcode that names no calendar note in the package is a
|
|
336
|
+
build error located at `defaultCalendar`:
|
|
337
|
+
|
|
338
|
+
> `defaultCalendar commonkal names no calendar note in thalorna; name the shortcode of a lore note with subType: calendar`
|
|
339
|
+
|
|
316
340
|
### `contentPackage`
|
|
317
341
|
|
|
318
342
|
**Type:** string · **Required** · no default.
|
|
@@ -275,7 +275,7 @@ Five keys, and each answers a question the build cannot answer for itself:
|
|
|
275
275
|
Everything omitted has a default, and the defaults are the conventional
|
|
276
276
|
HeroicLands layout: the content tree at `assets/content`, the compiled packs at
|
|
277
277
|
`build/stage/packs`, the intermediates and caches elsewhere under `build/`.
|
|
278
|
-
[`configuration.md`](../configuration.md) documents
|
|
278
|
+
[`configuration.md`](../configuration.md) documents every top-level key,
|
|
279
279
|
what each refusal message means, and the five values that are derived rather
|
|
280
280
|
than authored.
|
|
281
281
|
|
|
@@ -432,17 +432,55 @@ A named date uses `datefrom <calendar> <date>`, where the final text follows the
|
|
|
432
432
|
|
|
433
433
|
`package-build datefrom <calendar> <date>` reads the default calendar pattern and prints a canonical day. `package-build dateto <calendar> <canonical-date>` prints the day in the covering era; `--format <name>` chooses another named output pattern. The [authoring guide](../authoring/dates-and-calendars.md) gives a complete example.
|
|
434
434
|
|
|
435
|
+
##### A note's calendar
|
|
436
|
+
|
|
437
|
+
A note's dates print in one calendar, the first of:
|
|
438
|
+
|
|
439
|
+
1. its own `data.calendar`, which every note type accepts, and which always
|
|
440
|
+
wins;
|
|
441
|
+
2. its culture's calendar: the culture note its `data.culture` names, resolved
|
|
442
|
+
by these same rules — in effect that culture's own `data.calendar`;
|
|
443
|
+
3. for a `place`, its parents' calendar: each note its `data.parents` names,
|
|
444
|
+
resolved by these same rules;
|
|
445
|
+
4. the package's [`defaultCalendar`](../configuration.md#defaultcalendar);
|
|
446
|
+
5. otherwise none, and a date prints as it was written.
|
|
447
|
+
|
|
448
|
+
Steps 2 and 3 take only a calendar that some note states. A culture or a
|
|
449
|
+
parent that itself falls through to `defaultCalendar` contributes nothing, so a
|
|
450
|
+
place whose parents all fall through takes the default. Parents that resolve to
|
|
451
|
+
**two or more distinct calendars** are a build error at the place's
|
|
452
|
+
`data.parents`, naming the place and each calendar with the parent it came
|
|
453
|
+
through:
|
|
454
|
+
|
|
455
|
+
```text
|
|
456
|
+
Places/Edge.md:6:3: error: place edge: data.parents resolve to different calendars (thalorna-note-lore-commoncal via north, thalorna-note-lore-vrcal via south); state data.calendar
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
Stating `data.calendar` on the place settles it. A cycle through
|
|
460
|
+
`data.parents` or `data.culture` contributes nothing, and the chain goes on to
|
|
461
|
+
`defaultCalendar`. A culture or parent in another package contributes the
|
|
462
|
+
`data.calendar` its published entry states, and nothing else.
|
|
463
|
+
|
|
464
|
+
The calendar decides what a reader sees wherever the note prints a date: the
|
|
465
|
+
infobox's `born` and `died`, `dateformat` with no calendar named, the `events`
|
|
466
|
+
relation's `whenText`, and every date in the [event views](#event-views) the
|
|
467
|
+
note's page shows.
|
|
468
|
+
|
|
435
469
|
Markdown prose accepts inline `{{...}}` expressions. A property path reads
|
|
436
470
|
the note's frontmatter, and `dateformat` converts a date to the reckoning used by a
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
471
|
+
calendar. The first argument names a calendar note by shortcode or Address, or
|
|
472
|
+
one of its eras by `<calendar>.<era>`; left out, the calendar is
|
|
473
|
+
[the note's own](#a-notes-calendar), and a note with none prints the date as
|
|
474
|
+
written. Use a full Address when a short name is ambiguous. The date is a
|
|
475
|
+
canonical date or a frontmatter property holding a date. An optional last
|
|
476
|
+
argument names an output format from the calendar note. With two arguments,
|
|
477
|
+
the first is the calendar unless it is a date that names no calendar, so
|
|
478
|
+
`{{dateformat data.born "long"}}` prints the note's date in its own calendar's
|
|
479
|
+
`long` format. An explicit era that does not cover the date is an error.
|
|
442
480
|
|
|
443
481
|
```markdown
|
|
444
482
|
{{name.full}} was born on {{dateformat "vrcal" data.born}}.
|
|
445
|
-
{{dateformat data.
|
|
483
|
+
{{dateformat data.born}}
|
|
446
484
|
The event fell on {{dateformat "vrcal" "300.25"}}.
|
|
447
485
|
{{and (gt 3 5) (lt 4 2)}}
|
|
448
486
|
{{sql "SELECT COUNT(*) FROM notes WHERE type = 'being'"}}
|
|
@@ -870,6 +908,7 @@ noticed:
|
|
|
870
908
|
| `seeAlso` | list of `{ address, gloss? }` | Deliberate cross-references in reading order, shown on the site, in journals and in books. |
|
|
871
909
|
| `seeAlso[].address` | a note `Address` | Required; the whole note to read next. |
|
|
872
910
|
| `seeAlso[].gloss` | `string` | An optional short phrase saying why to follow the reference. |
|
|
911
|
+
| `calendar` | `Address` | The calendar note this note's dates print in — see [a note's calendar](#a-notes-calendar). |
|
|
873
912
|
| `id` | `string` | A pinned document identity. |
|
|
874
913
|
| `pack` | `string` | The shared compendium route. |
|
|
875
914
|
| `packFolder` | `Address` or pack map | The shared compendium folder Address. |
|
|
@@ -2972,14 +3011,22 @@ ORDER BY whenSort
|
|
|
2972
3011
|
```
|
|
2973
3012
|
````
|
|
2974
3013
|
|
|
2975
|
-
| Column | What it holds
|
|
2976
|
-
| ------------------------ |
|
|
2977
|
-
| `note` | The canonical Address of the note the event is written on.
|
|
2978
|
-
| `address` | The event's own Address: `note#id` where the event has an `id`, the note's Address alone where it has none.
|
|
2979
|
-
| `id`, `kind`, `depth`, … | Every key of an event, each its own column under its own name — `id`, `kind`, `depth`, `when`, `until`, `recurs`, `summary`, `standing`, `names`, `where`, `who`, `follows`, `accounts`, `unresolved`, `sources`, `stated`.
|
|
2980
|
-
| `whenSort`, `untilSort` | The date's position on the canonical axis: the canonical year, with a day as its fraction of the year where the calendar states the year's length. `ORDER BY whenSort` is date order.
|
|
2981
|
-
| `whenText`, `untilText` | The date as a reader sees it, printed as `dateformat` prints it in the
|
|
2982
|
-
| `
|
|
3014
|
+
| Column | What it holds |
|
|
3015
|
+
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
3016
|
+
| `note` | The canonical Address of the note the event is written on. |
|
|
3017
|
+
| `address` | The event's own Address: `note#id` where the event has an `id`, the note's Address alone where it has none. |
|
|
3018
|
+
| `id`, `kind`, `depth`, … | Every key of an event, each its own column under its own name — `id`, `kind`, `depth`, `when`, `until`, `recurs`, `summary`, `standing`, `names`, `where`, `who`, `follows`, `accounts`, `unresolved`, `sources`, `stated`. |
|
|
3019
|
+
| `whenSort`, `untilSort` | The date's position on the canonical axis: the canonical year, with a day as its fraction of the year where the calendar states the year's length. `ORDER BY whenSort` is date order. |
|
|
3020
|
+
| `whenText`, `untilText` | The date as a reader of the owning note sees it, printed as `dateformat` prints it in [the owning note's calendar](#a-notes-calendar), else in the era the date itself names; `~` marks an approximate date. A date that does not resolve keeps the text its note wrote. |
|
|
3021
|
+
| `whenIn`, `untilIn` | The date in every calendar: a struct keyed by each calendar note's canonical Address, holding the date as `dateformat` prints it there. `whenIn['thalorna-note-lore-commoncal']` reads it in that calendar; a date that calendar cannot print reads as in `whenText`. |
|
|
3022
|
+
| `whenYear`, `untilYear` | The canonical year alone, for a filter such as `whenYear BETWEEN 200 AND 299`. |
|
|
3023
|
+
|
|
3024
|
+
A fence chooses which calendar its dates print in. `whenText` prints each
|
|
3025
|
+
row in the calendar of the note that owns the event, so a table gathering the
|
|
3026
|
+
events of notes with different calendars reads in more than one count;
|
|
3027
|
+
`whenIn['<calendar Address>']` prints every row in one. The generated [event
|
|
3028
|
+
views](#event-views) do the second, in the calendar of the page showing the
|
|
3029
|
+
view.
|
|
2983
3030
|
|
|
2984
3031
|
`when` and `until` read as the text the note wrote, `~` included. The sort
|
|
2985
3032
|
keys and years are positions on the canonical axis, which counts a year `0`
|
|
@@ -3777,7 +3824,7 @@ The build appends sections to the end of a note's body that list the events conc
|
|
|
3777
3824
|
| Accounts | `accounts` | an `affiliation`, a `place`, a `lore` note of `subType: culture` | each `accounts[]` entry the note gives, with the event it concerns | When, Event, What they say, Agrees |
|
|
3778
3825
|
| What followed | `followed` | a note holding events | events whose `follows[].event` names one of this note's events, with how | When, What followed, How |
|
|
3779
3826
|
|
|
3780
|
-
- **Every view's first column is When**,
|
|
3827
|
+
- **Every view's first column is When**, every row's date written in [the calendar of the page showing the view](#a-notes-calendar), whichever note owns the event, so one table reads in one count. The fence reads `whenIn['<calendar Address>']` for that calendar; on a page with no calendar it reads `whenText`, each date in its owning note's calendar. An event whose date does not resolve shows the text its note wrote.
|
|
3781
3828
|
- **A chronology's Felt here column appears only where some row is felt in the place.** A place whose rows are all events that happened there, or world events, has the When and What happened columns alone.
|
|
3782
3829
|
- **A chronology is always set across the full page width in a PDF book**, whatever its columns.
|
|
3783
3830
|
- **The views follow everything the author wrote**, in the order of the [generated sections](#generated-sections).
|
|
@@ -4080,7 +4127,6 @@ See [a being's subtype describes the subject](#a-beings-subtype-describes-the-su
|
|
|
4080
4127
|
| `gender` | `male \| female \| nonbinary \| none \| other` | Gender of the being — see [a being's look](#a-beings-look) |
|
|
4081
4128
|
| `species` | `Address` | Being's species (lore) |
|
|
4082
4129
|
| `born` | `date \| unknown` | When the being was born; absent, it was never born |
|
|
4083
|
-
| `calendar` | `Address` | Calendar note that prints the being's dates |
|
|
4084
4130
|
| `died` | `date \| unknown` | When the being died; absent, it is alive |
|
|
4085
4131
|
| `age` | `34 \| ~34` | Age in years, stated only to override what `born` says; `~` marks an estimate |
|
|
4086
4132
|
| `ageYears` | `number` | Written by the compiler beside an `age` estimate — the `~` stripped; a note never authors this |
|
|
@@ -6982,7 +7028,6 @@ level with no background prints nothing.
|
|
|
6982
7028
|
| `data` property | Values | Description |
|
|
6983
7029
|
| --------------------------------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
|
6984
7030
|
| `events` | event entries — see [Events](#events) | What happened to or at this subject: dated, attributed events |
|
|
6985
|
-
| `calendar` | `Address` | Calendar note that prints this place's dates |
|
|
6986
7031
|
| `demonym` | `string` | What a person from this place is called — a Vylarian |
|
|
6987
7032
|
| `purpose` | `placeCharacter` tag | The reason a settlement, site, or structure exists |
|
|
6988
7033
|
| `lore` | `Address[]` | Lore concerning this place — its peoples, its law, its calendar, its history |
|
|
@@ -32,14 +32,15 @@ These are the only keys a note writes at its top level, in the order the formatt
|
|
|
32
32
|
|
|
33
33
|
These fields are accepted by every note type. A field's value can still be irrelevant to a particular output; the build reports that where it can. `data.icon` is not shared: it is listed under each type whose document carries art.
|
|
34
34
|
|
|
35
|
-
| Field | Shape | Meaning
|
|
36
|
-
| ----------------- | ----------------------------------------------- |
|
|
37
|
-
| `data.seeAlso` | list of `{ address, gloss? }` | Deliberate cross-references in reading order, with optional glosses; shown on the site, in journals and in books.
|
|
38
|
-
| `data.
|
|
39
|
-
| `data.
|
|
40
|
-
| `data.
|
|
41
|
-
| `data.
|
|
42
|
-
| `data.
|
|
35
|
+
| Field | Shape | Meaning |
|
|
36
|
+
| ----------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
37
|
+
| `data.seeAlso` | list of `{ address, gloss? }` | Deliberate cross-references in reading order, with optional glosses; shown on the site, in journals and in books. |
|
|
38
|
+
| `data.calendar` | an Address | The calendar this note's dates print in, as a calendar lore note. Absent, the note takes its culture's calendar, then — for a place — its parents', then the configured `defaultCalendar`. |
|
|
39
|
+
| `data.id` | string | A fixed document identity when the derived identity is unsuitable. |
|
|
40
|
+
| `data.pack` | string | The shared compendium route, with a system block overriding it. |
|
|
41
|
+
| `data.packFolder` | an Address, or a map of Addresses keyed by pack | The shared compendium folder Address, with a system block overriding it. |
|
|
42
|
+
| `data.harnworld` | `{ realm?, ritual? }` | HârnWorld source details shared by every system — `realm` and `ritual`. |
|
|
43
|
+
| `data.banner` | an Address | The page's hero image — an `image` address, cut to 1792×768, or `none` to decline a hero image. Reaches no compiled document. |
|
|
43
44
|
|
|
44
45
|
**Inner keys** — a key a field's value does not declare is an error at its own line and column.
|
|
45
46
|
|
|
@@ -71,7 +72,6 @@ These fields are accepted by every note type. A field's value can still be irrel
|
|
|
71
72
|
| `data.gender` | string | One of `female`, `male`, `nonbinary`, `none` or `other`. `none` says the being has no gender; an absent field says its gender is unrecorded. See [a being's look](format-details.md#a-beings-look) for what each word means. |
|
|
72
73
|
| `data.species` | an Address | The being's species, as a lore note. |
|
|
73
74
|
| `data.born` | string | When the being was born — a date, or `unknown` where the birth is unrecorded. Absent, the being was never born. |
|
|
74
|
-
| `data.calendar` | an Address | Calendar that displays this being's dates. |
|
|
75
75
|
| `data.died` | string | When the being died — a date, or `unknown` where the death is unrecorded. Absent, the being is alive. |
|
|
76
76
|
| `data.age` | string | Age in years, stated only to override what `born` says — `34`, or `~34` for an estimate. Unstated beside a dated `born` it is computed; unstated beside an unknown or absent `born` the age is unknown. |
|
|
77
77
|
| `data.ageYears` | number | Written by the compiler beside an `age` estimate — the `~` stripped, the magnitude alone. A note never authors this. |
|
|
@@ -867,7 +867,6 @@ Lore records in-world knowledge. A `culture` describes a people; a `custom` desc
|
|
|
867
867
|
| Field | Shape | Meaning |
|
|
868
868
|
| -------------------------------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
869
869
|
| `data.events` | list of event entries | What happened to or at this subject — each entry one dated, attributed event: a founding, a war, a fall, or an occasion that recurs. |
|
|
870
|
-
| `data.calendar` | an Address | Calendar that displays this place's dates. |
|
|
871
870
|
| `data.demonym` | string | What a person from this place is called — a Vylarian. |
|
|
872
871
|
| `data.purpose` | string | The reason this settlement, site, or structure exists, selected from its placeCharacter tags. |
|
|
873
872
|
| `data.lore` | list of Addresses | Lore concerning this place — its peoples, its law, its calendar, its history. |
|
package/engine/content-index.mjs
CHANGED
|
@@ -86,6 +86,7 @@
|
|
|
86
86
|
*/
|
|
87
87
|
|
|
88
88
|
import { isAddressSegment } from "./address-charset.mjs";
|
|
89
|
+
import { configFileIn, resolveNoteCalendars } from "./note-calendars.mjs";
|
|
89
90
|
import { cultureInheritance, reportCultureParents } from "./culture-parents.mjs";
|
|
90
91
|
import {
|
|
91
92
|
formatDiagnostic,
|
|
@@ -162,7 +163,7 @@ import { resolveNoteId } from "./note-ids.mjs";
|
|
|
162
163
|
// The `package:` refusal, so a note declaring one is reported where it is
|
|
163
164
|
// rather than as a bare abort.
|
|
164
165
|
import { assertNoDeclaredPackage } from "./note-package.mjs";
|
|
165
|
-
import { loadPackConfig } from "./pack-config.mjs";
|
|
166
|
+
import { CONFIG_FILENAMES, loadPackConfig } from "./pack-config.mjs";
|
|
166
167
|
// The record accessors, which live apart so that a module the compilers load
|
|
167
168
|
// can read a record without importing this one and closing a cycle.
|
|
168
169
|
// Re-exported because this is where callers have always addressed them.
|
|
@@ -1062,6 +1063,10 @@ export function resolveCultures(
|
|
|
1062
1063
|
* reader receives each as a finding, and the emitter throws once, listing
|
|
1063
1064
|
* every one.
|
|
1064
1065
|
* @param {string} [options.currentDate="720.1"] - Setting-wide neutral current date.
|
|
1066
|
+
* @param {string} [options.defaultCalendar] - The calendar of last resort, a
|
|
1067
|
+
* calendar note's shortcode; see {@link module:engine/note-calendars}.
|
|
1068
|
+
* @param {string} [options.configFile] - The configuration file, where an
|
|
1069
|
+
* unknown `defaultCalendar` is reported.
|
|
1065
1070
|
* @param {(key: string) => ({culture?: unknown}|undefined)} [options.foreignRecord] -
|
|
1066
1071
|
* Another package's entry for a canonical address, read for a parent that
|
|
1067
1072
|
* package publishes; see {@link resolveCultures}.
|
|
@@ -1079,6 +1084,8 @@ export function collectContentIndex(
|
|
|
1079
1084
|
{
|
|
1080
1085
|
contentPackage,
|
|
1081
1086
|
currentDate,
|
|
1087
|
+
defaultCalendar,
|
|
1088
|
+
configFile,
|
|
1082
1089
|
skipDirectories,
|
|
1083
1090
|
assetsBase,
|
|
1084
1091
|
manifest,
|
|
@@ -1234,7 +1241,17 @@ export function collectContentIndex(
|
|
|
1234
1241
|
|
|
1235
1242
|
// Every note record exists and every Address in it is a tuple, so a parent
|
|
1236
1243
|
// is found by its canonical address. Before the sort, which reads nothing
|
|
1237
|
-
// the pass writes.
|
|
1244
|
+
// the pass writes. Calendars first: they read the culture a note states,
|
|
1245
|
+
// which the culture pass then replaces with the one it resolves.
|
|
1246
|
+
resolveNoteCalendars(records, {
|
|
1247
|
+
contentPackage,
|
|
1248
|
+
defaultCalendar,
|
|
1249
|
+
configFile,
|
|
1250
|
+
contentBase,
|
|
1251
|
+
foreignRecord,
|
|
1252
|
+
problems,
|
|
1253
|
+
parsed,
|
|
1254
|
+
});
|
|
1238
1255
|
resolveCultures(records, { contentPackage, contentBase, foreignRecord, problems, parsed });
|
|
1239
1256
|
const cultureNotes = records
|
|
1240
1257
|
.filter((record) => isNoteRecord(record) && record.type === "lore")
|
|
@@ -1459,6 +1476,8 @@ export function indexRecordsFor({
|
|
|
1459
1476
|
return collectContentIndex(tree, {
|
|
1460
1477
|
contentPackage: resolved.contentPackage,
|
|
1461
1478
|
currentDate: resolved.currentDate,
|
|
1479
|
+
defaultCalendar: resolved.defaultCalendar ?? undefined,
|
|
1480
|
+
configFile: configFileIn(resolved.rootDir, CONFIG_FILENAMES),
|
|
1462
1481
|
addressContext: {
|
|
1463
1482
|
...noteAddressContext(resolved),
|
|
1464
1483
|
declaresAddress: dependencyAddresses(resolved),
|
package/engine/content-links.mjs
CHANGED
|
@@ -239,6 +239,9 @@ export function buildLinkIndex(
|
|
|
239
239
|
const body = splitFrontmatter(raw)?.body ?? raw;
|
|
240
240
|
const type = record.type.toLowerCase();
|
|
241
241
|
const note = { file: absPath, rel, fm, body, raw, type };
|
|
242
|
+
// The calendar the index resolved, which the reckoning context built
|
|
243
|
+
// over these notes hands to every date printed for this note.
|
|
244
|
+
if (record.resolvedCalendar) note.resolvedCalendar = record.resolvedCalendar;
|
|
242
245
|
const hierarchyProblems = cultureRecordProblems(record);
|
|
243
246
|
note.inheritedCultureFields = cultureInheritedFields(record);
|
|
244
247
|
if (hierarchyProblems)
|