@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/engine/event-rows.mjs
CHANGED
|
@@ -25,10 +25,19 @@
|
|
|
25
25
|
* `resolvedDates.events`, position for position with `data.events`, and the
|
|
26
26
|
* sort keys are read from it rather than parsed again here.
|
|
27
27
|
*
|
|
28
|
-
* **`whenText` and `untilText` are the dates as a reader
|
|
29
|
-
* as the `dateformat` helper prints a date, in the
|
|
30
|
-
*
|
|
31
|
-
*
|
|
28
|
+
* **`whenText` and `untilText` are the dates as a reader of the owning note
|
|
29
|
+
* sees them**: printed as the `dateformat` helper prints a date, in the
|
|
30
|
+
* calendar the owning note resolves to — see
|
|
31
|
+
* {@link module:engine/note-calendars} — else in the era the date itself
|
|
32
|
+
* names. A date that does not resolve keeps its authored text.
|
|
33
|
+
*
|
|
34
|
+
* **`whenIn` and `untilIn` are the same dates in every calendar**: a struct
|
|
35
|
+
* keyed by each calendar note's canonical Address, every calendar the corpus
|
|
36
|
+
* holds or any note resolves to, so a query reads a date in the calendar it
|
|
37
|
+
* chooses — `e.whenIn['thalorna-note-lore-commoncal']`. Every row carries every
|
|
38
|
+
* key; a date a calendar cannot print reads there as it would in `whenText`
|
|
39
|
+
* with no calendar, and an absent date is `NULL`. The event views select the
|
|
40
|
+
* key of the page's calendar.
|
|
32
41
|
*
|
|
33
42
|
* @module
|
|
34
43
|
*/
|
|
@@ -36,6 +45,7 @@
|
|
|
36
45
|
import { ownDocumentSystem, renderAddress } from "./address.mjs";
|
|
37
46
|
import { printEventDateIn } from "./event-fields.mjs";
|
|
38
47
|
import { EVENT_ENTRY_KEYS } from "./note-event-terms.mjs";
|
|
48
|
+
import { calendarAddress } from "./reckoning-markers.mjs";
|
|
39
49
|
|
|
40
50
|
/** The columns a row carries besides the event's own keys, before them. */
|
|
41
51
|
const IDENTITY_COLUMNS = Object.freeze(["note", "address"]);
|
|
@@ -46,12 +56,16 @@ export const EVENT_SORT_COLUMNS = Object.freeze(["whenSort", "whenYear", "untilS
|
|
|
46
56
|
/** The printed dates a row carries, after the sort keys. */
|
|
47
57
|
export const EVENT_TEXT_COLUMNS = Object.freeze(["whenText", "untilText"]);
|
|
48
58
|
|
|
59
|
+
/** The dates a row carries in every calendar, after the printed ones. */
|
|
60
|
+
export const EVENT_CALENDAR_COLUMNS = Object.freeze(["whenIn", "untilIn"]);
|
|
61
|
+
|
|
49
62
|
/** Every column of the `events` relation, in order. */
|
|
50
63
|
export const EVENT_COLUMNS = Object.freeze([
|
|
51
64
|
...IDENTITY_COLUMNS,
|
|
52
65
|
...EVENT_ENTRY_KEYS,
|
|
53
66
|
...EVENT_SORT_COLUMNS,
|
|
54
67
|
...EVENT_TEXT_COLUMNS,
|
|
68
|
+
...EVENT_CALENDAR_COLUMNS,
|
|
55
69
|
]);
|
|
56
70
|
|
|
57
71
|
/** The keys whose authored value is a date, printed as the text it was written as. */
|
|
@@ -95,18 +109,35 @@ function axisKeys(date) {
|
|
|
95
109
|
}
|
|
96
110
|
|
|
97
111
|
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
112
|
+
* Every calendar a set of records can print an event's date in: each calendar
|
|
113
|
+
* note's canonical Address, and every calendar a note resolves to.
|
|
100
114
|
*
|
|
101
|
-
* @param {Record<string, any
|
|
102
|
-
*
|
|
115
|
+
* @param {Iterable<Record<string, any>>} records - Index records, every
|
|
116
|
+
* Address a string.
|
|
117
|
+
* @returns {string[]} The calendars, sorted.
|
|
103
118
|
*/
|
|
104
|
-
function
|
|
119
|
+
export function eventCalendars(records) {
|
|
120
|
+
const calendars = new Set();
|
|
105
121
|
for (const record of records) {
|
|
106
|
-
|
|
107
|
-
|
|
122
|
+
const resolved = calendarAddress(record?.resolvedCalendar);
|
|
123
|
+
if (resolved) calendars.add(resolved);
|
|
124
|
+
if (
|
|
125
|
+
record?.type === "lore" &&
|
|
126
|
+
String(record.subType ?? "").toLowerCase() === "calendar" &&
|
|
127
|
+
record.package &&
|
|
128
|
+
record.shortcode &&
|
|
129
|
+
!record.documents
|
|
130
|
+
)
|
|
131
|
+
calendars.add(
|
|
132
|
+
renderAddress({
|
|
133
|
+
package: String(record.package),
|
|
134
|
+
system: "note",
|
|
135
|
+
type: "lore",
|
|
136
|
+
shortcode: String(record.shortcode),
|
|
137
|
+
}),
|
|
138
|
+
);
|
|
108
139
|
}
|
|
109
|
-
return
|
|
140
|
+
return [...calendars].sort();
|
|
110
141
|
}
|
|
111
142
|
|
|
112
143
|
/**
|
|
@@ -115,12 +146,16 @@ function worldCalendar(records) {
|
|
|
115
146
|
* @param {Iterable<Record<string, any>>} records - Index records, every
|
|
116
147
|
* Address a string, already narrowed to the audience being published to.
|
|
117
148
|
* @param {object} [dates] - The reckoning context the dates are printed in.
|
|
149
|
+
* @param {readonly string[]} [calendars] - The calendars `whenIn` and
|
|
150
|
+
* `untilIn` are keyed by: {@link eventCalendars} of every record of the
|
|
151
|
+
* corpus, whatever the audience, so every surface's relation has the same
|
|
152
|
+
* keys. Absent, those of `records`.
|
|
118
153
|
* @returns {object[]} One row per event entry, in record then entry order.
|
|
119
154
|
*/
|
|
120
|
-
export function eventRows(records, dates) {
|
|
155
|
+
export function eventRows(records, dates, calendars) {
|
|
121
156
|
const rows = [];
|
|
122
157
|
const all = [...records];
|
|
123
|
-
const
|
|
158
|
+
const keys = calendars ?? eventCalendars(all);
|
|
124
159
|
for (const record of all) {
|
|
125
160
|
const events = record?.data?.events;
|
|
126
161
|
if (!Array.isArray(events) || !events.length) continue;
|
|
@@ -128,7 +163,7 @@ export function eventRows(records, dates) {
|
|
|
128
163
|
if (!note) continue;
|
|
129
164
|
const resolved =
|
|
130
165
|
Array.isArray(record.resolvedDates?.events) ? record.resolvedDates.events : [];
|
|
131
|
-
const calendar =
|
|
166
|
+
const calendar = calendarAddress(record.resolvedCalendar);
|
|
132
167
|
events.forEach((entry, position) => {
|
|
133
168
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return;
|
|
134
169
|
const row = {
|
|
@@ -149,10 +184,20 @@ export function eventRows(records, dates) {
|
|
|
149
184
|
row.untilSort = until.sort;
|
|
150
185
|
row.untilYear = until.year;
|
|
151
186
|
for (const key of DATE_KEYS) {
|
|
187
|
+
const date = resolved[position]?.[key];
|
|
152
188
|
row[`${key}Text`] =
|
|
153
|
-
row[key] === null ?
|
|
154
|
-
|
|
155
|
-
|
|
189
|
+
row[key] === null ? null : printEventDateIn(row[key], date, dates, calendar);
|
|
190
|
+
row[`${key}In`] =
|
|
191
|
+
keys.length ?
|
|
192
|
+
Object.fromEntries(
|
|
193
|
+
keys.map((each) => [
|
|
194
|
+
each,
|
|
195
|
+
row[key] === null ?
|
|
196
|
+
null
|
|
197
|
+
: printEventDateIn(row[key], date, dates, each),
|
|
198
|
+
]),
|
|
199
|
+
)
|
|
200
|
+
: null;
|
|
156
201
|
}
|
|
157
202
|
rows.push(row);
|
|
158
203
|
});
|
package/engine/event-views.mjs
CHANGED
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
import { ownDocumentSystem, renderAddress } from "./address.mjs";
|
|
43
43
|
import { authoredSection, sectionHeading } from "./generated-sections.mjs";
|
|
44
|
+
import { calendarAddress } from "./reckoning-markers.mjs";
|
|
44
45
|
|
|
45
46
|
/** A literal SQL string. */
|
|
46
47
|
const literal = (text) => `'${String(text).replace(/'/g, "''")}'`;
|
|
@@ -48,6 +49,16 @@ const literal = (text) => `'${String(text).replace(/'/g, "''")}'`;
|
|
|
48
49
|
/** A list of SQL string literals, for an `IN (…)`. */
|
|
49
50
|
const literals = (texts) => texts.map(literal).join(", ");
|
|
50
51
|
|
|
52
|
+
/**
|
|
53
|
+
* The `When` column of a view on a page whose dates print in `calendar`: the
|
|
54
|
+
* event's date in that calendar, or — on a page with no calendar — in its
|
|
55
|
+
* owning note's.
|
|
56
|
+
*
|
|
57
|
+
* @param {string} [calendar] - The page's calendar, a canonical Address.
|
|
58
|
+
* @returns {string} The column's expression.
|
|
59
|
+
*/
|
|
60
|
+
const whenColumn = (calendar) => (calendar ? `e.whenIn[${literal(calendar)}]` : "e.whenText");
|
|
61
|
+
|
|
51
62
|
/** The order every view sorts its rows in: by date, undated last. */
|
|
52
63
|
const BY_DATE = "ORDER BY e.whenSort NULLS LAST, e.address";
|
|
53
64
|
|
|
@@ -65,7 +76,7 @@ const BY_DATE = "ORDER BY e.whenSort NULLS LAST, e.address";
|
|
|
65
76
|
*
|
|
66
77
|
* @type {ReadonlyArray<Readonly<{slug: string, heading: string,
|
|
67
78
|
* applies: (record: object) => boolean,
|
|
68
|
-
* query: (self: string[], shape: CorpusShape, columns?: {felt?: boolean}) => {fence: string, own?: string}|null,
|
|
79
|
+
* query: (self: string[], shape: CorpusShape, columns?: {felt?: boolean, calendar?: string}) => {fence: string, own?: string}|null,
|
|
69
80
|
* owners?: (db: object, selves: string[][], shape: CorpusShape) => Promise<Set<string>>,
|
|
70
81
|
* felt?: (db: object, selves: string[][], shape: CorpusShape) => Promise<Set<string>>}>>}
|
|
71
82
|
*/
|
|
@@ -87,13 +98,13 @@ export const EVENT_VIEWS = Object.freeze([
|
|
|
87
98
|
(record.type === "lore" && record.subType === "culture"),
|
|
88
99
|
owners: (db, selves, shape) =>
|
|
89
100
|
namedOwners(db, selves, "SELECT unnest(who).ref AS ref FROM events", shape.who),
|
|
90
|
-
query: (self, shape) => {
|
|
101
|
+
query: (self, shape, columns = {}) => {
|
|
91
102
|
if (!shape.who) return null;
|
|
92
103
|
const named = `list_filter(e.who, w -> w.ref IN (${literals(self)}))`;
|
|
93
104
|
return {
|
|
94
105
|
fence: [
|
|
95
106
|
"SELECT e.note AS _ref,",
|
|
96
|
-
|
|
107
|
+
` ${whenColumn(columns.calendar)} AS "When",`,
|
|
97
108
|
' e.summary AS "What happened",',
|
|
98
109
|
` array_to_string(list_transform(${named}, w -> w.role), ', ') AS "Role"`,
|
|
99
110
|
"FROM events e",
|
|
@@ -117,12 +128,12 @@ export const EVENT_VIEWS = Object.freeze([
|
|
|
117
128
|
'SELECT account."by" AS ref FROM (SELECT unnest(accounts) AS account FROM events)',
|
|
118
129
|
shape.accounts,
|
|
119
130
|
),
|
|
120
|
-
query: (self, shape) => {
|
|
131
|
+
query: (self, shape, columns = {}) => {
|
|
121
132
|
if (!shape.accounts) return null;
|
|
122
133
|
return {
|
|
123
134
|
fence: [
|
|
124
135
|
"SELECT e.note AS _ref,",
|
|
125
|
-
|
|
136
|
+
` ${whenColumn(columns.calendar)} AS "When",`,
|
|
126
137
|
' e.summary AS "Event",',
|
|
127
138
|
' e.account.says AS "What they say",',
|
|
128
139
|
' e.account.agrees AS "Agrees"',
|
|
@@ -145,7 +156,7 @@ export const EVENT_VIEWS = Object.freeze([
|
|
|
145
156
|
"FROM (SELECT unnest(follows) AS edge FROM events)",
|
|
146
157
|
shape.follows,
|
|
147
158
|
),
|
|
148
|
-
query: (self, shape) => {
|
|
159
|
+
query: (self, shape, columns = {}) => {
|
|
149
160
|
if (!shape.follows) return null;
|
|
150
161
|
const edges =
|
|
151
162
|
`list_filter(e.follows, f -> split_part(f.event, '#', 1) ` +
|
|
@@ -153,7 +164,7 @@ export const EVENT_VIEWS = Object.freeze([
|
|
|
153
164
|
return {
|
|
154
165
|
fence: [
|
|
155
166
|
"SELECT e.note AS _ref,",
|
|
156
|
-
|
|
167
|
+
` ${whenColumn(columns.calendar)} AS "When",`,
|
|
157
168
|
' e.summary AS "What followed",',
|
|
158
169
|
` array_to_string(list_transform(${edges}, f -> f.how), ', ') AS "How"`,
|
|
159
170
|
"FROM events e",
|
|
@@ -307,8 +318,9 @@ async function chronologyRoots(db, selves, shape, conditions) {
|
|
|
307
318
|
*
|
|
308
319
|
* @param {string[]} self - The place's Address, in each form.
|
|
309
320
|
* @param {CorpusShape} shape - What the corpus states.
|
|
310
|
-
* @param {{felt?: boolean}} [columns] - `felt: false` when
|
|
311
|
-
* place is felt there, which leaves the `Felt here` column
|
|
321
|
+
* @param {{felt?: boolean, calendar?: string}} [columns] - `felt: false` when
|
|
322
|
+
* no row of this place is felt there, which leaves the `Felt here` column
|
|
323
|
+
* out; `calendar`, the page's calendar, which the `When` column prints in.
|
|
312
324
|
* @returns {{fence: string, own: string}|null} The query, and the one that
|
|
313
325
|
* counts the place's own rows.
|
|
314
326
|
*/
|
|
@@ -332,7 +344,7 @@ function chronologyQuery(self, shape, columns = {}) {
|
|
|
332
344
|
...below,
|
|
333
345
|
"here AS (SELECT list(place) AS places FROM below)",
|
|
334
346
|
"SELECT e.note AS _ref,",
|
|
335
|
-
|
|
347
|
+
` ${whenColumn(columns.calendar)} AS "When",`,
|
|
336
348
|
shape.reach && columns.felt !== false ?
|
|
337
349
|
' e.summary AS "What happened",'
|
|
338
350
|
: ' e.summary AS "What happened"',
|
|
@@ -453,11 +465,12 @@ export async function eventViewSections(db, records, fileOf, only) {
|
|
|
453
465
|
const sections = new Map();
|
|
454
466
|
for (const view of EVENT_VIEWS) {
|
|
455
467
|
if (!view.applies(record) || authoredSection(record, view.slug)) continue;
|
|
456
|
-
const query = view.query(
|
|
457
|
-
self,
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
468
|
+
const query = view.query(self, shape, {
|
|
469
|
+
...(felt.has(view.slug) ? { felt: felt.get(view.slug).has(self[0]) } : {}),
|
|
470
|
+
...(calendarAddress(record.resolvedCalendar) ?
|
|
471
|
+
{ calendar: calendarAddress(record.resolvedCalendar) }
|
|
472
|
+
: {}),
|
|
473
|
+
});
|
|
461
474
|
if (!query) continue;
|
|
462
475
|
const has =
|
|
463
476
|
owned.has(view.slug) ?
|
package/engine/index-records.mjs
CHANGED
package/engine/infobox.mjs
CHANGED
|
@@ -128,6 +128,7 @@ import {
|
|
|
128
128
|
standingLead,
|
|
129
129
|
} from "./standings.mjs";
|
|
130
130
|
import { AddressEntries } from "./address-values.mjs";
|
|
131
|
+
import { noteCalendar } from "./note-calendars.mjs";
|
|
131
132
|
|
|
132
133
|
/**
|
|
133
134
|
* How a section arranges what it holds.
|
|
@@ -1066,15 +1067,10 @@ function noteBox(
|
|
|
1066
1067
|
: parsed?.qualifier ? dates.eras?.get(parsed.qualifier)
|
|
1067
1068
|
: null;
|
|
1068
1069
|
let printable = null;
|
|
1069
|
-
|
|
1070
|
+
const calendar = noteCalendar(fm, dates);
|
|
1071
|
+
if (parsed?.known && calendar) {
|
|
1070
1072
|
try {
|
|
1071
|
-
printable = formatDateInCalendar(
|
|
1072
|
-
parsed,
|
|
1073
|
-
isAddressTuple(data.calendar) ?
|
|
1074
|
-
renderAddress(data.calendar)
|
|
1075
|
-
: data.calendar,
|
|
1076
|
-
dates,
|
|
1077
|
-
);
|
|
1073
|
+
printable = formatDateInCalendar(parsed, calendar, dates);
|
|
1078
1074
|
} catch {
|
|
1079
1075
|
// The calendar reference is checked at the authored field.
|
|
1080
1076
|
}
|
|
@@ -15,11 +15,12 @@ import Handlebars from "handlebars";
|
|
|
15
15
|
|
|
16
16
|
import { isAddressTuple, renderAddress } from "./address.mjs";
|
|
17
17
|
import { matchAllOutsideCode, replaceOutsideCode } from "./code-fences.mjs";
|
|
18
|
-
import { formatDateInCalendar, parseNoteDate } from "./note-dates.mjs";
|
|
18
|
+
import { calendarEras, formatDateInCalendar, parseNoteDate } from "./note-dates.mjs";
|
|
19
19
|
import { numberWords, numberDigits } from "./number-words.mjs";
|
|
20
20
|
import { slugify } from "./content-slug.mjs";
|
|
21
21
|
import { WIKILINK, authoredLabel, isSamePage, parseWikilink } from "./wikilink-syntax.mjs";
|
|
22
|
-
import { EVENT_REFERENCE_FIELDS, eventFieldText } from "./event-fields.mjs";
|
|
22
|
+
import { EVENT_REFERENCE_FIELDS, eventFieldText, printEventDate } from "./event-fields.mjs";
|
|
23
|
+
import { noteCalendar } from "./note-calendars.mjs";
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* An inline expression, as an author writes one.
|
|
@@ -33,6 +34,48 @@ import { EVENT_REFERENCE_FIELDS, eventFieldText } from "./event-fields.mjs";
|
|
|
33
34
|
*/
|
|
34
35
|
export const EXPRESSION = /(?<![\\{])\{\{(?![{<%])([^{}\n]+)\}\}(?!\})/g;
|
|
35
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Which of `dateformat`'s arguments is which. Three are a calendar, a date and
|
|
39
|
+
* a format. Two are a calendar and a date, unless the first is absent — a
|
|
40
|
+
* `data.calendar` the note leaves unset is no calendar — or is a date that
|
|
41
|
+
* names no calendar, when they are a date and a format. One is a date.
|
|
42
|
+
*
|
|
43
|
+
* @param {unknown[]} given - The arguments, without Handlebars' options.
|
|
44
|
+
* @param {object} [dates] - The reckoning context.
|
|
45
|
+
* @returns {{calendar?: unknown, authored: unknown, format?: unknown}} The roles.
|
|
46
|
+
*/
|
|
47
|
+
function dateformatArguments(given, dates) {
|
|
48
|
+
if (given.length >= 3) {
|
|
49
|
+
const [calendar, authored, format] = given;
|
|
50
|
+
return { calendar: calendar ?? undefined, authored, format };
|
|
51
|
+
}
|
|
52
|
+
if (given.length < 2) return { authored: given[0] };
|
|
53
|
+
const [first, second] = given;
|
|
54
|
+
if (first === undefined || first === null) return { authored: second };
|
|
55
|
+
if (typeof first === "number") return { authored: first, format: second };
|
|
56
|
+
if (typeof first === "string" && !namesCalendar(first, dates)) {
|
|
57
|
+
const parsed = parseNoteDate(first, { ...dates, allowUnknown: false });
|
|
58
|
+
if (parsed.date && !parsed.findings.some((item) => item.severity === "error"))
|
|
59
|
+
return { authored: first, format: second };
|
|
60
|
+
}
|
|
61
|
+
return { calendar: first, authored: second };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Whether a string names a calendar or one of its eras.
|
|
66
|
+
*
|
|
67
|
+
* @param {string} value - The string.
|
|
68
|
+
* @param {object} [dates] - The reckoning context.
|
|
69
|
+
* @returns {boolean} Whether it resolves to one.
|
|
70
|
+
*/
|
|
71
|
+
function namesCalendar(value, dates) {
|
|
72
|
+
try {
|
|
73
|
+
return calendarEras(value, dates).length > 0;
|
|
74
|
+
} catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
36
79
|
/**
|
|
37
80
|
* Every helper an expression may call, with the parameters it takes.
|
|
38
81
|
*
|
|
@@ -135,30 +178,42 @@ const HELPERS = Object.freeze([
|
|
|
135
178
|
}),
|
|
136
179
|
Object.freeze({
|
|
137
180
|
name: "dateformat",
|
|
138
|
-
params: 'calendar date ["format"]',
|
|
181
|
+
params: '[calendar] date ["format"]',
|
|
139
182
|
summary:
|
|
140
|
-
"A date written in a calendar. The calendar is an Address or its shortcode
|
|
141
|
-
"is the
|
|
183
|
+
"A date written in a calendar. The calendar is an Address or its shortcode; left " +
|
|
184
|
+
"out, it is the note's own calendar — its `data.calendar`, else its culture's, " +
|
|
185
|
+
"else for a place its parents', else the configured `defaultCalendar` — and a " +
|
|
186
|
+
"note with none prints the date as written. The date is the value a note " +
|
|
187
|
+
"carries, and the optional last argument names an output pattern.",
|
|
142
188
|
make:
|
|
143
|
-
({ dates }) =>
|
|
144
|
-
(
|
|
189
|
+
({ dates, fm }) =>
|
|
190
|
+
(...args) => {
|
|
191
|
+
const { calendar, authored, format } = dateformatArguments(
|
|
192
|
+
args.slice(0, -1),
|
|
193
|
+
dates,
|
|
194
|
+
);
|
|
145
195
|
if (
|
|
146
|
-
!(
|
|
147
|
-
|
|
196
|
+
!(
|
|
197
|
+
calendar === undefined ||
|
|
198
|
+
typeof calendar === "string" ||
|
|
199
|
+
isAddressTuple(calendar)
|
|
200
|
+
) ||
|
|
201
|
+
!["string", "number"].includes(typeof authored) ||
|
|
202
|
+
!(format === undefined || typeof format === "string")
|
|
148
203
|
)
|
|
149
|
-
throw new TypeError("dateformat needs a
|
|
204
|
+
throw new TypeError("dateformat needs a date, and takes a calendar Address");
|
|
150
205
|
const parsed = parseNoteDate(authored, { ...dates, allowUnknown: false });
|
|
151
206
|
const error = parsed.findings.find((item) => item.severity === "error");
|
|
152
207
|
if (error || !parsed.date)
|
|
153
208
|
throw new RangeError(error?.message ?? "date does not resolve");
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
isAddressTuple(calendar) ? renderAddress(calendar)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
);
|
|
209
|
+
const reference =
|
|
210
|
+
calendar === undefined ? noteCalendar(fm, dates)
|
|
211
|
+
: isAddressTuple(calendar) ? renderAddress(calendar)
|
|
212
|
+
: calendar;
|
|
213
|
+
if (reference === undefined) return printEventDate(authored, parsed.date, dates);
|
|
214
|
+
const printable = formatDateInCalendar(parsed.date, reference, dates, format);
|
|
160
215
|
if (!printable)
|
|
161
|
-
throw new RangeError(`date cannot be printed in calendar ${
|
|
216
|
+
throw new RangeError(`date cannot be printed in calendar ${reference}`);
|
|
162
217
|
return printable.prose ?? printable.text;
|
|
163
218
|
},
|
|
164
219
|
}),
|