@heroiclands/package-build 22.7.0 → 22.9.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 +47 -0
- package/docs/api.md +45 -0
- package/docs/configuration.md +2 -2
- package/docs/content-format.md +152 -13
- package/engine/calendar-notes.mjs +805 -0
- package/engine/calendars.mjs +233 -0
- package/engine/content-format-check.mjs +10 -1
- package/engine/draft-notice.mjs +45 -13
- package/engine/frontmatter-lint.mjs +26 -0
- package/engine/index.mjs +9 -0
- package/engine/infobox.mjs +7 -2
- package/engine/note-dates.mjs +350 -0
- package/engine/note-vocabulary.mjs +69 -8
- package/engine/pdf-render.mjs +10 -0
- package/engine/retired-fields.mjs +58 -8
- package/package.json +1 -1
- package/types/engine/calendar-notes.d.mts +173 -0
- package/types/engine/calendars.d.mts +206 -0
- package/types/engine/draft-notice.d.mts +26 -4
- package/types/engine/index.d.mts +3 -0
- package/types/engine/note-dates.d.mts +70 -0
- package/types/engine/retired-fields.d.mts +23 -2
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The world facts a package declares, read from its own notes.
|
|
3
|
+
*
|
|
4
|
+
* Nothing here is configured and nothing is assumed: a package with no world
|
|
5
|
+
* note has no year, and every question that depends on one goes unasked.
|
|
6
|
+
*
|
|
7
|
+
* @param {object} [index] - The link index, holding every note in the package.
|
|
8
|
+
* @returns {{year: object|null, present: unknown, moon: object|null,
|
|
9
|
+
* body: object|null, moonName: string|null, yearNote: object|null,
|
|
10
|
+
* moonNote: object|null}} What the package's notes state.
|
|
11
|
+
*/
|
|
12
|
+
export function worldInvariants(index?: object): {
|
|
13
|
+
year: object | null;
|
|
14
|
+
present: unknown;
|
|
15
|
+
moon: object | null;
|
|
16
|
+
body: object | null;
|
|
17
|
+
moonName: string | null;
|
|
18
|
+
yearNote: object | null;
|
|
19
|
+
moonNote: object | null;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Check a `place` note's world facts.
|
|
23
|
+
*
|
|
24
|
+
* Declared on `place` beside its tenure check, so the lint runs both with the
|
|
25
|
+
* same index. Four rules, and each is a fact about the setting rather than
|
|
26
|
+
* about the file:
|
|
27
|
+
*
|
|
28
|
+
* - a world fact is written on a body — a `world` or a `celestial` — and
|
|
29
|
+
* nowhere else;
|
|
30
|
+
* - a package states **one** year, because two years is two settings and
|
|
31
|
+
* nothing can choose between them;
|
|
32
|
+
* - a package states **one** moon, for the same reason;
|
|
33
|
+
* - a moon with no year is refused, because a cycle measured in days has
|
|
34
|
+
* nothing to be measured against.
|
|
35
|
+
*
|
|
36
|
+
* `data.present` is read through the parser a note's dates go through, with the
|
|
37
|
+
* corpus in hand, so a present written in an era resolves where it is written.
|
|
38
|
+
*
|
|
39
|
+
* @param {object} note - The note, as the link index hands it over.
|
|
40
|
+
* @param {object} [opts]
|
|
41
|
+
* @param {object} [opts.index] - The link index, holding every note.
|
|
42
|
+
* @returns {object[]} Findings.
|
|
43
|
+
*/
|
|
44
|
+
export function checkWorldFacts(note: object, { index }?: {
|
|
45
|
+
index?: object | undefined;
|
|
46
|
+
}): object[];
|
|
47
|
+
/**
|
|
48
|
+
* Check a `lore` note's calendar declaration.
|
|
49
|
+
*
|
|
50
|
+
* Both halves of one sentence, and the second is the half that keeps the family
|
|
51
|
+
* from leaking: a calendar note must carry its months and its epoch, and a lore
|
|
52
|
+
* note that is not a calendar must carry none of the family at all.
|
|
53
|
+
*
|
|
54
|
+
* The sum is the only arithmetic. It runs where the package states a year and
|
|
55
|
+
* the note states months, and nowhere else — neither fires on a package that
|
|
56
|
+
* declared nothing.
|
|
57
|
+
*
|
|
58
|
+
* A calendar note **cannot** restate a world fact, and it needs no rule of its
|
|
59
|
+
* own to stop it: `data.year`, `data.moon`, `data.world` and `data.body` are
|
|
60
|
+
* declared on `place` and not on `lore`, so the closed `data:` container
|
|
61
|
+
* already refuses them by the rule it refuses every undeclared key by.
|
|
62
|
+
*
|
|
63
|
+
* @param {object} note - The note, as the link index hands it over.
|
|
64
|
+
* @param {object} [opts]
|
|
65
|
+
* @param {object} [opts.index] - The link index, for the world's year.
|
|
66
|
+
* @returns {object[]} Findings.
|
|
67
|
+
*/
|
|
68
|
+
export function checkCalendarNote(note: object, { index }?: {
|
|
69
|
+
index?: object | undefined;
|
|
70
|
+
}): object[];
|
|
71
|
+
/**
|
|
72
|
+
* The four days the year turns on, by day of year.
|
|
73
|
+
*
|
|
74
|
+
* The year opens on the first of the first month, and the year's length sets
|
|
75
|
+
* the spacing; nothing else is consulted. A body's tilt is what makes seasons
|
|
76
|
+
* exist at all, and it is read by nobody — a quarter day is where the calendar
|
|
77
|
+
* opens plus a quarter of the year, to the nearest whole day, because a day is
|
|
78
|
+
* the smallest thing a calendar can name.
|
|
79
|
+
*
|
|
80
|
+
* @param {number} daysPerYear - The world's year.
|
|
81
|
+
* @returns {number[]} Four day-of-year numbers, in order from the year's start.
|
|
82
|
+
*/
|
|
83
|
+
export function quarterDays(daysPerYear: number): number[];
|
|
84
|
+
/**
|
|
85
|
+
* Compile one calendar note and the package's world facts into one definition.
|
|
86
|
+
*
|
|
87
|
+
* The object both consumers read: array-shaped for core's `ArrayField`
|
|
88
|
+
* collections, carrying the keys core prunes and Calendaria keeps.
|
|
89
|
+
*
|
|
90
|
+
* @param {object} opts
|
|
91
|
+
* @param {object} opts.note - The calendar note.
|
|
92
|
+
* @param {object} opts.invariants - What {@link worldInvariants} read.
|
|
93
|
+
* @param {string} [opts.contentPackage] - The package shipping the note, which
|
|
94
|
+
* is a fact about the tree rather than about the note: a note never declares
|
|
95
|
+
* its own package.
|
|
96
|
+
* @returns {object} The definition.
|
|
97
|
+
*/
|
|
98
|
+
export function compileCalendar({ note, invariants, contentPackage }: {
|
|
99
|
+
note: object;
|
|
100
|
+
invariants: object;
|
|
101
|
+
contentPackage?: string | undefined;
|
|
102
|
+
}): object;
|
|
103
|
+
/**
|
|
104
|
+
* Wrap a definition in the envelope a Calendaria settings import reads.
|
|
105
|
+
*
|
|
106
|
+
* `calendarData` is the definition unchanged — the importer derives an id from
|
|
107
|
+
* its `name` and creates a custom calendar from it — so the envelope adds a
|
|
108
|
+
* header and nothing else. That is what makes the two artefacts assertable
|
|
109
|
+
* against each other rather than merely similar.
|
|
110
|
+
*
|
|
111
|
+
* @param {object} definition - What {@link compileCalendar} produced.
|
|
112
|
+
* @param {object} opts
|
|
113
|
+
* @param {string} opts.version - The Calendaria version this was generated
|
|
114
|
+
* against, which the importer records.
|
|
115
|
+
* @param {string} opts.exportedAt - When, as an ISO 8601 instant.
|
|
116
|
+
* @returns {object} The envelope.
|
|
117
|
+
*/
|
|
118
|
+
export function calendariaEnvelope(definition: object, { version, exportedAt }: {
|
|
119
|
+
version: string;
|
|
120
|
+
exportedAt: string;
|
|
121
|
+
}): object;
|
|
122
|
+
/**
|
|
123
|
+
* Every calendar a package declares, compiled.
|
|
124
|
+
*
|
|
125
|
+
* A package whose notes state no year declares no calendars and is asked
|
|
126
|
+
* nothing about one, which is the right answer for a package that builds a
|
|
127
|
+
* setting somebody else wrote down.
|
|
128
|
+
*
|
|
129
|
+
* @param {object} [index] - The link index, holding every note.
|
|
130
|
+
* @param {object} [opts]
|
|
131
|
+
* @param {string} [opts.contentPackage] - The package shipping the tree.
|
|
132
|
+
* @returns {{calendars: object[], invariants: object}} One compiled definition
|
|
133
|
+
* per calendar note, and the facts they were compiled against.
|
|
134
|
+
*/
|
|
135
|
+
export function compileCalendars(index?: object, { contentPackage }?: {
|
|
136
|
+
contentPackage?: string | undefined;
|
|
137
|
+
}): {
|
|
138
|
+
calendars: object[];
|
|
139
|
+
invariants: object;
|
|
140
|
+
};
|
|
141
|
+
/** The `lore` subType whose notes are calendars. */
|
|
142
|
+
export const CALENDAR_SUBTYPE: "calendar";
|
|
143
|
+
/**
|
|
144
|
+
* The `place` subTypes a world fact may be written on.
|
|
145
|
+
*
|
|
146
|
+
* `world` is a body people stand on; `celestial` is one they only look at. A
|
|
147
|
+
* region, a settlement, a site, a structure or a feature is somewhere *in* a
|
|
148
|
+
* world and states nothing about the world's year.
|
|
149
|
+
*
|
|
150
|
+
* @type {readonly string[]}
|
|
151
|
+
*/
|
|
152
|
+
export const INVARIANT_SUBTYPES: readonly string[];
|
|
153
|
+
/**
|
|
154
|
+
* The `data:` keys a calendar note may write — the closed list, in authored
|
|
155
|
+
* order.
|
|
156
|
+
*
|
|
157
|
+
* Every key in either target schema that is not here is either a world fact,
|
|
158
|
+
* read from a `place` note and written by the emitters, or omitted because no
|
|
159
|
+
* calendar has declared one.
|
|
160
|
+
*
|
|
161
|
+
* @type {readonly object[]}
|
|
162
|
+
*/
|
|
163
|
+
export const CALENDAR_FIELDS: readonly object[];
|
|
164
|
+
/**
|
|
165
|
+
* The `data:` keys a world or a celestial body may write.
|
|
166
|
+
*
|
|
167
|
+
* Four groups, and which note carries which is a fact about the body rather
|
|
168
|
+
* than a convention: a planet states its own size, tilt, year and present; a
|
|
169
|
+
* moon states its own size, orbit and cycle.
|
|
170
|
+
*
|
|
171
|
+
* @type {readonly object[]}
|
|
172
|
+
*/
|
|
173
|
+
export const INVARIANT_FIELDS: readonly object[];
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The year on the canonical axis that a written year lands on.
|
|
3
|
+
*
|
|
4
|
+
* The whole of the conversion. A reckoning differs from its neighbours in
|
|
5
|
+
* where its year 1 sits and in nothing else, so an era states one number and
|
|
6
|
+
* this states what to do with it.
|
|
7
|
+
*
|
|
8
|
+
* The two branches are the year-zero hole: the authored numbering has no year
|
|
9
|
+
* 0, so a positive year is one place closer to the epoch than its magnitude
|
|
10
|
+
* suggests and a negative year is exactly its magnitude below it.
|
|
11
|
+
*
|
|
12
|
+
* @param {number} year - The year as authored, signed, within its own
|
|
13
|
+
* reckoning. Never 0 — the authored numbering has no such year.
|
|
14
|
+
* @param {number} [epoch] - Where that reckoning's year 1 sits on the axis.
|
|
15
|
+
* Omitted, the axis itself.
|
|
16
|
+
* @returns {number} The signed year on the axis — authored `-1` is `0`.
|
|
17
|
+
*/
|
|
18
|
+
export function canonicalYear(year: number, epoch?: number): number;
|
|
19
|
+
/**
|
|
20
|
+
* The total-order key a date sorts on.
|
|
21
|
+
*
|
|
22
|
+
* Month and day fold into the fraction, so a mixed-precision list sorts stably
|
|
23
|
+
* against a single number instead of a three-key comparator. The arithmetic is
|
|
24
|
+
* done in ten-thousandths and divided once, because `year + 6 / 100 + 19 /
|
|
25
|
+
* 10000` accumulates a rounding error and `689.0619` is a value a reader
|
|
26
|
+
* compares against by eye.
|
|
27
|
+
*
|
|
28
|
+
* A coarser value sorts **before** the finer values inside it: `689` precedes
|
|
29
|
+
* `689/1`, which is the ordering a reader expects of a year whose month nobody
|
|
30
|
+
* wrote.
|
|
31
|
+
*
|
|
32
|
+
* @param {number} year - The year on the canonical axis.
|
|
33
|
+
* @param {number|null} month - The month, or `null`.
|
|
34
|
+
* @param {number|null} day - The day, or `null`.
|
|
35
|
+
* @returns {number} The sort key.
|
|
36
|
+
*/
|
|
37
|
+
export function dateSortKey(year: number, month: number | null, day: number | null): number;
|
|
38
|
+
/**
|
|
39
|
+
* One month of a calendar, as the note declares it.
|
|
40
|
+
*
|
|
41
|
+
* @typedef {object} CalendarMonth
|
|
42
|
+
* @property {string} name - What the month is called.
|
|
43
|
+
* @property {string} [abbreviation] - A short form, where the note gives one.
|
|
44
|
+
* @property {number} days - How many days it holds.
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* The months a calendar keeps, or `null` where it declares none.
|
|
48
|
+
*
|
|
49
|
+
* Separate from the check that reads it so a caller can ask what a calendar
|
|
50
|
+
* divides its year into without phrasing a finding about it. An empty list
|
|
51
|
+
* reads as no list: a calendar that declares nothing and one that declares
|
|
52
|
+
* nothing in a pair of brackets divide the year identically.
|
|
53
|
+
*
|
|
54
|
+
* @param {{months?: readonly CalendarMonth[]|null}} [calendar] - The calendar
|
|
55
|
+
* the date is written in, as its note declares it.
|
|
56
|
+
* @returns {{months: readonly CalendarMonth[]|null}} What it divides the year
|
|
57
|
+
* into.
|
|
58
|
+
*/
|
|
59
|
+
export function calendarStructure(calendar?: {
|
|
60
|
+
months?: readonly CalendarMonth[] | null;
|
|
61
|
+
}): {
|
|
62
|
+
months: readonly CalendarMonth[] | null;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* How long one month of a calendar is, or `null` where the calendar is silent.
|
|
66
|
+
*
|
|
67
|
+
* @param {{months?: readonly CalendarMonth[]|null}} [calendar] - The calendar.
|
|
68
|
+
* @param {number} month - The month, numbered from 1.
|
|
69
|
+
* @returns {number|null} Its length in days, or `null`.
|
|
70
|
+
*/
|
|
71
|
+
export function daysInMonth(calendar?: {
|
|
72
|
+
months?: readonly CalendarMonth[] | null;
|
|
73
|
+
}, month: number): number | null;
|
|
74
|
+
/**
|
|
75
|
+
* How many days the months add up to.
|
|
76
|
+
*
|
|
77
|
+
* The number a calendar's list claims the year is. Whether that is the year the
|
|
78
|
+
* world keeps is a question about the world, and is asked elsewhere.
|
|
79
|
+
*
|
|
80
|
+
* @param {readonly CalendarMonth[]} months - The ordered month list.
|
|
81
|
+
* @returns {number} The sum of their day counts.
|
|
82
|
+
*/
|
|
83
|
+
export function daysInYear(months: readonly CalendarMonth[]): number;
|
|
84
|
+
/**
|
|
85
|
+
* The day of the year each month opens on, in order, numbered from 1.
|
|
86
|
+
*
|
|
87
|
+
* The sum read as a sequence rather than as a total. Two lists holding the same
|
|
88
|
+
* numbers in a different order sum alike and open their months on different
|
|
89
|
+
* days, which is the error a total cannot see.
|
|
90
|
+
*
|
|
91
|
+
* @param {readonly CalendarMonth[]} months - The ordered month list.
|
|
92
|
+
* @returns {number[]} One entry per month: the day of the year it begins on.
|
|
93
|
+
*/
|
|
94
|
+
export function monthStarts(months: readonly CalendarMonth[]): number[];
|
|
95
|
+
/**
|
|
96
|
+
* Which day of the year a written month and day land on, numbered from 1.
|
|
97
|
+
*
|
|
98
|
+
* @param {readonly CalendarMonth[]} months - The ordered month list.
|
|
99
|
+
* @param {number} month - The month, numbered from 1.
|
|
100
|
+
* @param {number} day - The day within it, numbered from 1.
|
|
101
|
+
* @returns {number} The day of the year.
|
|
102
|
+
*/
|
|
103
|
+
export function dayOfYear(months: readonly CalendarMonth[], month: number, day: number): number;
|
|
104
|
+
/**
|
|
105
|
+
* How far into its cycle a moon is on a given day.
|
|
106
|
+
*
|
|
107
|
+
* **Floored, not truncated.** JavaScript's `%` takes the dividend's sign, so a
|
|
108
|
+
* day seven before the epoch yields `-7` where the phase is 23 — a value that
|
|
109
|
+
* is right on one side of the epoch and wrong on the other, which is invisible
|
|
110
|
+
* in any list that does not span it.
|
|
111
|
+
*
|
|
112
|
+
* @param {number} dayNumber - The day, on whatever continuous day count the
|
|
113
|
+
* caller keeps.
|
|
114
|
+
* @param {number} epochDay - The day of that same count on which the moon was
|
|
115
|
+
* new.
|
|
116
|
+
* @param {number} cycle - The cycle's length in days.
|
|
117
|
+
* @returns {number} Days into the cycle, `0` to `cycle - 1`.
|
|
118
|
+
*/
|
|
119
|
+
export function lunarPhase(dayNumber: number, epochDay: number, cycle: number): number;
|
|
120
|
+
/**
|
|
121
|
+
* **The axis every date normalises onto, and the one function that puts a
|
|
122
|
+
* reckoning on it.**
|
|
123
|
+
*
|
|
124
|
+
* A setting keeps several counts of years at once, each proclaimed by a body
|
|
125
|
+
* that has a note — a founding, a first occasion, a reign. A date either names
|
|
126
|
+
* one of them or names none, in which case it sits on the **canonical axis**.
|
|
127
|
+
*
|
|
128
|
+
* ## The canonical axis is an authoring device, not a calendar
|
|
129
|
+
*
|
|
130
|
+
* The axis is the line of integers dates written by peoples who never met are
|
|
131
|
+
* compared on. Nobody in a setting keeps it, no body stands behind it, and no
|
|
132
|
+
* shortcode addresses it: a date is on the axis exactly when it names no era.
|
|
133
|
+
* A reckoning whose year 1 happens to sit where the axis's year 1 sits
|
|
134
|
+
* coincides with it numerically and is still that people's own count.
|
|
135
|
+
*
|
|
136
|
+
* ## There is no year zero, and one function converts
|
|
137
|
+
*
|
|
138
|
+
* The authored numbering skips zero — `-1` sits immediately before `1` — while
|
|
139
|
+
* the normalised value does not, so that arithmetic across an epoch is one
|
|
140
|
+
* subtraction rather than a special case somebody forgets.
|
|
141
|
+
*
|
|
142
|
+
* ```text
|
|
143
|
+
* authored … -3 -2 -1 1 2 3 …
|
|
144
|
+
* canonicalYear … -2 -1 0 1 2 3 …
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* ```text
|
|
148
|
+
* canonicalYear(y, E) = E + (y > 0 ? y - 1 : y)
|
|
149
|
+
* ```
|
|
150
|
+
*
|
|
151
|
+
* `E` is where a reckoning's year 1 sits on the axis — the `canonicalYear` of
|
|
152
|
+
* an era's own `start`. The axis is the same function with `E` of
|
|
153
|
+
* {@link CANONICAL_EPOCH}, which holds by definition: the axis's year 1 is the
|
|
154
|
+
* axis's year 1.
|
|
155
|
+
*
|
|
156
|
+
* **The conversion is piecewise on the sign**, and that is the property worth
|
|
157
|
+
* guarding. Collapsed to a single branch it is correct on one side of an epoch
|
|
158
|
+
* and off by one on the other, which is invisible in any list that does not
|
|
159
|
+
* span it.
|
|
160
|
+
*
|
|
161
|
+
* ## The month structure is the calendar's, and an absent list bounds nothing
|
|
162
|
+
*
|
|
163
|
+
* An era moves where year 1 sits; it does not divide the year differently. The
|
|
164
|
+
* division belongs to the calendar, which is a note declaring an **ordered
|
|
165
|
+
* list** of months, each with a name and a day count. Position in the list is
|
|
166
|
+
* position in the year, so a five-day month sits wherever its people put it and
|
|
167
|
+
* needs no rule of its own.
|
|
168
|
+
*
|
|
169
|
+
* A date is bounded by the calendar it is written in, and a calendar whose list
|
|
170
|
+
* nobody has written down bounds nothing — a toolchain that invented twelve
|
|
171
|
+
* Gregorian months would refuse `667/2/30`, an ordinary date in a year of
|
|
172
|
+
* twelve thirty-day months.
|
|
173
|
+
*
|
|
174
|
+
* ## The lunar phase takes a floored modulo, not JavaScript's
|
|
175
|
+
*
|
|
176
|
+
* `%` takes the dividend's sign, so a day before the epoch yields `-7` where
|
|
177
|
+
* the phase is 23. {@link lunarPhase} is the one place that is written.
|
|
178
|
+
*
|
|
179
|
+
* @module
|
|
180
|
+
*/
|
|
181
|
+
/**
|
|
182
|
+
* Where the canonical axis's own year 1 sits — on itself.
|
|
183
|
+
*
|
|
184
|
+
* It takes no configuration entry and no era row, because it is true by
|
|
185
|
+
* definition rather than by declaration.
|
|
186
|
+
*
|
|
187
|
+
* @type {number}
|
|
188
|
+
*/
|
|
189
|
+
export const CANONICAL_EPOCH: number;
|
|
190
|
+
/**
|
|
191
|
+
* One month of a calendar, as the note declares it.
|
|
192
|
+
*/
|
|
193
|
+
export type CalendarMonth = {
|
|
194
|
+
/**
|
|
195
|
+
* - What the month is called.
|
|
196
|
+
*/
|
|
197
|
+
name: string;
|
|
198
|
+
/**
|
|
199
|
+
* - A short form, where the note gives one.
|
|
200
|
+
*/
|
|
201
|
+
abbreviation?: string | undefined;
|
|
202
|
+
/**
|
|
203
|
+
* - How many days it holds.
|
|
204
|
+
*/
|
|
205
|
+
days: number;
|
|
206
|
+
};
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* `body.game .app blockquote` carries a left rule and an indent — so the
|
|
6
6
|
* treatment survives with no stylesheet of this package's own. The mark is a
|
|
7
7
|
* Font Awesome element, which Foundry bundles; `aria-hidden` keeps it out of a
|
|
8
|
-
* screen reader, where the label reads it.
|
|
8
|
+
* screen reader, where the label reads it. The sentence is an `em`, which every
|
|
9
|
+
* renderer of HTML sets in italic with no stylesheet to ask.
|
|
9
10
|
*
|
|
10
11
|
* @returns {string} The notice's HTML.
|
|
11
12
|
*/
|
|
@@ -41,9 +42,30 @@ export function withDraftNotice(fm: object | null | undefined, html: string): st
|
|
|
41
42
|
/**
|
|
42
43
|
* The `#let` the book's notice is drawn by.
|
|
43
44
|
*
|
|
44
|
-
* Emitted with the rest of the book's preamble. The mark is a
|
|
45
|
-
* exclamation
|
|
46
|
-
* page, so there is no font to resolve and nothing that can come out as a
|
|
45
|
+
* Emitted with the rest of the book's preamble. The mark is a disc with an
|
|
46
|
+
* exclamation knocked out of it: two primitives and the face already setting
|
|
47
|
+
* the page, so there is no font to resolve and nothing that can come out as a
|
|
48
|
+
* box. It is filled in the accent the book rules its headings with and the
|
|
49
|
+
* glyph is the colour of the paper, so the mark carries against the running
|
|
50
|
+
* face rather than reading as a character of it.
|
|
51
|
+
*
|
|
52
|
+
* **The mark is a column, not a word.** A two-column grid puts it beside the
|
|
53
|
+
* sentence rather than inside it, so a notice that takes two lines sets its
|
|
54
|
+
* second line against the first and never under the disc; the grid centres the
|
|
55
|
+
* mark's cell on the block, so it holds the middle of one line or two. The rule
|
|
56
|
+
* is the block's own left stroke and spans whatever height the sentence takes.
|
|
57
|
+
*
|
|
58
|
+
* **The sentence sets in the book's body face, size and ink**, because it is
|
|
59
|
+
* the one thing in the entry a reader has to read before trusting the rest. The
|
|
60
|
+
* rule and the mark set the block apart; nothing else has to, and type set
|
|
61
|
+
* smaller or lighter than the prose around it reads as apparatus a reader may
|
|
62
|
+
* skip. The mark scales with that text, so a consumer setting the book larger
|
|
63
|
+
* or smaller carries the disc with it.
|
|
64
|
+
*
|
|
65
|
+
* **One number sets the mark.** The glyph is a multiple of the disc's radius
|
|
66
|
+
* rather than a size of its own, so the exclamation keeps its share of the disc
|
|
67
|
+
* however large the disc is drawn and resizing the mark is one edit. Both are
|
|
68
|
+
* `em`, so the mark still follows the body text.
|
|
47
69
|
*
|
|
48
70
|
* @returns {string} The Typst definition.
|
|
49
71
|
*/
|
package/types/engine/index.d.mts
CHANGED
|
@@ -29,6 +29,9 @@ export * as mapGraphviz from "./map-graphviz.mjs";
|
|
|
29
29
|
export * as mapBuild from "./map-build.mjs";
|
|
30
30
|
export * as siteMaps from "./site-maps.mjs";
|
|
31
31
|
export * as systems from "./systems.mjs";
|
|
32
|
+
export * as calendars from "./calendars.mjs";
|
|
33
|
+
export * as noteDates from "./note-dates.mjs";
|
|
34
|
+
export * as calendarNotes from "./calendar-notes.mjs";
|
|
32
35
|
export * as contentSlug from "./content-slug.mjs";
|
|
33
36
|
export * as contentAddress from "./content-address.mjs";
|
|
34
37
|
export * as subtypeRegistry from "./subtype-registry.mjs";
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse one authored date.
|
|
3
|
+
*
|
|
4
|
+
* Every field that holds a date — a birth, a death, an event's start and its
|
|
5
|
+
* end — parses through here, so there is one grammar to write, test, document
|
|
6
|
+
* and teach.
|
|
7
|
+
*
|
|
8
|
+
* Findings are returned rather than thrown, because a corpus pass wants every
|
|
9
|
+
* bad value in one run rather than the first. Each carries the `file` it was
|
|
10
|
+
* given and, where `raw` and `keyPath` locate the value, its line and column;
|
|
11
|
+
* a position that cannot be established honestly is dropped rather than
|
|
12
|
+
* defaulted, which is what keeps `file:line:column:` parseable.
|
|
13
|
+
*
|
|
14
|
+
* @param {unknown} value - The authored value. A number is what YAML hands
|
|
15
|
+
* back for a bare year, so it is accepted and stringified.
|
|
16
|
+
* @param {object} [options]
|
|
17
|
+
* @param {{months?: readonly object[]|null}} [options.calendar] - The calendar
|
|
18
|
+
* the value is written in, as its note declares it. Its ordered month list
|
|
19
|
+
* bounds a written month and a written day, the day against the length of
|
|
20
|
+
* the month it names. A calendar that declares no list bounds nothing.
|
|
21
|
+
* @param {string} [options.field] - The key that carried it, named in every
|
|
22
|
+
* message. Omitted, a message names the value alone.
|
|
23
|
+
* @param {boolean} [options.allowUnknown=true] - Whether `"unknown"` is a
|
|
24
|
+
* permitted value here. It is not, in a field whose absence already says the
|
|
25
|
+
* date is unrecorded.
|
|
26
|
+
* @param {string} [options.file] - The note, for the diagnostics.
|
|
27
|
+
* @param {string} [options.raw] - The note's full contents, to locate the value.
|
|
28
|
+
* @param {ReadonlyArray<string|number>} [options.keyPath] - Path to the key
|
|
29
|
+
* within the frontmatter, for the same.
|
|
30
|
+
* @returns {{date: object|null, findings: object[]}} The record, or `null` when
|
|
31
|
+
* the value is absent or refused, and every finding the value earned.
|
|
32
|
+
*/
|
|
33
|
+
export function parseNoteDate(value: unknown, options?: {
|
|
34
|
+
calendar?: {
|
|
35
|
+
months?: readonly object[] | null;
|
|
36
|
+
} | undefined;
|
|
37
|
+
field?: string | undefined;
|
|
38
|
+
allowUnknown?: boolean | undefined;
|
|
39
|
+
file?: string | undefined;
|
|
40
|
+
raw?: string | undefined;
|
|
41
|
+
keyPath?: readonly (string | number)[] | undefined;
|
|
42
|
+
}): {
|
|
43
|
+
date: object | null;
|
|
44
|
+
findings: object[];
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* The literal that says a thing happened and the date is not recorded.
|
|
48
|
+
*
|
|
49
|
+
* @type {string}
|
|
50
|
+
*/
|
|
51
|
+
export const UNKNOWN_DATE: string;
|
|
52
|
+
/**
|
|
53
|
+
* What a date's trailing token may look like.
|
|
54
|
+
*
|
|
55
|
+
* A calendar note's address followed by `.<era shortcode>`. The `{0,3}`
|
|
56
|
+
* repetition is the four address forms exactly — bare `shortcode`,
|
|
57
|
+
* `type-shortcode`, `system-type-shortcode` and
|
|
58
|
+
* `package-system-type-shortcode` — so the hyphen separates an address's
|
|
59
|
+
* segments, the dot separates the address from the era, and the split needs no
|
|
60
|
+
* lookahead.
|
|
61
|
+
*
|
|
62
|
+
* @type {RegExp}
|
|
63
|
+
*/
|
|
64
|
+
export const ERA_QUALIFIER_PATTERN: RegExp;
|
|
65
|
+
/**
|
|
66
|
+
* The grammar, as one expression.
|
|
67
|
+
*
|
|
68
|
+
* @type {RegExp}
|
|
69
|
+
*/
|
|
70
|
+
export const NOTE_DATE_PATTERN: RegExp;
|
|
@@ -292,9 +292,16 @@ export function retiredTopLevelMessage(field: {
|
|
|
292
292
|
*
|
|
293
293
|
* @param {object|null|undefined} fm - Parsed frontmatter.
|
|
294
294
|
* @param {string} current - The field's current name.
|
|
295
|
+
* @param {object} [options] - Options.
|
|
296
|
+
* @param {boolean} [options.inData=false] - Search the `data:` container
|
|
297
|
+
* instead. A `data:` field has exactly one home, so its retired spelling has
|
|
298
|
+
* exactly one too, and searching the block or the top level for it would
|
|
299
|
+
* answer about a key the container check has already refused.
|
|
295
300
|
* @returns {boolean} Whether the retired spelling is declared.
|
|
296
301
|
*/
|
|
297
|
-
export function declaresRetiredAlias(fm: object | null | undefined, current: string
|
|
302
|
+
export function declaresRetiredAlias(fm: object | null | undefined, current: string, { inData }?: {
|
|
303
|
+
inData?: boolean | undefined;
|
|
304
|
+
}): boolean;
|
|
298
305
|
/**
|
|
299
306
|
* Read a field that has a retired spelling, the current name winning.
|
|
300
307
|
*
|
|
@@ -310,9 +317,16 @@ export function declaresRetiredAlias(fm: object | null | undefined, current: str
|
|
|
310
317
|
*
|
|
311
318
|
* @param {object|null|undefined} fm - Parsed frontmatter.
|
|
312
319
|
* @param {string} current - The field's current name.
|
|
320
|
+
* @param {object} [options] - Options.
|
|
321
|
+
* @param {boolean} [options.inData=false] - Read the `data:` container instead,
|
|
322
|
+
* which is where a `data:` field and its retired spelling are both written.
|
|
323
|
+
* Dotted names resolve inside it, so `appearance.eye_color` reads the way it
|
|
324
|
+
* is authored.
|
|
313
325
|
* @returns {any} The value, or `undefined` when neither spelling carries one.
|
|
314
326
|
*/
|
|
315
|
-
export function readAliasedField(fm: object | null | undefined, current: string
|
|
327
|
+
export function readAliasedField(fm: object | null | undefined, current: string, { inData }?: {
|
|
328
|
+
inData?: boolean | undefined;
|
|
329
|
+
}): any;
|
|
316
330
|
/**
|
|
317
331
|
* The current field name a retired spelling was renamed to.
|
|
318
332
|
*
|
|
@@ -336,6 +350,13 @@ export function readAliasedField(fm: object | null | undefined, current: string)
|
|
|
336
350
|
* read past. Only `affiliation` declares the field, so the alias is reported
|
|
337
351
|
* there and the old spelling stays an ordinary unknown key everywhere else.
|
|
338
352
|
*
|
|
353
|
+
* **`born`.** A birthday is a day that recurs; what a note records is the date
|
|
354
|
+
* somebody was born, once. The two read alike while every value belonged to a
|
|
355
|
+
* living person, and `born` is what the field has to be called beside `died`,
|
|
356
|
+
* which a being now also states. It is the first alias whose field lives in
|
|
357
|
+
* `data:` rather than in a system block, so the two readers below take
|
|
358
|
+
* `inData`.
|
|
359
|
+
*
|
|
339
360
|
* @type {Readonly<Record<string, string>>}
|
|
340
361
|
*/
|
|
341
362
|
export const RETIRED_FIELD_ALIASES: Readonly<Record<string, string>>;
|