@heroiclands/package-build 22.16.0 → 22.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,70 +1,64 @@
1
- /*
2
- * This file is part of the Song of Heroic Lands (SoHL) system for Foundry VTT.
3
- * Copyright (c) 2024-2026 Tom Rodriguez ("Toasty") — <toasty@heroiclands.org>
4
- *
5
- * This work is licensed under the GNU General Public License v3.0 (GPLv3).
6
- * You may copy, modify, and distribute it under the terms of that license.
7
- *
8
- * SPDX-License-Identifier: GPL-3.0-or-later
9
- */
1
+ /* SPDX-License-Identifier: GPL-3.0-or-later */
10
2
 
11
3
  import { positionOfFrontmatterPath } from "./diagnostics.mjs";
12
- import { canonicalDayOffset, daysInMonth } from "./calendars.mjs";
13
- import { DATEFROM_PATTERN, parseNoteDate } from "./note-dates.mjs";
14
- import { eraNames } from "./calendar-human.mjs";
15
- import { addressSuffixes, renderAddress } from "./address-render.mjs";
4
+ import {
5
+ canonicalDateFromOffset,
6
+ canonicalDayOffset,
7
+ canonicalYear,
8
+ parseCanonicalDate,
9
+ } from "./calendars.mjs";
10
+ import { renderAddress } from "./address-render.mjs";
16
11
 
