@heroiclands/package-build 22.16.0 → 22.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/bin/package-build.mjs +14 -2
- package/docs/api.md +22 -22
- package/docs/authoring/dates-and-calendars.md +63 -11
- package/docs/authoring/links-and-markup.md +1 -1
- package/docs/commands.md +8 -6
- package/docs/reference/format-details.md +107 -165
- package/docs/reference/note-types.md +11 -10
- package/engine/calendar-format.mjs +441 -0
- package/engine/calendar-human.mjs +65 -3
- package/engine/calendar-notes.mjs +277 -96
- package/engine/content-format.yaml +2 -1
- package/engine/date-conversion.mjs +4 -4
- package/engine/markdown-expressions.mjs +2 -1
- package/engine/note-dates.mjs +50 -22
- package/engine/reckoning-markers.mjs +154 -256
- package/package.json +1 -1
- package/types/engine/calendar-format.d.mts +33 -0
- package/types/engine/calendar-notes.d.mts +3 -3
- package/types/engine/date-conversion.d.mts +1 -1
- package/types/engine/note-dates.d.mts +2 -2
- package/types/engine/reckoning-markers.d.mts +13 -28
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @heroiclands/package-build
|
|
2
2
|
|
|
3
|
+
## 22.17.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
**Calendar dates**
|
|
8
|
+
|
|
9
|
+
- Calendar notes anchor their first year to a canonical day, count eras from calendar years, and include an era for dates before year one.
|
|
10
|
+
- Named calendar formats control how dates print; the standard format also controls how authored calendar dates are read.
|
|
11
|
+
- Calendars can name special days and divide the year into seasons, with those names available in formatted dates.
|
|
12
|
+
|
|
13
|
+
**Content dates**
|
|
14
|
+
|
|
15
|
+
- A date written as a year covers that whole year; a written day covers that day, and a clock time identifies a moment.
|
|
16
|
+
- Calendar starting days and moon phase references require a day so their dates cannot silently shift to the first day of a year.
|
|
17
|
+
|
|
3
18
|
## 22.16.0
|
|
4
19
|
|
|
5
20
|
### Minor Changes
|
package/bin/package-build.mjs
CHANGED
|
@@ -540,7 +540,10 @@ function datefromCommand() {
|
|
|
540
540
|
type: "string",
|
|
541
541
|
describe: "Calendar Address or shortcode",
|
|
542
542
|
})
|
|
543
|
-
.positional("date", {
|
|
543
|
+
.positional("date", {
|
|
544
|
+
type: "string",
|
|
545
|
+
describe: "Day written in that calendar's std format (or first named format)",
|
|
546
|
+
}),
|
|
544
547
|
handler: handler((args) => {
|
|
545
548
|
console.log(dateFromCalendar(args.calendar, args.date, calendarConversionContext()));
|
|
546
549
|
}),
|
|
@@ -561,10 +564,19 @@ function datetoCommand() {
|
|
|
561
564
|
.positional("canonical-date", {
|
|
562
565
|
type: "string",
|
|
563
566
|
describe: "Canonical <year>.<day>[:HHMMSS]",
|
|
567
|
+
})
|
|
568
|
+
.option("format", {
|
|
569
|
+
type: "string",
|
|
570
|
+
describe: "Named calendar format; defaults to std or the first declared format",
|
|
564
571
|
}),
|
|
565
572
|
handler: handler((args) => {
|
|
566
573
|
console.log(
|
|
567
|
-
dateToCalendar(
|
|
574
|
+
dateToCalendar(
|
|
575
|
+
args.calendar,
|
|
576
|
+
args.canonicalDate,
|
|
577
|
+
calendarConversionContext(),
|
|
578
|
+
args.format,
|
|
579
|
+
),
|
|
568
580
|
);
|
|
569
581
|
}),
|
|
570
582
|
};
|
package/docs/api.md
CHANGED
|
@@ -623,7 +623,7 @@ The closed registry of system ids, and the `none` that stands for no system at a
|
|
|
623
623
|
|
|
624
624
|
### `engine.calendars`
|
|
625
625
|
|
|
626
|
-
The axis every date normalises onto, the arithmetic over a calendar's month list, and the moon. A
|
|
626
|
+
The axis every date normalises onto, the arithmetic over a calendar's month list, and the moon. A calendar's `data.epoch` anchors its year 1, day 1 on that axis; its eras declare in-calendar start years. The year conversion is piecewise on the sign, because the authored numbering has no year zero while the normalised value does: authored `-1` is `0`, and `-1` and `1` are adjacent. `lunarPhase` uses a floored modulo on either side of the epoch.
|
|
627
627
|
|
|
628
628
|
The neutral day spelling is `<year>.<day>[:HHMMSS]`. The pure conversion functions take the world's year length and an explicit origin year, so their arithmetic names no month or era. A caller supplies those values from its content; no setting year is baked into the toolchain.
|
|
629
629
|
|
|
@@ -647,29 +647,29 @@ The neutral day spelling is `<year>.<day>[:HHMMSS]`. The pure conversion functio
|
|
|
647
647
|
|
|
648
648
|
### `engine.noteDates`
|
|
649
649
|
|
|
650
|
-
A date on a note is one authored
|
|
651
|
-
|
|
652
|
-
| Export | Signature
|
|
653
|
-
| ----------------------- |
|
|
654
|
-
| `UNKNOWN_DATE` | `const UNKNOWN_DATE`
|
|
655
|
-
| `NOTE_DATE_PATTERN` | `const NOTE_DATE_PATTERN`
|
|
656
|
-
| `DATEFROM_PATTERN` | `const DATEFROM_PATTERN`
|
|
657
|
-
| `ERA_QUALIFIER_PATTERN` | `const ERA_QUALIFIER_PATTERN`
|
|
658
|
-
| `parseNoteDate` | `parseNoteDate(value, options)`
|
|
659
|
-
| `eraCovering` | `eraCovering(date, eras, daysPerYear)`
|
|
660
|
-
| `formatNoteDate` | `formatNoteDate(date, era, daysPerYear)` | `{era, year, month, day, text, prose}` or `null` | printing a resolved date in a chosen era or its authored form |
|
|
661
|
-
| `formatDateInCalendar` | `formatDateInCalendar(date, reference, context)` | printable record or `null` | selecting a calendar's era and printing a resolved date in it |
|
|
662
|
-
| `calendarEras` | `calendarEras(reference, context)`
|
|
663
|
-
| `resolvedDateFields` | `resolvedDateFields(fm, context)`
|
|
650
|
+
A date on a note is one authored scalar. `<year>[.<day>[:HHMMSS]]` names a calendar-neutral year, day, or second; `datefrom vrcal 23 Taranis 326 VR` names a calendar, a named month, and an era. Year and day values span their written interval; a clock time identifies a second. Either form may begin with `~` for uncertainty beyond that interval. The `approximate` field records that explicit marker, while `precision` and `seconds` describe the interval or time. A resolved date carries a canonical year, span, and sort key; a neutral year has no `canonicalDay`, while day-precision dates have one. Print `prose ?? text`, order on `sort`, and do arithmetic on `canonicalYear`. The literal `unknown` has no sort key or canonical year. `resolvedDateFields` supplies identical derived records to JSONL and generated page frontmatter.
|
|
651
|
+
|
|
652
|
+
| Export | Signature | Returns | Use it when |
|
|
653
|
+
| ----------------------- | ------------------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------------------- |
|
|
654
|
+
| `UNKNOWN_DATE` | `const UNKNOWN_DATE` | — | naming the literal that says a date is not recorded |
|
|
655
|
+
| `NOTE_DATE_PATTERN` | `const NOTE_DATE_PATTERN` | — | matching the date grammar directly |
|
|
656
|
+
| `DATEFROM_PATTERN` | `const DATEFROM_PATTERN` | — | recognizing a named calendar conversion in frontmatter |
|
|
657
|
+
| `ERA_QUALIFIER_PATTERN` | `const ERA_QUALIFIER_PATTERN` | — | checking that a string is an era qualifier a date could carry |
|
|
658
|
+
| `parseNoteDate` | `parseNoteDate(value, options)` | `{date, findings}` — `date` is `null` when refused | reading a note's authored date, with every finding it earned |
|
|
659
|
+
| `eraCovering` | `eraCovering(date, eras, daysPerYear)` | one era or `null`; throws on overlap | selecting the era covering a resolved date's full precision |
|
|
660
|
+
| `formatNoteDate` | `formatNoteDate(date, era, daysPerYear, formatName?)` | `{era, year, month, day, text, prose}` or `null` | printing a resolved date in a chosen era or its authored form |
|
|
661
|
+
| `formatDateInCalendar` | `formatDateInCalendar(date, reference, context, formatName?)` | printable record or `null` | selecting a calendar's era and printing a resolved date in it |
|
|
662
|
+
| `calendarEras` | `calendarEras(reference, context)` | ordered era records | resolving an addressed calendar or one of its eras |
|
|
663
|
+
| `resolvedDateFields` | `resolvedDateFields(fm, context)` | map of normalized dates | deriving being and lore event date records for index and pages |
|
|
664
664
|
|
|
665
665
|
### `engine.dateConversion`
|
|
666
666
|
|
|
667
|
-
The exact-day conversion functions use the corpus reckoning context.
|
|
667
|
+
The exact-day conversion functions use the corpus reckoning context. `dateFromCalendar` reads the `std` pattern, or the first named pattern. An era-relative year needs its era label. They reject dates outside the selected era; approximate input keeps its `~` prefix.
|
|
668
668
|
|
|
669
|
-
| Export | Signature
|
|
670
|
-
| ------------------ |
|
|
671
|
-
| `dateFromCalendar` | `dateFromCalendar(reference, value, context)`
|
|
672
|
-
| `dateToCalendar` | `dateToCalendar(reference, canonicalDate, context)` | calendar date string | expressing one canonical day in a calendar |
|
|
669
|
+
| Export | Signature | Returns | Use it when |
|
|
670
|
+
| ------------------ | ---------------------------------------------------------------- | --------------------- | --------------------------------------------- |
|
|
671
|
+
| `dateFromCalendar` | `dateFromCalendar(reference, value, context)` | canonical date string | converting one calendar day to the world axis |
|
|
672
|
+
| `dateToCalendar` | `dateToCalendar(reference, canonicalDate, context, formatName?)` | calendar date string | expressing one canonical day in a calendar |
|
|
673
673
|
|
|
674
674
|
### `engine.calendarChoice`
|
|
675
675
|
|
|
@@ -700,7 +700,7 @@ invokes the check during frontmatter lint.
|
|
|
700
700
|
|
|
701
701
|
### `engine.reckoningMarkers`
|
|
702
702
|
|
|
703
|
-
The corpus registry
|
|
703
|
+
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.
|
|
704
704
|
|
|
705
705
|
| Export | Signature | Returns | Use it when |
|
|
706
706
|
| ------------------------- | --------------------------------------------- | ---------------------------------------- | ----------------------------------------------------------- |
|
|
@@ -720,7 +720,7 @@ A calendar is a `lore` note with `subType: calendar`, declaring the months it ke
|
|
|
720
720
|
| `CALENDAR_FORMAT_TOKENS` | `const CALENDAR_FORMAT_TOKENS` | — | checking bare date tokens in a format string |
|
|
721
721
|
| `INVARIANT_FIELDS` | `const INVARIANT_FIELDS` | — | reading the closed list of what a body may declare about itself |
|
|
722
722
|
| `checkCalendarNote` | `checkCalendarNote(note, opts)` | `object[]` — findings | holding a `lore` note to the family and to the year the world keeps |
|
|
723
|
-
| `checkCalendarDateFormats` | `checkCalendarDateFormats(note)` | `object[]` — findings | checking
|
|
723
|
+
| `checkCalendarDateFormats` | `checkCalendarDateFormats(note)` | `object[]` — findings | checking named patterns and the readable default |
|
|
724
724
|
| `checkWorldFacts` | `checkWorldFacts(note, opts)` | `object[]` — findings | holding a `place` note's world facts to one body, one year and one moon |
|
|
725
725
|
| `worldInvariants` | `worldInvariants(index)` | `{year, present, moon, body, moonName, …}` | reading the year, the present and the moon a package's own notes state |
|
|
726
726
|
| `quarterDays` | `quarterDays(daysPerYear)` | `number[]` — four days of the year | asking which days the year turns on |
|
|
@@ -7,27 +7,79 @@ subType: howto
|
|
|
7
7
|
|
|
8
8
|
# Dates, calendars, and eras
|
|
9
9
|
|
|
10
|
-
A canonical date
|
|
10
|
+
A canonical date uses the world's year and day count without choosing a culture's calendar. Write `<year>[.<day>[:HHMMSS]]`: `720` covers year 720, `720.136` covers its day 136, and `720.136:143005` identifies 14:30:05 on that day. The dot separates the year from the **day of year**, not a month. Negative years are valid, and the day must fit the world's declared year length. Prefix a date with `~` when its uncertainty extends outside the stated year, day, or second. `unknown` records an occurrence whose date is not known, in fields that permit it.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
## Define a calendar
|
|
13
|
+
|
|
14
|
+
A `lore` note with `subType: calendar` names months, weekdays, seasons, named days, eras, and date formats. Its `data.epoch` is the **canonical day that equals calendar year 1, day 1**. For a calendar beginning on canonical day `1.91`, write `epoch: 1.91`: calendar year 1 still starts at its own day 1. A calendar does not state the length of the world year: its months must sum to `data.year.days` on the world's `place` note.
|
|
13
15
|
|
|
14
16
|
```yaml
|
|
17
|
+
shortcode: commoncal
|
|
18
|
+
name: { full: The Common Calendar }
|
|
19
|
+
type: lore
|
|
20
|
+
subType: calendar
|
|
15
21
|
data:
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
epoch: 1.1
|
|
23
|
+
months:
|
|
24
|
+
- { name: Floralis, abbreviation: Flor, days: 30 }
|
|
25
|
+
- { name: Lusenar, abbreviation: Luse, days: 31 }
|
|
26
|
+
- { name: Murkas, abbreviation: Murk, days: 30 }
|
|
27
|
+
- { name: Taranis, abbreviation: Tara, days: 31 }
|
|
28
|
+
- { name: Vulcar, abbreviation: Vulc, days: 30 }
|
|
29
|
+
- { name: Menaris, abbreviation: Mena, days: 31 }
|
|
30
|
+
- { name: Venuris, abbreviation: Venu, days: 30 }
|
|
31
|
+
- { name: Karnavar, abbreviation: Karn, days: 30 }
|
|
32
|
+
- { name: Morveth, abbreviation: Morv, days: 31 }
|
|
33
|
+
- { name: Thanaris, abbreviation: Than, days: 30 }
|
|
34
|
+
- { name: Aetheris, abbreviation: Aeth, days: 31 }
|
|
35
|
+
- { name: Janar, abbreviation: Jana, days: 30 }
|
|
36
|
+
weekdays:
|
|
37
|
+
- { name: Newday, abbreviation: New }
|
|
38
|
+
- { name: Tillday, abbreviation: Til }
|
|
39
|
+
- { name: Growday, abbreviation: Gro }
|
|
40
|
+
- { name: Harvestday, abbreviation: Hrv }
|
|
41
|
+
- { name: Reapday, abbreviation: Rep }
|
|
42
|
+
- { name: Slowday, abbreviation: Slo }
|
|
43
|
+
- { name: Setday, abbreviation: Set }
|
|
44
|
+
seasons:
|
|
45
|
+
- { name: Spring, abbreviation: Spr, start: 1 }
|
|
46
|
+
- { name: Summer, abbreviation: Sum, start: 92 }
|
|
47
|
+
- { name: Fall, abbreviation: Fal, start: 183 }
|
|
48
|
+
- { name: Winter, abbreviation: Win, start: 274 }
|
|
49
|
+
namedDays:
|
|
50
|
+
- { name: New Years Day, abbreviation: NY, day: 1 }
|
|
51
|
+
formats:
|
|
52
|
+
std: "MM/DD/Y GGG"
|
|
53
|
+
long: "D MMMM Y GGG"
|
|
54
|
+
eras:
|
|
55
|
+
- { shortcode: bvr, name: Before Vylarian Reckoning, abbreviation: BVR, start: null }
|
|
56
|
+
- { shortcode: vr, name: Vylarian Reckoning, abbreviation: VR, start: 1 }
|
|
18
57
|
```
|
|
19
58
|
|
|
20
|
-
`
|
|
59
|
+
The `weekdays` array gives the names in order, starting at index 0. Weeks continue across month and year boundaries. Leave `weekdays` out when the calendar has no week. `seasons[].start` is the one-based day of year on which a season begins. Starts increase in array order. A season continues through the day before the next, and the last wraps through the beginning of the next year when the first season starts after day 1. `namedDays[].day` is also a one-based day of year. Its name appears through `[namedDay]`; `[namedDayAbbr]` prints the abbreviation.
|
|
60
|
+
|
|
61
|
+
Every calendar has exactly one era with `start: null` and one with `start: 1`. The null era covers the years before calendar year 1 and counts them backwards: under `Y GGG`, package-build prints canonical `-50.2` as `50 BVR` when the epoch is `1.1`. This null-start era is an authoring extension and is omitted from the Calendaria definition; Foundry's calendar represents current time. Each other `start` is a distinct, positive **calendar year**, never a day-precise date: `start: 701` begins on day 1 of calendar year 701. `start: 1` begins on the canonical day given by `epoch`, even when that day is `1.91` or another date. Eras end where the next numeric start begins. Array order does not determine chronology. The optional `marker` identifies an era in authored dates and must be unique across the corpus.
|
|
62
|
+
|
|
63
|
+
`formats` contains any number of named Calendaria patterns. `std` is the default for `dateto`, `datefrom`, and `dateformat`; if absent, the first named pattern is the default. The default pattern must contain enough information to read a day back: a complete year (`Y`, `YYYY`, or `[yearInEra]`), a day of year (`DDD`) or month and day, and an era label when using `[yearInEra]`. `Y` means the calendar year in Calendaria; `[yearInEra]` means the year counted from the era's start. In package-build's null-start era, `Y`, `YY`, and `YYYY` print the positive historical year. Other named patterns can use display-only Calendaria tokens. Use `package-build dateto <calendar> <canonical-date> --format <name>` or `{{dateformat "commoncal" data.born "long"}}` to select another output format. The [format token reference](../reference/format-details.md#calendar-format-tokens) lists every Calendaria token and the input constraints.
|
|
64
|
+
|
|
65
|
+
## Write and convert dates
|
|
21
66
|
|
|
22
|
-
A
|
|
67
|
+
A frontmatter date can use the canonical form or `datefrom <calendar> <date in the default format>`. The calendar may be a shortcode or Address. A named date keeps the precision it states: with the sample `std` pattern, `326 VR` covers a year, `04/326 VR` covers Taranis, and `04/23/326 VR` covers its twenty-third day. A date with an era-relative year names its era.
|
|
68
|
+
|
|
69
|
+
```yaml
|
|
70
|
+
data:
|
|
71
|
+
born: datefrom commoncal 04/23/326 VR
|
|
72
|
+
died: ~326.114
|
|
73
|
+
```
|
|
23
74
|
|
|
24
|
-
|
|
75
|
+
The conversion commands take the same forms:
|
|
25
76
|
|
|
26
77
|
```bash
|
|
27
|
-
package-build datefrom
|
|
28
|
-
package-build dateto
|
|
78
|
+
package-build datefrom commoncal '04/23/326 VR'
|
|
79
|
+
package-build dateto commoncal 326.114
|
|
80
|
+
package-build dateto commoncal 326.114 --format long
|
|
29
81
|
```
|
|
30
82
|
|
|
31
|
-
`datefrom`
|
|
83
|
+
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.
|
|
32
84
|
|
|
33
|
-
In prose, `{{dateformat "
|
|
85
|
+
In prose, `{{dateformat "commoncal" data.born}}` prints a date in the chosen calendar. `{{dateformat data.calendar data.born}}` uses the note's calendar Address. A third argument chooses another named pattern. A being or place can set `data.calendar`; its infobox uses that calendar for dates.
|
|
@@ -134,4 +134,4 @@ The index contains {{digits (sql "SELECT COUNT(*) FROM entries")}} entries.
|
|
|
134
134
|
{{and (gt 3 5) (lt 4 2)}}
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
-
Use `{{dateformat data.calendar data.born}}` when the note supplies a calendar Address. SQL fences produce tables; the `sql` helper returns one value for an inline expression. Wrap a numeric result in `words` for running prose or `digits` for a grouped numeral. See [date rules](dates-and-calendars.md) and [SQL details](../reference/format-details.md#content-tables) for query options.
|
|
137
|
+
Use `{{dateformat data.calendar data.born}}` when the note supplies a calendar Address. A third argument selects a named output pattern, as in `{{dateformat data.calendar data.born "long"}}`. SQL fences produce tables; the `sql` helper returns one value for an inline expression. Wrap a numeric result in `words` for running prose or `digits` for a grouped numeral. See [date rules](dates-and-calendars.md) and [SQL details](../reference/format-details.md#content-tables) for query options.
|
package/docs/commands.md
CHANGED
|
@@ -382,9 +382,10 @@ package-build datefrom <calendar> <date>
|
|
|
382
382
|
|
|
383
383
|
Reads the current content tree, resolves its world year and calendar eras, and
|
|
384
384
|
prints `<year>.<day>[:HHMMSS]` to standard output. `<calendar>` is a calendar
|
|
385
|
-
shortcode, full Address, or addressed era. The date
|
|
386
|
-
|
|
387
|
-
|
|
385
|
+
shortcode, full Address, or addressed era. The date follows the calendar's
|
|
386
|
+
`data.formats.std` pattern, or its first named pattern when `std` is absent.
|
|
387
|
+
For example, `MM/DD/Y GGG` reads `04/23/326 VR`. An era-relative year written
|
|
388
|
+
with `[yearInEra]` must identify its era. A date must specify a day;
|
|
388
389
|
year-only and month-only dates do not identify one canonical day.
|
|
389
390
|
Prefix the date with `~` to preserve an approximate value.
|
|
390
391
|
|
|
@@ -417,19 +418,20 @@ Express a canonical day in an authored calendar.
|
|
|
417
418
|
**SYNOPSIS**
|
|
418
419
|
|
|
419
420
|
```
|
|
420
|
-
package-build dateto <calendar> <canonical-date>
|
|
421
|
+
package-build dateto <calendar> <canonical-date> [--format <name>]
|
|
421
422
|
```
|
|
422
423
|
|
|
423
424
|
**DESCRIPTION**
|
|
424
425
|
|
|
425
426
|
Reads the current content tree, selects the era covering the canonical day, and
|
|
426
|
-
prints the date
|
|
427
|
+
prints the date using `data.formats.std`, or the first named pattern if `std`
|
|
428
|
+
is absent. The input is
|
|
427
429
|
`<year>.<day>[:HHMMSS]`, optionally prefixed with `~`. A date in a gap between
|
|
428
430
|
eras has no conversion.
|
|
429
431
|
|
|
430
432
|
**OPTIONS**
|
|
431
433
|
|
|
432
|
-
|
|
434
|
+
`--format` selects another named pattern from the calendar note; pass its name as the value.
|
|
433
435
|
|
|
434
436
|
**EXIT STATUS**
|
|
435
437
|
|