17
- /**
18
- * Resolve every declared reckoning marker against its calendar and era start.
19
- * The marker names one era, while the calendar supplies the month layout.
20
- *
21
- * @param {{notes?: readonly object[]}} index - The corpus link index.
22
- * @param {number} daysPerYear - The world's year length.
23
- * @returns {{eras: Map<string, object>, markers: Map<string, object>, findings: object[]}} Resolved eras, markers, and errors.
24
- */
12
+ /** Resolve calendar eras on the canonical day axis. */
25
13
  export function resolveReckoningMarkers(index, daysPerYear) {
26
- const declared = new Map();
27
- const qualifiers = new Map();
28
- const markerKeys = new Map();
29
14
  const eras = new Map();
30
15
  const markers = new Map();
31
16
  const findings = [];
32
- const failed = new Set();
33
- const visiting = [];
17
+ const qualifiers = new Map();
18
+ const markerOwners = new Map();
19
+ const calendarRows = [];
34
20
 
35
- const location = (row, key) => ({
36
- ...(row.note.file === undefined ? {} : { file: row.note.file }),
37
- ...(row.note.raw === undefined ?
21
+ const location = (note, position, key) => ({
22
+ ...(note.file === undefined ? {} : { file: note.file }),
23
+ ...(note.raw === undefined ?
38
24
  {}
39
- : positionOfFrontmatterPath(row.note.raw, ["data", "eras", row.position, key])),
25
+ : positionOfFrontmatterPath(note.raw, ["data", "eras", position, key])),
40
26
  });
41
- const finding = (row, key, message) =>
42
- findings.push({
43
- ...location(row, key),
44
- severity: "error",
45
- message,
46
- });
47
- const alias = (qualifier, key) => {
48
- if (qualifiers.has(qualifier) && qualifiers.get(qualifier) !== key)
49
- qualifiers.set(qualifier, null);
50
- else qualifiers.set(qualifier, key);
51
- };
27
+ const error = (note, position, key, message) =>
28
+ findings.push({ ...location(note, position, key), severity: "error", message });
52
29
 
53
30
  for (const note of index?.notes ?? []) {
54
31
  const fm = note?.fm ?? note?.frontmatter ?? note;
55
32
  if (fm?.type !== "lore" || fm?.subType !== "calendar") continue;
56
- const rows = fm.data?.eras;
33
+ const data = fm.data ?? {};
34
+ const rows = data.eras;
57
35
  if (!Array.isArray(rows)) continue;
58
- rows.forEach((era, position) => {
59
- if (
60
- !era ||
61
- typeof era.shortcode !== "string" ||
62
- !era.shortcode ||
63
- typeof fm.shortcode !== "string" ||
64
- !fm.shortcode
65
- )
66
- return;
67
- const pkg = fm.package ?? note.package ?? index?.contentPackage;
36
+ if (!Number.isSafeInteger(daysPerYear) || daysPerYear < 1) continue;
37
+ const epochText = String(data.epoch ?? "");
38
+ const epoch = parseCanonicalDate(epochText, daysPerYear);
39
+ if (!epoch || epoch.year === 0 || epoch.seconds !== undefined) {
40
+ findings.push({
41
+ ...(note.file === undefined ? {} : { file: note.file }),
42
+ ...(note.raw === undefined ?
43
+ {}
44
+ : positionOfFrontmatterPath(note.raw, ["data", "epoch"])),
45
+ severity: "error",
46
+ message:
47
+ "data.epoch must be a canonical <year>.<day> anchoring calendar year 1, day 1",
48
+ });
49
+ continue;
50
+ }
51
+ const epochOffset = canonicalDayOffset(
52
+ canonicalYear(epoch.year),
53
+ epoch.day,
54
+ 1,
55
+ daysPerYear,
56
+ );
57
+ const pkg = fm.package ?? note.package ?? index?.contentPackage;
58
+ const declared = [];
59
+ for (const [position, era] of rows.entries()) {
60
+ if (!era || typeof era.shortcode !== "string" || !era.shortcode || !fm.shortcode)
61
+ continue;
68
62
  const short = `${fm.shortcode}.${era.shortcode}`;
69
63
  const key =
70
64
  pkg ?
@@ -73,235 +67,139 @@ export function resolveReckoningMarkers(index, daysPerYear) {
73
67
  const row = {
74
68
  key,
75
69
  era: short,
76
- calendar: fm.data,
77
- marker: era.marker,
70
+ calendar: data,
78
71
  calendarShortcode: fm.shortcode,
72
+ note,
73
+ position,
74
+ start: era.start,
79
75
  name: era.name,
80
76
  abbreviation: era.abbreviation,
77
+ marker: era.marker,
81
78
  label: era.label,
82
- start: era.start,
83
- end: era.end,
84
- note,
85
- position,
86
79
  };
87
- if (declared.has(key)) {
88
- return;
80
+ declared.push(row);
81
+ const aliases = [short, `lore-${short}`, `note-lore-${short}`];
82
+ for (const alias of aliases) {
83
+ if (qualifiers.has(alias) && qualifiers.get(alias) !== key)
84
+ qualifiers.set(alias, null);
85
+ else qualifiers.set(alias, key);
89
86
  }
90
- declared.set(key, row);
91
- alias(short, key);
92
- if (pkg) {
93
- alias(
94
- renderAddress({ package: pkg, system: "note", type: "lore", shortcode: short }),
95
- key,
96
- );
97
- alias(`note-lore-${short}`, key);
98
- alias(`lore-${short}`, key);
87
+ if (era.marker !== undefined) {
88
+ if (typeof era.marker !== "string" || !/^[A-Z][A-Z0-9]*$/.test(era.marker))
89
+ error(
90
+ note,
91
+ position,
92
+ "marker",
93
+ "an era marker needs uppercase letters and digits",
94
+ );
95
+ else if (markerOwners.has(era.marker))
96
+ error(
97
+ note,
98
+ position,
99
+ "marker",
100
+ `reckoning marker ${era.marker} is declared more than once`,
101
+ );
102
+ else markerOwners.set(era.marker, key);
99
103
  }
100
- if (era.marker === undefined) return;
101
- if (typeof era.marker !== "string" || !/^[A-Z][A-Z0-9]*$/.test(era.marker)) {
102
- finding(
103
- row,
104
- "marker",
105
- "an era marker is uppercase letters and digits, starting with a letter",
104
+ if (era.end !== undefined)
105
+ error(
106
+ note,
107
+ position,
108
+ "end",
109
+ "an era ends when the next calendar year era begins; omit end",
106
110
  );
107
- return;
108
- }
109
- if (markerKeys.has(era.marker)) {
110
- finding(row, "marker", `reckoning marker ${era.marker} is declared more than once`);
111
- return;
112
- }
113
- markerKeys.set(era.marker, key);
114
- });
111
+ }
112
+ calendarRows.push({ note, declared, epochOffset });
115
113
  }
116
114
 
117
- for (const [qualifier, key] of qualifiers)
118
- if (key === null) eras.set(qualifier, { ambiguous: true });
119
-
120
- function resolve(key) {
121
- if (key === null || !declared.has(key) || failed.has(key)) return null;
122
- const row = declared.get(key);
123
- if (eras.has(key)) return eras.get(key);
124
- if (visiting.includes(key)) {
125
- const members = [...visiting.slice(visiting.indexOf(key)), key].map(
126
- (member) => declared.get(member).era,
115
+ for (const { note, declared, epochOffset } of calendarRows) {
116
+ const nullRows = declared.filter((row) => row.start === null);
117
+ const firstRows = declared.filter((row) => row.start === 1);
118
+ if (nullRows.length !== 1)
119
+ error(
120
+ note,
121
+ nullRows[0]?.position ?? 0,
122
+ "start",
123
+ "a calendar needs exactly one start: null era before year 1",
127
124
  );
128
- finding(row, "start", `calendar era cycle includes ${members.join(" → ")}`);
129
- for (const member of visiting.slice(visiting.indexOf(key))) failed.add(member);
130
- return null;
131
- }
132
- visiting.push(key);
133
- if (row.start === undefined || row.start === null) {
134
- finding(row, "start", `calendar era ${row.era} needs a start`);
135
- failed.add(key);
136
- }
137
- const source = typeof row.start === "string" ? row.start.trim() : "";
138
- const marker = /^([A-Z][A-Z0-9]*)\(/.exec(source)?.[1];
139
- const qualifier = /\s+([^\s]+\.[^\s]+)$/.exec(source)?.[1];
140
- const conversion = DATEFROM_PATTERN.exec(source);
141
- const convertedRef = conversion?.[1];
142
- const convertedDate = conversion?.[2];
143
- const convertedRows =
144
- convertedRef ?
145
- [...declared.values()].filter((candidate) => {
146
- const fm = candidate.note.fm ?? candidate.note.frontmatter ?? candidate.note;
147
- const pkg = fm.package ?? candidate.note.package ?? index?.contentPackage;
148
- if (!pkg) return convertedRef === candidate.calendarShortcode;
149
- return addressSuffixes({
150
- package: pkg,
151
- system: "note",
152
- type: "lore",
153
- shortcode: candidate.calendarShortcode,
154
- }).includes(convertedRef);
155
- })
156
- : [];
157
- const convertedTargets = convertedRows.filter((candidate) =>
158
- eraNames(candidate).some((name) =>
159
- convertedDate?.toLowerCase().endsWith(` ${name.toLowerCase()}`),
160
- ),
161
- );
162
- if (convertedTargets.length === 0 && convertedRows.length === 1)
163
- convertedTargets.push(convertedRows[0]);
164
- const dependency =
165
- marker ? markerKeys.get(marker)
166
- : qualifier ? qualifiers.get(qualifier)
167
- : convertedTargets.length === 1 ? convertedTargets[0].key
168
- : null;
169
- if (dependency && !failed.has(key)) resolve(dependency);
170
- if (!failed.has(key)) {
171
- const parsed = parseNoteDate(row.start, {
172
- markers,
173
- eras,
174
- daysPerYear,
175
- field: "data.eras.start",
176
- allowUnknown: false,
177
- ...location(row, "start"),
178
- raw: row.note.raw,
179
- keyPath: ["data", "eras", row.position, "start"],
180
- });
181
- findings.push(...parsed.findings);
182
- if (
183
- Number.isSafeInteger(parsed.date?.canonicalYear) &&
184
- parsed.findings.every((item) => item.severity !== "error")
185
- ) {
186
- const entry = {
187
- era: row.era,
188
- qualifier: row.key,
189
- marker: row.marker,
190
- firstEra: row.position === 0,
191
- calendar: row.calendar,
192
- calendarShortcode: row.calendarShortcode,
193
- name: row.name,
194
- abbreviation: row.abbreviation,
195
- label: row.label,
196
- epochYear: parsed.date.canonicalYear,
197
- epochDay: parsed.date.canonicalDay ?? 1,
198
- };
199
- if (Number.isSafeInteger(daysPerYear) && daysPerYear > 0)
200
- entry.startOffset = canonicalDayOffset(
201
- entry.epochYear,
202
- entry.epochDay,
203
- 1,
204
- daysPerYear,
205
- );
206
- eras.set(key, entry);
207
- for (const [name, owner] of qualifiers) if (owner === key) eras.set(name, entry);
208
- if (row.marker && markerKeys.get(row.marker) === key)
209
- markers.set(row.marker, entry);
210
- } else failed.add(key);
211
- }
212
- visiting.pop();
213
- return eras.get(key) ?? null;
214
- }
215
- for (const key of declared.keys()) resolve(key);
216
- for (const row of declared.values()) {
217
- const entry = eras.get(row.key);
218
- if (!entry || row.end === undefined || row.end === null) continue;
219
- const parsed = parseNoteDate(row.end, {
220
- markers,
221
- eras,
222
- daysPerYear,
223
- field: "data.eras.end",
224
- allowUnknown: false,
225
- file: row.note.file,
226
- raw: row.note.raw,
227
- keyPath: ["data", "eras", row.position, "end"],
228
- });
229
- findings.push(...parsed.findings);
230
- if (!Number.isSafeInteger(parsed.date?.canonicalYear)) continue;
231
- if (!Number.isSafeInteger(daysPerYear) || daysPerYear < 1) {
232
- finding(
233
- row,
234
- "end",
235
- `calendar era ${row.era} needs the world's year length to bound its end`,
125
+ if (firstRows.length !== 1)
126
+ error(
127
+ note,
128
+ firstRows[0]?.position ?? 0,
129
+ "start",
130
+ "a calendar needs exactly one era with start: 1",
236
131
  );
237
- continue;
238
- }
239
- const firstEndDay = canonicalDayOffset(
240
- parsed.date.canonicalYear,
241
- parsed.date.canonicalDay ?? 1,
242
- 1,
243
- daysPerYear,
244
- );
245
- const extraDays =
246
- parsed.date.precision === "year" ? daysPerYear - 1
247
- : parsed.date.precision === "month" ?
248
- (daysInMonth(
249
- markers.get(parsed.date.marker)?.calendar ??
250
- eras.get(parsed.date.qualifier)?.calendar,
251
- parsed.date.month,
252
- ) ?? 1) - 1
253
- : 0;
254
- const endOffset = firstEndDay + extraDays;
255
- const startOffset = canonicalDayOffset(entry.epochYear, entry.epochDay, 1, daysPerYear);
256
- if (endOffset < startOffset) {
257
- finding(row, "end", `calendar era ${row.era} ends before its start`);
258
- continue;
259
- }
260
- entry.endOffset = endOffset;
261
- }
262
- const calendars = new Map();
263
- for (const row of declared.values()) {
264
- const rows = calendars.get(row.note) ?? [];
265
- rows.push(row);
266
- calendars.set(row.note, rows);
267
- }
268
- for (const rows of calendars.values()) {
269
- for (let position = 0; position < rows.length; position++) {
270
- const row = rows[position];
271
- const entry = eras.get(row.key);
272
- if (!entry || !Number.isSafeInteger(entry.startOffset)) continue;
273
- entry.firstEra = position === 0;
274
- const next = rows[position + 1];
275
- if (!next) continue;
276
- const following = eras.get(next.key);
277
- if (!following || !Number.isSafeInteger(following.startOffset)) continue;
278
- if (following.startOffset <= entry.startOffset) {
279
- finding(
280
- next,
132
+ const byStart = new Map();
133
+ for (const row of declared) {
134
+ if (row.start !== null && (!Number.isSafeInteger(row.start) || row.start < 1)) {
135
+ error(
136
+ note,
137
+ row.position,
281
138
  "start",
282
- `calendar eras ${row.era} and ${next.era} must begin in increasing order`,
139
+ "an era start is null or a positive integer calendar year",
283
140
  );
284
141
  continue;
285
142
  }
286
- if (entry.endOffset !== undefined && entry.endOffset >= following.startOffset) {
287
- finding(next, "start", `calendar eras ${row.era} and ${next.era} overlap`);
143
+ if (byStart.has(row.start)) {
144
+ error(note, row.position, "start", `calendar eras cannot share start ${row.start}`);
145
+ continue;
146
+ }
147
+ byStart.set(row.start, row);
148
+ }
149
+ const ordered = [...byStart.values()].sort((a, b) =>
150
+ a.start === null ? -1
151
+ : b.start === null ? 1
152
+ : a.start - b.start,
153
+ );
154
+ for (const [position, row] of ordered.entries()) {
155
+ const startOffset =
156
+ row.start === null ? epochOffset : epochOffset + (row.start - 1) * daysPerYear;
157
+ if (!Number.isSafeInteger(startOffset)) {
158
+ error(
159
+ note,
160
+ row.position,
161
+ "start",
162
+ "era start lies outside the supported day range",
163
+ );
288
164
  continue;
289
165
  }
290
- if (entry.endOffset === undefined) entry.endOffset = following.startOffset - 1;
166
+ const startDate = canonicalDateFromOffset(startOffset, 1, daysPerYear);
167
+ const next = ordered[position + 1];
168
+ const endOffset = next ? epochOffset + (next.start - 1) * daysPerYear - 1 : undefined;
169
+ const entry = {
170
+ era: row.era,
171
+ qualifier: row.key,
172
+ marker: row.marker,
173
+ firstEra: row.start === null,
174
+ beforeEra: row.start === null,
175
+ startYear: row.start,
176
+ calendar: row.calendar,
177
+ calendarShortcode: row.calendarShortcode,
178
+ name: row.name,
179
+ abbreviation: row.abbreviation,
180
+ label: row.label,
181
+ epochYear: startDate.year,
182
+ epochDay: startDate.day,
183
+ calendarEpochOffset: epochOffset,
184
+ startOffset,
185
+ ...(endOffset === undefined ? {} : { endOffset }),
186
+ };
187
+ eras.set(row.key, entry);
188
+ if (row.marker && markerOwners.get(row.marker) === row.key)
189
+ markers.set(row.marker, entry);
291
190
  }
292
191
  }
192
+ for (const [alias, key] of qualifiers) {
193
+ if (key === null) eras.set(alias, { ambiguous: true });
194
+ else if (eras.has(key)) eras.set(alias, eras.get(key));
195
+ }
293
196
  return { eras, markers, findings };
294
197
  }
295
198
 
296
- /** One resolved date context per corpus index, shared by its note checks. */
199
+ /** One resolved date context per corpus index. */
297
200
  const contexts = new WeakMap();
298
201
 
299
- /**
300
- * Read the world's year length and its era markers from one corpus index.
301
- *
302
- * @param {{notes?: readonly object[]}|undefined} index - The corpus index.
303
- * @returns {{eras: Map<string, object>, markers: Map<string, object>, daysPerYear: number|undefined, findings: object[]}}
304
- */
202
+ /** Read the world's year length and resolve every calendar era in one corpus. */
305
203
  export function reckoningContext(index) {
306
204
  if (!index || typeof index !== "object")
307
205
  return { eras: new Map(), markers: new Map(), daysPerYear: undefined, findings: [] };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heroiclands/package-build",
3
- "version": "22.16.0",
3
+ "version": "22.17.1",
4
4
  "description": "Shared toolchain for building and shipping a HeroicLands Foundry VTT package — content compilation, manifest, localization, staging, bundle, release and deployment.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "type": "module",
@@ -137,10 +137,12 @@
137
137
  "acorn": "^8.18.0",
138
138
  "archiver": "^8.0.0",
139
139
  "classic-level": "^3.0.0",
140
+ "dale-chall": "^2.0.1",
140
141
  "dotenv": "^18.0.0",
141
142
  "eslint": "^10.10.0",
142
143
  "eslint-plugin-yml": "^3.8.1",
143
144
  "fflate": "^0.8.3",
145
+ "flesch": "^2.0.1",
144
146
  "glob": "^13.0.6",
145
147
  "gray-matter": "^4.0.3",
146
148
  "handlebars": "^4.7.9",
@@ -153,6 +155,7 @@
153
155
  "pagefind": "^1.5.2",
154
156
  "prettier": "^3.9.6",
155
157
  "remark-frontmatter": "^5.0.0",
158
+ "remark-gfm": "^4.0.1",
156
159
  "remark-parse": "^11.0.0",
157
160
  "remark-retext": "^6.0.1",
158
161
  "retext-english": "^5.0.0",
@@ -162,6 +165,7 @@
162
165
  "sharp": "^0.35.4",
163
166
  "smol-toml": "^1.8.0",
164
167
  "ssh2-sftp-client": "^12.1.1",
168
+ "syllable": "^5.0.1",
165
169
  "typescript": "^6.0.3",
166
170
  "unidecode": "^1.1.0",
167
171
  "unified": "^11.0.5",
@@ -94,7 +94,8 @@ export const DERIVED_MANIFEST_KEYS: Readonly<Record<string, string>>;
94
94
  *
95
95
  * @typedef {object} PackageBuildConfig
96
96
  * @property {string} rootDir The repository root, from package-build.
97
- * @property {{age: number, threshold: number, minWords: number}} proseLint Optional prose analysis settings.
97
+ * @property {{age: number, threshold: number, minWords: number, rules: string}} proseLint Optional prose lint settings.
98
+ * @property {{minWords: number, bands: Record<string, {min?: number, max?: number}>}} proseScore Optional note score settings.
98
99
  * @property {string} packageKind `systems` or `modules`.
99
100
  * @property {string} packageId The Foundry package id.
100
101
  * @property {string} artifact Derived: `system` or `module`.
@@ -198,12 +199,23 @@ export type PackageBuildConfig = {
198
199
  */
199
200
  rootDir: string;
200
201
  /**
201
- * Optional prose analysis settings.
202
+ * Optional prose lint settings.
202
203
  */
203
204
  proseLint: {
204
205
  age: number;
205
206
  threshold: number;
206
207
  minWords: number;
208
+ rules: string;
209
+ };
210
+ /**
211
+ * Optional note score settings.
212
+ */
213
+ proseScore: {
214
+ minWords: number;
215
+ bands: Record<string, {
216
+ min?: number;
217
+ max?: number;
218
+ }>;
207
219
  };
208
220
  /**
209
221
  * `systems` or `modules`.
@@ -0,0 +1,33 @@
1
+ /** Brackets and braces must close; `[[]` is a literal left bracket. */
2
+ export function calendarFormatSyntaxError(pattern: any): string | null;
3
+ /** Split a Calendaria pattern into tokens and literal text. */
4
+ export function calendarFormatSegments(pattern: any): {
5
+ token: boolean;
6
+ value: any;
7
+ }[];
8
+ /** A standard format must identify one calendar day and be readable without context. */
9
+ export function readableCalendarFormatError(pattern: any): string | null;
10
+ /** Whether a selected pattern prints clock components. */
11
+ export function calendarFormatHasClock(pattern: any): boolean;
12
+ /** Keep the fields named by an authored date's precision. */
13
+ export function calendarPatternSegmentsForPrecision(pattern: any, precision?: string, includeClock?: boolean): {
14
+ token: boolean;
15
+ value: any;
16
+ }[];
17
+ /** Choose an authored named format, with `std` as the preferred default. */
18
+ export function selectCalendarFormat(calendar: any, name: any): {
19
+ name: any;
20
+ pattern: any;
21
+ };
22
+ /** Format calendar date components with Calendaria's documented tokens. */
23
+ export function formatCalendarPattern(pattern: any, parts: any, precision?: string, includeClock?: boolean): string;
24
+ /** Read the invertible date fields of one Calendaria pattern. */
25
+ export function parseCalendarPattern(pattern: any, text: any, calendar: any): {
26
+ hour: number;
27
+ };
28
+ /** Convert a calendar month/day into its one-based day of year. */
29
+ export function calendarOrdinal(calendar: any, month: any, day: any): number;
30
+ /** Calendaria's bare date, time, week, season, and zone tokens. */
31
+ export const CALENDAR_FORMAT_TOKENS: Readonly<Set<string>>;
32
+ /** Calendaria's named fields inside brackets or braces. */
33
+ export const CALENDAR_CUSTOM_TOKENS: Readonly<Set<string>>;
@@ -18,7 +18,7 @@ export function worldInvariants(index?: object): {
18
18
  yearNote: object | null;
19
19
  moonNote: object | null;
20
20
  };
21
- /** Check each authored format slot and every unescaped letter run in it. */
21
+ /** Check each named pattern and the standard pattern's readable fields. */
22
22
  export function checkCalendarDateFormats(note: any): {
23
23
  severity: any;
24
24
  message: any;
@@ -162,8 +162,7 @@ export const CALENDAR_SUBTYPE: "calendar";
162
162
  export const INVARIANT_SUBTYPES: readonly string[];
163
163
  /** Calendaria's display locations that a calendar note can format. */
164
164
  export const CALENDAR_DATE_FORMAT_KEYS: readonly string[];
165
- /** Bare date tokens Calendaria substitutes inside authored format strings. */
166
- export const CALENDAR_FORMAT_TOKENS: Readonly<Set<string>>;
165
+ export { CALENDAR_FORMAT_TOKENS };
167
166
  /**
168
167
  * The `data:` keys a calendar note may write — the closed list, in authored
169
168
  * order.
@@ -185,3 +184,4 @@ export const CALENDAR_FIELDS: readonly object[];
185
184
  * @type {readonly object[]}
186
185
  */
187
186
  export const INVARIANT_FIELDS: readonly object[];
187
+ import { CALENDAR_FORMAT_TOKENS } from "./calendar-format.mjs";
@@ -1,4 +1,4 @@
1
1
  /** Convert a day in an addressed calendar to its canonical spelling. */
2
2
  export function dateFromCalendar(reference: any, value: any, context: any): string;
3
3
  /** Convert a canonical day to the date in the covering era of a calendar. */
4
- export function dateToCalendar(reference: any, value: any, context: any): any;
4
+ export function dateToCalendar(reference: any, value: any, context: any, formatName: any): any;
@@ -60,7 +60,7 @@ export function eraCovering(date: any, eraRows: any, daysPerYear: any): any;
60
60
  /** Resolve a calendar or one of its eras from an Address or shortcode. */
61
61
  export function calendarEras(reference: any, context: any): any;
62
62
  /** Print a resolved date using the era active in one addressed calendar. */
63
- export function formatDateInCalendar(date: any, reference: any, context: any): {
63
+ export function formatDateInCalendar(date: any, reference: any, context: any, formatName: any): {
64
64
  era: null;
65
65
  year: number;
66
66
  text: any;
@@ -76,7 +76,7 @@ export function formatDateInCalendar(date: any, reference: any, context: any): {
76
76
  prose: string | null;
77
77
  } | null;
78
78
  /** Print a resolved date in one era, retaining its authored precision. */
79
- export function formatNoteDate(date: any, era: any, daysPerYear: any): {
79
+ export function formatNoteDate(date: any, era: any, daysPerYear: any, formatName: any): {
80
80
  era: null;
81
81
  year: number;
82
82
  text: any;
@@ -1,11 +1,7 @@
1
1
  /** Files in a content tree, excluding configured directory names. */
2
2
  export function proseFiles(root: any, skipDirectories?: any[]): any[];
3
3
  /** Source-aligned findings for one Markdown note. */
4
- export function analyzeProse(file: any, source: any, { age, threshold, minWords }?: {
5
- age?: number | undefined;
6
- threshold?: number | undefined;
7
- minWords?: number | undefined;
8
- }): Promise<{
4
+ export function analyzeProse(file: any, source: any, options?: {}): Promise<{
9
5
  file: any;
10
6
  line: any;
11
7
  column: any;
@@ -20,3 +16,13 @@ export function lintProse(root: any, options: any, skipDirectories?: any[]): Pro
20
16
  severity: string;
21
17
  message: string;
22
18
  }[]>;
19
+ /** Score the complete prose paragraphs in one note. */
20
+ export function scoreProse(file: any, source: any, { minWords, bands }?: {
21
+ minWords?: number | undefined;
22
+ bands?: {} | undefined;
23
+ }): Promise<any>;
24
+ /** Score a note or content tree and pool counts for its aggregate. */
25
+ export function scoreProseTree(root: any, options: any, skipDirectories?: any[]): Promise<{
26
+ notes: any[];
27
+ summary: any;
28
+ }>;