@heroiclands/package-build 24.0.1 → 24.0.3
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 +32 -0
- package/assets/preview/gitea.ini +1 -1
- package/assets/styles/content-base.css +33 -0
- package/bin/content-commands.mjs +17 -17
- package/content-config.mjs +1 -52
- package/docs/api.md +20 -13
- package/docs/authoring/links-and-markup.md +165 -17
- package/docs/commands.md +20 -20
- package/docs/configuration.md +29 -69
- package/docs/content-format.md +4 -2
- package/docs/guides/site.md +3 -1
- package/docs/guides/writing-in-invented-scripts.md +68 -6
- package/docs/reference/format-details.md +160 -118
- package/docs/reference/note-types.md +49 -29
- package/docs/source-preview.md +2 -2
- package/engine/content-blocks.mjs +6 -2
- package/engine/content-charset.mjs +1 -0
- package/engine/content-format.yaml +2 -0
- package/engine/content-index.mjs +5 -1
- package/engine/content-render.mjs +2 -1
- package/engine/content-scripts.mjs +268 -21
- package/engine/content-scroll.mjs +389 -0
- package/engine/dictionary-layout.mjs +16 -3
- package/engine/font-outlines.mjs +394 -0
- package/engine/foreign-catalog.mjs +11 -122
- package/engine/language-data.mjs +154 -63
- package/engine/language-rows.mjs +35 -9
- package/engine/language-terms.mjs +39 -9
- package/engine/map-lexicon.mjs +31 -6
- package/engine/note-vocabulary.mjs +58 -6
- package/engine/pdf-build.mjs +9 -178
- package/engine/pdf-fonts.mjs +1 -1
- package/engine/pdf-render.mjs +52 -11
- package/engine/run-rows.mjs +45 -3
- package/engine/script-direction.mjs +67 -0
- package/engine/script-emphasis-terms.mjs +11 -3
- package/engine/script-font-delivery.mjs +42 -9
- package/engine/script-fonts.mjs +7 -0
- package/engine/site-reach.mjs +23 -0
- package/engine/site-render.mjs +18 -3
- package/engine/verse-metre.mjs +1 -0
- package/engine/written-in.mjs +208 -0
- package/package.json +2 -1
- package/site-theme/static/css/style.css +7 -0
- package/types/content-config.d.mts +1 -19
- package/types/engine/content-scripts.d.mts +31 -6
- package/types/engine/content-scroll.d.mts +179 -0
- package/types/engine/dictionary-layout.d.mts +5 -0
- package/types/engine/font-outlines.d.mts +67 -0
- package/types/engine/foreign-catalog.d.mts +0 -38
- package/types/engine/language-data.d.mts +13 -0
- package/types/engine/language-rows.d.mts +5 -4
- package/types/engine/language-terms.d.mts +7 -0
- package/types/engine/map-lexicon.d.mts +4 -3
- package/types/engine/pdf-build.d.mts +5 -27
- package/types/engine/pdf-fonts.d.mts +10 -0
- package/types/engine/run-rows.d.mts +28 -6
- package/types/engine/script-direction.d.mts +10 -0
- package/types/engine/script-emphasis-terms.d.mts +10 -3
- package/types/engine/script-font-delivery.d.mts +5 -3
- package/types/engine/script-fonts.d.mts +9 -0
- package/types/engine/site-reach.d.mts +11 -0
- package/types/engine/written-in.d.mts +76 -0
- package/engine/asset-replacement.mjs +0 -93
- package/types/engine/asset-replacement.d.mts +0 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @heroiclands/package-build
|
|
2
2
|
|
|
3
|
+
## 24.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
**Sites**
|
|
8
|
+
|
|
9
|
+
- Glossary and dictionary entries link only to pages a reader can reach, and such links never make a page reachable.
|
|
10
|
+
|
|
11
|
+
**Configuration**
|
|
12
|
+
|
|
13
|
+
- A package can no longer declare a dependency whose images replace its own: `assetReplacement` and `assetArchive` are refused as unknown options.
|
|
14
|
+
|
|
15
|
+
**Languages and scripts**
|
|
16
|
+
|
|
17
|
+
- A sound mark can say `apart`, beside `stress` and `length`: the mark sets a vowel to be said apart from its neighbour, as a diaeresis does.
|
|
18
|
+
- A skeleton row can state `third`, the third consonants it holds for, beside `second`, so a rule that depends on the third consonant can be written.
|
|
19
|
+
- Text in the Veldikko script draws no charset warnings.
|
|
20
|
+
|
|
21
|
+
## 24.0.2
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
**Languages**
|
|
26
|
+
|
|
27
|
+
- A language whose stress always falls on the first syllable says so with `stress: { two: first, longer: first }`, and its verse is scanned that way.
|
|
28
|
+
- A reference note can state a setting's spelling guide as data: its letters and marks, with an `ipa` sound for each letter and final, and the languages that write each letter.
|
|
29
|
+
|
|
30
|
+
**Scripts**
|
|
31
|
+
|
|
32
|
+
- A `scroll` fence sets text in a script written in columns as a handscroll: columns read right to left, scrolling sideways on screen and continuing on panels in the book.
|
|
33
|
+
- A language note names the script it is written in with `data.writtenIn: { map, font }`, so text marked with the language alone is set in that script; a run's own `map=` or `font=` still chooses another.
|
|
34
|
+
|
|
3
35
|
## 24.0.1
|
|
4
36
|
|
|
5
37
|
### Patch Changes
|
package/assets/preview/gitea.ini
CHANGED
|
@@ -9,7 +9,7 @@ RENDER_CONTENT_MODE = sanitized
|
|
|
9
9
|
[markup.sanitizer.markdown.previewDiv]
|
|
10
10
|
ELEMENT = div
|
|
11
11
|
ALLOW_ATTR = class
|
|
12
|
-
REGEXP = ^(hl-preview(?:-[a-z-]+)?|content-figure(?:-[a-z-]+)?|verse(?:-[a-z-]+)?|border)( (hl-preview(?:-[a-z-]+)?|content-figure(?:-[a-z-]+)?|verse(?:-[a-z-]+)?|border))*$
|
|
12
|
+
REGEXP = ^(hl-preview(?:-[a-z-]+)?|content-figure(?:-[a-z-]+)?|verse(?:-[a-z-]+)?|scroll|border)( (hl-preview(?:-[a-z-]+)?|content-figure(?:-[a-z-]+)?|verse(?:-[a-z-]+)?|scroll|border))*$
|
|
13
13
|
|
|
14
14
|
[markup.sanitizer.markdown.previewSpan]
|
|
15
15
|
ELEMENT = span
|
|
@@ -285,6 +285,39 @@
|
|
|
285
285
|
text-align: start;
|
|
286
286
|
}
|
|
287
287
|
|
|
288
|
+
/*
|
|
289
|
+
* A scroll: a script written in columns, top to bottom, read from the right,
|
|
290
|
+
* as a handscroll unrolls. Each paragraph starts a fresh column, flush at the
|
|
291
|
+
* top. The line height sets the column pitch: one em for the character and
|
|
292
|
+
* half an em between columns. `--scroll-rows` sets a column's length in
|
|
293
|
+
* characters; without it a column runs as long as its paragraph.
|
|
294
|
+
* `--scroll-cols` sets the panel's width in columns; without it the panel is
|
|
295
|
+
* as wide as its text. A panel wider than its container scrolls sideways,
|
|
296
|
+
* starting at the right.
|
|
297
|
+
*/
|
|
298
|
+
:is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .scroll {
|
|
299
|
+
writing-mode: vertical-rl;
|
|
300
|
+
line-height: 1.5;
|
|
301
|
+
inline-size: max-content;
|
|
302
|
+
max-block-size: 100%;
|
|
303
|
+
overflow-x: auto;
|
|
304
|
+
overflow-y: hidden;
|
|
305
|
+
margin: 1rem 0;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
:is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .scroll[data-rows] {
|
|
309
|
+
inline-size: calc(var(--scroll-rows) * 1em);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
:is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .scroll[data-cols] {
|
|
313
|
+
block-size: calc(var(--scroll-cols) * 1.5em);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
:is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .scroll p {
|
|
317
|
+
margin: 0;
|
|
318
|
+
text-indent: 0;
|
|
319
|
+
}
|
|
320
|
+
|
|
288
321
|
/*
|
|
289
322
|
* Emphasis in a script follows the script's convention, never a weight or a
|
|
290
323
|
* slant the face does not have: the element keeps the face's Regular, and its
|
package/bin/content-commands.mjs
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* npx package-build map [--tree] [--from <shortcode>] [--chart <shortcode>] [--travel] [--out <dir>]
|
|
32
32
|
* npx package-build reachability <dir> [file] [--index <shortcode>]
|
|
33
33
|
* npx package-build transliterate <map> [--lang <language>] [--font <slug>] [--hex] [text..]
|
|
34
|
-
* npx package-build lexicon <language> --map <map> [--font <slug>] [--derived] [--json]
|
|
34
|
+
* npx package-build lexicon <language> [--map <map>] [--font <slug>] [--derived] [--json]
|
|
35
35
|
* npx package-build addresses diff --from <zip|dir> [--strict]
|
|
36
36
|
* npx package-build npc new (--spec <json> | --specfile <path>) [--seed <text>] [--out <path>]
|
|
37
37
|
*
|
|
@@ -2472,7 +2472,8 @@ function transliterateCommand() {
|
|
|
2472
2472
|
})
|
|
2473
2473
|
.option("font", {
|
|
2474
2474
|
type: "string",
|
|
2475
|
-
describe:
|
|
2475
|
+
describe:
|
|
2476
|
+
"The face; the language's `data.writtenIn` face where the map is drawn in it, and required when neither it nor the map gives one",
|
|
2476
2477
|
})
|
|
2477
2478
|
.option("hex", {
|
|
2478
2479
|
type: "boolean",
|
|
@@ -2518,7 +2519,7 @@ function transliterateCommand() {
|
|
|
2518
2519
|
}
|
|
2519
2520
|
|
|
2520
2521
|
/**
|
|
2521
|
-
* `package-build lexicon <language> --map <map
|
|
2522
|
+
* `package-build lexicon <language> [--map <map>]` — every word of a language's
|
|
2522
2523
|
* lexicon with its native form under a map, as the build writes it; with
|
|
2523
2524
|
* `--derived`, the forms its rules derive follow, each naming its word in a
|
|
2524
2525
|
* sixth column. Under a logographic map the third column says where a
|
|
@@ -2540,12 +2541,13 @@ function lexiconCommand() {
|
|
|
2540
2541
|
})
|
|
2541
2542
|
.option("map", {
|
|
2542
2543
|
type: "string",
|
|
2543
|
-
|
|
2544
|
-
|
|
2544
|
+
describe:
|
|
2545
|
+
"The `data.map.name` of a mapping note; the language's `data.writtenIn` map where left out",
|
|
2545
2546
|
})
|
|
2546
2547
|
.option("font", {
|
|
2547
2548
|
type: "string",
|
|
2548
|
-
describe:
|
|
2549
|
+
describe:
|
|
2550
|
+
"The face; the language's `data.writtenIn` face where the map is drawn in it, and required when neither it nor the map gives one",
|
|
2549
2551
|
})
|
|
2550
2552
|
.option("derived", {
|
|
2551
2553
|
type: "boolean",
|
|
@@ -2567,7 +2569,7 @@ function lexiconCommand() {
|
|
|
2567
2569
|
}
|
|
2568
2570
|
const listed = lexiconEntries(read.ctx, {
|
|
2569
2571
|
lang: String(argv.language),
|
|
2570
|
-
map: String(argv.map),
|
|
2572
|
+
map: argv.map === undefined ? undefined : String(argv.map),
|
|
2571
2573
|
font: argv.font,
|
|
2572
2574
|
derived: Boolean(argv.derived),
|
|
2573
2575
|
});
|
|
@@ -2813,18 +2815,16 @@ async function fetchFromLocalArtifact(config, argv) {
|
|
|
2813
2815
|
|
|
2814
2816
|
/**
|
|
2815
2817
|
* `deps fetch` — fill the caches this build resolves other packages through:
|
|
2816
|
-
* the **content index** of every declared dependency, the **item catalogue
|
|
2817
|
-
*
|
|
2818
|
-
* `assetArchive: true`, and the **site navigation** heroiclands.org
|
|
2818
|
+
* the **content index** of every declared dependency, the **item catalogue**
|
|
2819
|
+
* of those additionally declaring `itemCatalog: true`, and the **site navigation** heroiclands.org
|
|
2819
2820
|
* publishes, which the site build writes its menu from.
|
|
2820
2821
|
*
|
|
2821
2822
|
* The dependency sets differ deliberately. Citing another package's
|
|
2822
|
-
* *addresses
|
|
2823
|
-
*
|
|
2823
|
+
* *addresses* and embedding its *items* are separate edges, and a package may
|
|
2824
|
+
* declare either without the other —
|
|
2824
2825
|
* `harn-ensemble` cites no foreign address and embeds 324,016 item
|
|
2825
2826
|
* references. The navigation is fetched for every package, because every
|
|
2826
|
-
* package publishes a site.
|
|
2827
|
-
* and `assetArchive: true` is fetched once.
|
|
2827
|
+
* package publishes a site.
|
|
2828
2828
|
*
|
|
2829
2829
|
* Its own command rather than a step of `package compile` or `site`, so that
|
|
2830
2830
|
* neither reaches the network. A build that downloads silently is not
|
|
@@ -2885,7 +2885,7 @@ function depsCommand() {
|
|
|
2885
2885
|
const indexes = await fetchAllMetadata(config);
|
|
2886
2886
|
if (indexes) log.info(`Fetched ${indexes} dependency content index(es).`);
|
|
2887
2887
|
const count = await fetchAllCatalogs(config);
|
|
2888
|
-
if (count) log.info(`Fetched ${count} dependency catalogue(s)
|
|
2888
|
+
if (count) log.info(`Fetched ${count} dependency catalogue(s).`);
|
|
2889
2889
|
if (!indexes && !count) {
|
|
2890
2890
|
// Distinguished from a package declaring nothing at all: a
|
|
2891
2891
|
// relationship may still be declared, just narrowed to the
|
|
@@ -2897,8 +2897,8 @@ function depsCommand() {
|
|
|
2897
2897
|
);
|
|
2898
2898
|
log.info(
|
|
2899
2899
|
declared ?
|
|
2900
|
-
"No declared dependency needs a fetched content index
|
|
2901
|
-
"catalogue
|
|
2900
|
+
"No declared dependency needs a fetched content index or item " +
|
|
2901
|
+
"catalogue."
|
|
2902
2902
|
: "This package declares no dependencies.",
|
|
2903
2903
|
);
|
|
2904
2904
|
}
|
package/content-config.mjs
CHANGED
|
@@ -350,8 +350,7 @@ export function publishesContentPages(config) {
|
|
|
350
350
|
* @property {string} [stage] Compiled LevelDB packs.
|
|
351
351
|
* @property {string} [unpack] Where `unpack` extracts JSON back to.
|
|
352
352
|
* @property {string} [foreignCache] Where a dependency declaring
|
|
353
|
-
* `itemCatalog: true`
|
|
354
|
-
* `assetArchive: true` is unpacked.
|
|
353
|
+
* `itemCatalog: true` is unpacked.
|
|
355
354
|
* Inbound, and fetched rather than
|
|
356
355
|
* committed.
|
|
357
356
|
* @property {string} [metadataCache] Where a dependency's published content
|
|
@@ -474,10 +473,6 @@ export function publishesContentPages(config) {
|
|
|
474
473
|
* its Item packs, so the actors pass can
|
|
475
474
|
* resolve embedded items this repository
|
|
476
475
|
* does not hold. Needs a `manifest`.
|
|
477
|
-
* @property {boolean} [assetArchive] Whether `deps fetch` unpacks this
|
|
478
|
-
* dependency's release archive for its
|
|
479
|
-
* asset bytes alone, building no item
|
|
480
|
-
* catalogue from it. Needs a `manifest`.
|
|
481
476
|
* @property {boolean} [contentIndex] Whether `deps fetch` fetches this
|
|
482
477
|
* dependency's content index. Default
|
|
483
478
|
* `true`. `false` declares the dependency
|
|
@@ -486,13 +481,6 @@ export function publishesContentPages(config) {
|
|
|
486
481
|
* `itemCatalog: true` on the same entry,
|
|
487
482
|
* since a catalogue is fetched from the same
|
|
488
483
|
* index.
|
|
489
|
-
* @property {boolean} [assetReplacement] Whether this dependency's asset
|
|
490
|
-
* tree answers this package's own asset
|
|
491
|
-
* addresses ahead of its local record.
|
|
492
|
-
* Default `false`. Refuses `contentIndex:
|
|
493
|
-
* false` on the same entry, since a
|
|
494
|
-
* replacement with no fetched index to
|
|
495
|
-
* check against resolves nothing.
|
|
496
484
|
*/
|
|
497
485
|
|
|
498
486
|
/**
|
|
@@ -859,9 +847,7 @@ export const RELATIONSHIP_KEYS = [
|
|
|
859
847
|
"manifest",
|
|
860
848
|
"compatibility",
|
|
861
849
|
"itemCatalog",
|
|
862
|
-
"assetArchive",
|
|
863
850
|
"contentIndex",
|
|
864
|
-
"assetReplacement",
|
|
865
851
|
];
|
|
866
852
|
const AUTHOR_KEYS = ["name", "email", "url", "discord", "role"];
|
|
867
853
|
/**
|
|
@@ -2611,23 +2597,6 @@ function normalizeRelationships(value) {
|
|
|
2611
2597
|
}
|
|
2612
2598
|
spec.itemCatalog = rel.itemCatalog;
|
|
2613
2599
|
}
|
|
2614
|
-
// Opt-in, sibling to `itemCatalog`: unpack this dependency's
|
|
2615
|
-
// release archive for its asset bytes alone, building no item
|
|
2616
|
-
// catalogue from it. Buys the archive for a package with no
|
|
2617
|
-
// items of its own to extract — an asset-replacement source
|
|
2618
|
-
// ships no Item packs and has no use for `itemCatalog: true`.
|
|
2619
|
-
if (rel.assetArchive !== undefined) {
|
|
2620
|
-
if (typeof rel.assetArchive !== "boolean") {
|
|
2621
|
-
fail(`${at}.assetArchive`, "must be true or false");
|
|
2622
|
-
}
|
|
2623
|
-
if (rel.assetArchive && spec.manifest === undefined) {
|
|
2624
|
-
fail(
|
|
2625
|
-
`${at}.assetArchive`,
|
|
2626
|
-
"needs a `manifest` naming the package to fetch",
|
|
2627
|
-
);
|
|
2628
|
-
}
|
|
2629
|
-
spec.assetArchive = rel.assetArchive;
|
|
2630
|
-
}
|
|
2631
2600
|
// Opt-out: declares the dependency for the Foundry manifest
|
|
2632
2601
|
// only, so `deps fetch` fetches no content index for it and a
|
|
2633
2602
|
// wikilink into it is refused rather than silently dead. A
|
|
@@ -2646,26 +2615,6 @@ function normalizeRelationships(value) {
|
|
|
2646
2615
|
}
|
|
2647
2616
|
spec.contentIndex = rel.contentIndex;
|
|
2648
2617
|
}
|
|
2649
|
-
// Opt-in: this dependency's asset tree answers this
|
|
2650
|
-
// package's own asset addresses ahead of its local record —
|
|
2651
|
-
// the "rewrite table" `engine/asset-replacement.mjs` reads.
|
|
2652
|
-
// A replacement with no fetched index to check against
|
|
2653
|
-
// resolves nothing, so it cannot pair with
|
|
2654
|
-
// `contentIndex: false`.
|
|
2655
|
-
if (rel.assetReplacement !== undefined) {
|
|
2656
|
-
if (typeof rel.assetReplacement !== "boolean") {
|
|
2657
|
-
fail(`${at}.assetReplacement`, "must be true or false");
|
|
2658
|
-
}
|
|
2659
|
-
if (rel.assetReplacement && rel.contentIndex === false) {
|
|
2660
|
-
fail(
|
|
2661
|
-
`${at}.assetReplacement`,
|
|
2662
|
-
"cannot be true together with `contentIndex: false` — a " +
|
|
2663
|
-
"replacement with no fetched index to check against resolves " +
|
|
2664
|
-
"nothing",
|
|
2665
|
-
);
|
|
2666
|
-
}
|
|
2667
|
-
spec.assetReplacement = rel.assetReplacement;
|
|
2668
|
-
}
|
|
2669
2618
|
return Object.freeze(spec);
|
|
2670
2619
|
}),
|
|
2671
2620
|
);
|
package/docs/api.md
CHANGED
|
@@ -1735,11 +1735,12 @@ A note's markdown, and a document plan, rendered as Typst source. **This module
|
|
|
1735
1735
|
|
|
1736
1736
|
Which glyph an icon name resolves to, read from the font that carries it. {@link module:engine/content-icons} states an icon's family and its name and **deliberately holds no codepoints**: writing them out by hand would be a second copy of a table the font already owns, wrong the first time the icon set renumbers anything, and wrong silently. So the renderer resolves a name against the file it is going to embed, which is this module.
|
|
1737
1737
|
|
|
1738
|
-
| Export | Signature | Returns
|
|
1739
|
-
| ------------------- | ------------------------------------------------ |
|
|
1740
|
-
| `glyphTable` | `function glyphTable(file)` | {Map<string, number>} Name → codepoint.
|
|
1741
|
-
| `familyName` | `function familyName(file)` | {string} The family name, or "" when the table cannot be read.
|
|
1742
|
-
| `resolveIconGlyphs` | `function resolveIconGlyphs(registry, iconFonts` | {Map<string, {font: string, codepoint: number}>} Icon name → glyph.
|
|
1738
|
+
| Export | Signature | Returns | Use it when |
|
|
1739
|
+
| ------------------- | ------------------------------------------------ | -------------------------------------------------------------------- | -------------------------------------------------------------------- |
|
|
1740
|
+
| `glyphTable` | `function glyphTable(file)` | {Map<string, number>} Name → codepoint. | Every glyph name a font carries, with the codepoint that reaches it. |
|
|
1741
|
+
| `familyName` | `function familyName(file)` | {string} The family name, or "" when the table cannot be read. | The family name a font file announces, for Typst's `text(font: …)`. |
|
|
1742
|
+
| `resolveIconGlyphs` | `function resolveIconGlyphs(registry, iconFonts` | {Map<string, {font: string, codepoint: number}>} Icon name → glyph. | Resolve every icon in a registry against the fonts a consumer named. |
|
|
1743
|
+
| `tableDirectory` | `function tableDirectory(buf)` | {Map<string, {offset: number, length: number}>} Its table directory. | The tables an sfnt file holds, by tag. |
|
|
1743
1744
|
|
|
1744
1745
|
### `engine.pdfBuild`
|
|
1745
1746
|
|
|
@@ -2623,14 +2624,15 @@ occupies one line and the file ends with a newline.
|
|
|
2623
2624
|
`@heroiclands/package-build/engine/dictionary-layout` renders SQL results as
|
|
2624
2625
|
Markdown for the dictionary or glossary on its owner's note:
|
|
2625
2626
|
|
|
2626
|
-
| Export | Signature | Returns | Use it when
|
|
2627
|
-
| ------------------------- | ------------------------------------ | -------------------------- |
|
|
2628
|
-
| `LAYOUT_REQUIRED_COLUMNS` | `const LAYOUT_REQUIRED_COLUMNS` | Required columns by layout | Checking the columns a dictionary or glossary query must select.
|
|
2629
|
-
| `COMMON_MARK` | `const COMMON_MARK` | `string` | Reading the mark a common glossary entry opens with.
|
|
2630
|
-
| `DICTIONARY_ENTRY_CLASS` | `const DICTIONARY_ENTRY_CLASS` | `string` | Identifying generated headword spans that are native dictionary targets in Foundry.
|
|
2631
|
-
| `
|
|
2632
|
-
| `
|
|
2633
|
-
| `
|
|
2627
|
+
| Export | Signature | Returns | Use it when |
|
|
2628
|
+
| ------------------------- | ------------------------------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
2629
|
+
| `LAYOUT_REQUIRED_COLUMNS` | `const LAYOUT_REQUIRED_COLUMNS` | Required columns by layout | Checking the columns a dictionary or glossary query must select. |
|
|
2630
|
+
| `COMMON_MARK` | `const COMMON_MARK` | `string` | Reading the mark a common glossary entry opens with. |
|
|
2631
|
+
| `DICTIONARY_ENTRY_CLASS` | `const DICTIONARY_ENTRY_CLASS` | `string` | Identifying generated headword spans that are native dictionary targets in Foundry. |
|
|
2632
|
+
| `LEXICAL_LINK_CLASS` | `const LEXICAL_LINK_CLASS` | `string` | Identifying the links an entry writes, which a site sets as text where they lead nowhere a reader can reach. |
|
|
2633
|
+
| `dictionaryEntryPlugin` | `dictionaryEntryPlugin(md)` | `void` | Registering native dictionary headword rendering on the Foundry Markdown parser. |
|
|
2634
|
+
| `renderDictionary` | `renderDictionary(result, options?)` | `string` | Rendering a language's words with classes, etymology, senses and citations. |
|
|
2635
|
+
| `renderGlossary` | `renderGlossary(result, options?)` | `string` | Rendering an owner's glossary entries, ranks and offices. |
|
|
2634
2636
|
|
|
2635
2637
|
`result` is `{ columns: string[], rows: object[] }`. Both layouts require
|
|
2636
2638
|
`name`, `senses` and `usage`; a missing column throws an error naming it.
|
|
@@ -2676,6 +2678,11 @@ headword's span and paragraph. `anchorsOf` maps this dictionary target to
|
|
|
2676
2678
|
its containing page's UUID with the word fragment; generic authored spans
|
|
2677
2679
|
keep their containing-page behavior.
|
|
2678
2680
|
|
|
2681
|
+
`LEXICAL_LINK_CLASS` is `"lexical-ref"`. Every link an entry writes to
|
|
2682
|
+
another note, a citation, a headword's link to its dictionary word or a
|
|
2683
|
+
wikilink in a gloss, carries it as an attribute. A site build sets such a link
|
|
2684
|
+
as its text when the target is a page a reader cannot reach.
|
|
2685
|
+
|
|
2679
2686
|
## Automatic dictionary and glossary sections
|
|
2680
2687
|
|
|
2681
2688
|
`@heroiclands/package-build/engine/lexical-sections` derives and inserts the
|
|
@@ -546,13 +546,105 @@ as a grid with a row per verse line.
|
|
|
546
546
|
Each finding is an error at the text that is wrong; see
|
|
547
547
|
[a verse in columns](../diagnostics.md#a-worked-case-a-verse-in-columns).
|
|
548
548
|
|
|
549
|
+
### Scrolls
|
|
550
|
+
|
|
551
|
+
Some scripts are written in vertical columns, top to bottom, with the columns
|
|
552
|
+
read from the right, as on a handscroll. A `scroll` fence sets a passage in one
|
|
553
|
+
of these scripts:
|
|
554
|
+
|
|
555
|
+
````markdown
|
|
556
|
+
```scroll {rows=25 cols=12 lang=tsu map=tengchou}
|
|
557
|
+
chen teng chou hing
|
|
558
|
+
tan tsou dou rou
|
|
559
|
+
|
|
560
|
+
gen chei chou tsuen
|
|
561
|
+
```
|
|
562
|
+
````
|
|
563
|
+
|
|
564
|
+
A scroll fence is a real code fence, so Markdown never reformats its body.
|
|
565
|
+
|
|
566
|
+
- **Paragraphs.** The lines of a paragraph are joined into one text. Where
|
|
567
|
+
the source breaks a line makes no difference to where a column breaks. A
|
|
568
|
+
blank line starts a new paragraph, flush at the top of a fresh column, with
|
|
569
|
+
no indent and no mark between paragraphs. This follows classical practice.
|
|
570
|
+
- **`rows=`** is the number of characters in a column, and **`cols=`** the
|
|
571
|
+
number of columns in a panel. Each is a whole number above zero, and either
|
|
572
|
+
may be left out.
|
|
573
|
+
- **`lang=`, `font=` and `map=`** work as they do on a verse fence. See
|
|
574
|
+
[marking language, font and mapping](#marking-language-font-and-mapping).
|
|
575
|
+
The text is mapped before it is laid out, so under a
|
|
576
|
+
[logographic map](#logographic-maps) each word is written by its
|
|
577
|
+
characters, one to a morpheme. The map's rows decide what is written
|
|
578
|
+
between words, and a map for a script that runs its characters together
|
|
579
|
+
writes a space as nothing. If the fence names no `font=`, it takes the face
|
|
580
|
+
of its map, provided the map is drawn in exactly one face. A fence marked
|
|
581
|
+
only with a language whose note names its script, such as
|
|
582
|
+
` ```scroll {rows=25 cols=12 lang=tsu} `, takes that script's map and face;
|
|
583
|
+
see [a language's script](#a-languages-script).
|
|
584
|
+
- **The direction comes from the script.** The face's script note states
|
|
585
|
+
`direction: vertical-rl` in its `data.script`; see
|
|
586
|
+
[script notes and emphasis](../reference/format-details.md#script-notes-and-emphasis).
|
|
587
|
+
A script that states no direction is written in lines, and a scroll fence
|
|
588
|
+
set in it is an error. Markup never states a direction itself.
|
|
589
|
+
- **Spans stay horizontal.** A `[…]{lang=… font=… map=…}` span in the same
|
|
590
|
+
script sets its characters left to right, inline, so a short phrase can sit
|
|
591
|
+
in a line of prose.
|
|
592
|
+
|
|
593
|
+
**On the site, in the preview and in Foundry**, a scroll is a `<div
|
|
594
|
+
class="scroll">` with one `<p>` for each paragraph. The stylesheet sets it
|
|
595
|
+
with `writing-mode: vertical-rl`. A column is one em wide, with half an em
|
|
596
|
+
between columns, so the column pitch is 1.5em.
|
|
597
|
+
|
|
598
|
+
| Attribute | Stated | Left out |
|
|
599
|
+
| --------- | --------------------------------------------------------------------------- | ----------------------------------------------------------- |
|
|
600
|
+
| `rows=N` | Each column is N ems tall: `inline-size: calc(var(--scroll-rows) * 1em)` | Each paragraph is a single column, as long as the paragraph |
|
|
601
|
+
| `cols=M` | The panel is M columns wide: `block-size: calc(var(--scroll-cols) * 1.5em)` | The panel is as wide as its text |
|
|
602
|
+
|
|
603
|
+
The sizes are carried as `data-rows` and `data-cols`, and as the custom
|
|
604
|
+
properties `--scroll-rows` and `--scroll-cols` in the element's `style`. A
|
|
605
|
+
panel wider than its page, or than `cols` columns, scrolls sideways. It opens
|
|
606
|
+
at the right, where the text begins, and unrolls to the left like a
|
|
607
|
+
handscroll.
|
|
608
|
+
|
|
609
|
+
**In the book**, Typst has no vertical writing, so the build draws each panel
|
|
610
|
+
as an image from the face's own TrueType outlines. Each panel is an SVG of at
|
|
611
|
+
most `rows` × `cols` characters, with its columns read from the right. Its alt
|
|
612
|
+
text is the roman text it was written from. Panels follow one another from
|
|
613
|
+
right to left and wrap down the page. Emphasis follows the script's convention:
|
|
614
|
+
rubric characters are drawn in the book's red, and an overline is a rule to the
|
|
615
|
+
right of the column.
|
|
616
|
+
|
|
617
|
+
| Attribute | Stated | Left out |
|
|
618
|
+
| --------- | -------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
619
|
+
| `rows=N` | Each column holds N characters | Each column holds as many characters as the longest paragraph, up to 40 |
|
|
620
|
+
| `cols=M` | Each panel holds up to M columns | Each column is a panel of its own, so as many columns sit side by side as the measure allows |
|
|
621
|
+
|
|
622
|
+
In the book, a space that a map leaves in the text takes up a whole cell.
|
|
623
|
+
|
|
624
|
+
**Errors.** Each of these is an error at its line and column, reported by
|
|
625
|
+
`lint`, the site build, the Foundry compile and the book:
|
|
626
|
+
|
|
627
|
+
| Message | Fix |
|
|
628
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- |
|
|
629
|
+
| `` `rows=0` is not a number of characters: `rows=` is a whole number above zero `` | Write a whole number above zero, or leave the key out. |
|
|
630
|
+
| `` `cols=two` is not a number of columns: `cols=` is a whole number above zero `` | Write a whole number above zero, or leave the key out. |
|
|
631
|
+
| `` `width=` is not a scroll attribute; a scroll takes `rows=`, `cols=`, `lang=`, `font=` and `map=` `` | Remove the key. |
|
|
632
|
+
| ``a `scroll` fence names the face it is set in, with `font=`, a map drawn in one face, with `map=`, or a language whose note names its script in `data.writtenIn`, with `lang=` `` | Name the face, the map, or a language with a script. |
|
|
633
|
+
| ``the map `x` is drawn in more than one face; a `scroll` fence names its face with `font=` `` | Add `font=`. |
|
|
634
|
+
| ``a `scroll` fence sets a script written in columns, and the script of `semaron-kuriale` is written in lines; set it in a face whose script note states `direction: vertical-rl`, or use a div`` | Set the text in a script written in columns, or use a div. |
|
|
635
|
+
| `scroll fence is empty`, `scroll fence needs a closing code fence`, `` a scroll fence takes no `#id` `` | Write the text, close the fence, or remove the id. |
|
|
636
|
+
|
|
637
|
+
A fence with an error in its opening line is shown as code. A fence whose text
|
|
638
|
+
has an error is set exactly as written.
|
|
639
|
+
|
|
549
640
|
## Marking language, font and mapping
|
|
550
641
|
|
|
551
|
-
Three keys go in the attribute block a span, a fenced div
|
|
552
|
-
already takes. Each is optional, and each does one thing:
|
|
642
|
+
Three keys go in the attribute block a span, a fenced div, a verse fence or a
|
|
643
|
+
[scroll fence](#scrolls) already takes. Each is optional, and each does one thing:
|
|
553
644
|
|
|
554
645
|
- **`lang=`** names the language of the text. It becomes the element's
|
|
555
|
-
language tag and
|
|
646
|
+
language tag, and where the language's note names
|
|
647
|
+
[its script](#a-languages-script), the run takes that script's map and face.
|
|
556
648
|
- **`font=`** names the font the text is set in: one of the faces of
|
|
557
649
|
`@heroiclands/fonts`, or `mono`, `serif` or `sans`.
|
|
558
650
|
- **`map=`** names a [mapping note](#mapping-notes), which rewrites the text
|
|
@@ -606,6 +698,60 @@ Zaron tholmeza, [an oath, a vow]{lang=en font=serif}.
|
|
|
606
698
|
:::
|
|
607
699
|
```
|
|
608
700
|
|
|
701
|
+
### A language's script
|
|
702
|
+
|
|
703
|
+
A language note can name the script its language is written in, as one map and
|
|
704
|
+
one face, in `data.writtenIn`:
|
|
705
|
+
|
|
706
|
+
```yaml
|
|
707
|
+
data:
|
|
708
|
+
writtenIn: { map: semaron, font: semaron-kuriale }
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
A run marked with that language alone is then mapped and set as though it named
|
|
712
|
+
both. With Vylari's note stating the default above, these two spans are set
|
|
713
|
+
identically:
|
|
714
|
+
|
|
715
|
+
```markdown
|
|
716
|
+
The lintel is cut with [Zaron tholmeza]{lang=vyl}.
|
|
717
|
+
The lintel is cut with [Zaron tholmeza]{lang=vyl font=semaron-kuriale map=semaron}.
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
The same holds for a div, a verse fence and a [scroll fence](#scrolls). A run
|
|
721
|
+
fills in what it leaves unstated, and an explicit key overrides its half of the
|
|
722
|
+
default:
|
|
723
|
+
|
|
724
|
+
| The run states | It takes from the language |
|
|
725
|
+
| -------------------------- | -------------------------------------------------------------- |
|
|
726
|
+
| neither `map=` nor `font=` | the map and the face |
|
|
727
|
+
| `font=` alone | the map, where the map is drawn in that face; otherwise no map |
|
|
728
|
+
| `map=` alone | the face, where that map is drawn in it; otherwise no face |
|
|
729
|
+
| both | nothing |
|
|
730
|
+
|
|
731
|
+
So a language written in more than one script names its usual one in
|
|
732
|
+
`data.writtenIn` and marks a run in another with that script's keys:
|
|
733
|
+
`[Gar-Anlagh]{lang=khel font=qalezu-hand map=qalezu}`. `[Zaron]{lang=vyl
|
|
734
|
+
font=serif}` sets Vylari in the page's serif, unmapped, since Semaron's map is
|
|
735
|
+
not drawn in it.
|
|
736
|
+
|
|
737
|
+
The default is the run's own language's, read after a div or fence around the
|
|
738
|
+
run gives it its keys. Inside `::: {lang=vyl}`, a gloss marked
|
|
739
|
+
`[an oath]{lang=en}` takes no face from Vylari. A language whose note states no
|
|
740
|
+
`data.writtenIn` marks its runs with its tag alone.
|
|
741
|
+
|
|
742
|
+
`lint` checks the key on the language note: `map` must be the `data.map.name`
|
|
743
|
+
of a mapping note in the package, and `font` one of the faces that map lists.
|
|
744
|
+
Each is an error at its value, and the default then fills no run:
|
|
745
|
+
|
|
746
|
+
> `` `data.writtenIn.map` is `semoran`, which no mapping note's `data.map.name` declares; did you mean `semaron`? ``
|
|
747
|
+
>
|
|
748
|
+
> `` `data.writtenIn.font` is `teng-chou`, which the map `semaron` is not drawn in; it is drawn in `semaron-kuriale` ``
|
|
749
|
+
>
|
|
750
|
+
> `` `data.writtenIn` names the script a language is written in, and this note's `subType` is not `language` ``
|
|
751
|
+
|
|
752
|
+
The face a language's script names is delivered with the package's fonts, as a
|
|
753
|
+
face named by `font=` is.
|
|
754
|
+
|
|
609
755
|
### What `lang=` takes
|
|
610
756
|
|
|
611
757
|
`lang=` is read in this order:
|
|
@@ -622,7 +768,8 @@ still a well-formed tag, such as `vly` for `vyl`, is read as the tag of a real
|
|
|
622
768
|
language. When such a value is within one edit of a declared name (a letter
|
|
623
769
|
added, dropped or changed, two neighbours swapped, or a different case), `lint`
|
|
624
770
|
warns and names the declared language. Text marked with `lang=` alone is not
|
|
625
|
-
checked against any lexicon
|
|
771
|
+
checked against any lexicon unless its language names
|
|
772
|
+
[its script](#a-languages-script); a run with `lang=` and a map is, as
|
|
626
773
|
[a mapped run's words](#a-mapped-runs-words) describes.
|
|
627
774
|
|
|
628
775
|
### What `font=` takes
|
|
@@ -993,13 +1140,14 @@ finding the lint reports in `data.map`.
|
|
|
993
1140
|
Every target rewrites marked text first, so a page, a Foundry journal and a
|
|
994
1141
|
book all show the same thing.
|
|
995
1142
|
|
|
996
|
-
| Marking | The text | The element
|
|
997
|
-
| -------------------------------------- | ---------------------------------- |
|
|
998
|
-
| `lang=` alone | As written | Tagged with the language's tag, `lang="art-x-vyl"`
|
|
999
|
-
| `map=` | Rewritten by the map, line by line | As below
|
|
1000
|
-
| `font=` a face | As written, or as the map wrote it | The tag, `script` and the face's class; not indexed by the site's search
|
|
1001
|
-
| `font=mono`, `serif`, `sans` | As written, or as the map wrote it | The tag and `font-mono`, `font-serif` or `font-sans`
|
|
1002
|
-
| A div or fence in a right-to-left face | As above | Also `dir="rtl"`; a div also carries `script-block`
|
|
1143
|
+
| Marking | The text | The element |
|
|
1144
|
+
| -------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------- |
|
|
1145
|
+
| `lang=` alone | As written | Tagged with the language's tag, `lang="art-x-vyl"` |
|
|
1146
|
+
| `map=` | Rewritten by the map, line by line | As below |
|
|
1147
|
+
| `font=` a face | As written, or as the map wrote it | The tag, `script` and the face's class; not indexed by the site's search |
|
|
1148
|
+
| `font=mono`, `serif`, `sans` | As written, or as the map wrote it | The tag and `font-mono`, `font-serif` or `font-sans` |
|
|
1149
|
+
| A div or fence in a right-to-left face | As above | Also `dir="rtl"`; a div also carries `script-block` |
|
|
1150
|
+
| A scroll fence | Each paragraph on one line | `scroll`, the tag, `script` and the face's class; see [scrolls](#scrolls) |
|
|
1003
1151
|
|
|
1004
1152
|
No target writes `<bdo>`, `<bdi>` or a Unicode direction control character: a
|
|
1005
1153
|
right-to-left face's code points carry their own direction. Text with an error
|
|
@@ -1135,7 +1283,7 @@ SELECT owner, kind, tag, font, line FROM runs WHERE lang = 'vyl' ORDER BY owner,
|
|
|
1135
1283
|
```
|
|
1136
1284
|
````
|
|
1137
1285
|
|
|
1138
|
-
Its columns are `owner`, `kind` (`span`, `block` or `
|
|
1286
|
+
Its columns are `owner`, `kind` (`span`, `block`, `verse` or `scroll`), `lang` as written,
|
|
1139
1287
|
the `tag` it resolves to (`NULL` when it resolves to none), `font`, `map`, `line`
|
|
1140
1288
|
and `column`. A run inside a div or a fence records the keys it inherits. See
|
|
1141
1289
|
[the `runs` relation](../reference/format-details.md#content-tables).
|
|
@@ -1297,7 +1445,7 @@ A column's heading is its SQL alias, so `AS "Name"` is what a reader sees. A cel
|
|
|
1297
1445
|
| `entries` | Every note, stubs included. |
|
|
1298
1446
|
| `events` | One row per event a `lore`, `place` or `affiliation` note writes in `data.events`, with `whenSort` to order them by date. |
|
|
1299
1447
|
| `names` | Each authored `.name` span, with its containing NOTE Address, visible text, optional type/subtype and source line/column. |
|
|
1300
|
-
| `runs` | Each span, div and verse fence marked with `lang=`, `font=` or `map=`, with its containing NOTE Address, its `kind`, `lang` as written, the `tag` it resolves to, `font
|
|
1448
|
+
| `runs` | Each span, div and verse fence marked with `lang=`, `font=` or `map=`, with its containing NOTE Address, its `kind`, `lang` as written, the `tag` it resolves to, the `font` and `map` it is set with (its own, inherited, or its language's [script](#a-languages-script)), and source line/column. See [marking language, font and mapping](#marking-language-font-and-mapping). |
|
|
1301
1449
|
| `maps` | One row per row of a mapping note's `data.map`, with its containing NOTE Address, the map's `name`, the `font` whose own row it is (`NULL` for a shared row), the row's 1-based place as `"row"`, and its `"from"`, `"to"`, `before` and `"at"`. See [mapping notes](#mapping-notes). |
|
|
1302
1450
|
| `natives` | One row per native form a language note's word states in `native`, with that note as its `language`, the word's place as `word`, its `form`, the entry's place as `native`, and its `map`, `font` and `"text"`. See [what `map=` takes](#what-map-takes). |
|
|
1303
1451
|
| `words` | One row per word a language note writes in `data.words`, with that note as its `language`, its `position` and what it is built from. |
|
|
@@ -1311,17 +1459,17 @@ A column's heading is its SQL alias, so `AS "Name"` is what a reader sees. A cel
|
|
|
1311
1459
|
| `tongues` | One row per tag a language note writes in `data.tongues`: `tag`, `meaning` and `tongue_language`. |
|
|
1312
1460
|
| `retired` | One row per form a language note writes in `data.retired`: `form`, `instead` as a list, and `why`. |
|
|
1313
1461
|
| `scope` | One row per value of a language note's `data.scope`: the `kind` it is under and the `value`. |
|
|
1314
|
-
| `letters` | One row per entry of a language note's `data.sounds.letters`: `letters` as a list, `kind`, `like`, `place` and `tongue`.
|
|
1462
|
+
| `letters` | One row per entry of a language note's or a spelling guide's `data.sounds.letters`: `letters` as a list, `kind`, `like`, `place`, `ipa` and `tongue`. |
|
|
1315
1463
|
| `edges` | One row per entry of a language note's `data.sounds.edges`: the `edge` and its `sounds` as a list. |
|
|
1316
1464
|
| `clusters` | One row per language note stating `data.sounds.clusters`, with its `max`. |
|
|
1317
1465
|
| `cluster_groups` | One row per group of a language note's `data.sounds.clusters.groups`: `what`, `clusters` as a list, and `use`. |
|
|
1318
1466
|
| `stress` | One row per language note stating `data.sounds.stress`, with its `two`, `longer` and `mark` (`NULL` where unstated). |
|
|
1319
|
-
| `finals` | One row per entry of a language note's `data.sounds.finals`: `final` and `
|
|
1467
|
+
| `finals` | One row per entry of a language note's `data.sounds.finals`: `final`, `like` and `ipa`. |
|
|
1320
1468
|
| `syllables` | One row per language note stating `data.sounds.syllables`: each rule a column, the harmony as `harmony_back`, `harmony_front`, `harmony_neutral`, `harmony_neutralAs` and `harmony_partners`, a list of `{ vowel, partner }`. |
|
|
1321
1469
|
| `joining` | One row per entry of a language note's `data.sounds.joining`: `first`, `second`, `written` and `example`. |
|
|
1322
1470
|
| `joins` | One row per entry of a language note's `data.sounds.joins`: `meeting`, `rule`, `letters` and `"where"`. |
|
|
1323
|
-
| `marks` | One row per entry of a language note's `data.sounds.marks`: `mark`, `letters`, `kind` and `"limit"`.
|
|
1324
|
-
| `skeleton` | One row per entry of a language note's `data.sounds.skeleton`: `second` and `between`.
|
|
1471
|
+
| `marks` | One row per entry of a language note's or a spelling guide's `data.sounds.marks`: `mark`, `letters`, `kind` and `"limit"`. |
|
|
1472
|
+
| `skeleton` | One row per entry of a language note's `data.sounds.skeleton`: `second`, `third` and `between`. |
|
|
1325
1473
|
| `frames` | One row per frame of a language note's `data.sounds.frames`: `frame`, `shape`, `class`, `makes` and `examples` as `{ root, form }`. |
|
|
1326
1474
|
| `read_past` | One row per entry of a language note's `data.sounds.readPast`: `written`, `readAs` and `what`. |
|
|
1327
1475
|
| `mutations` | One row per entry of a language note's `data.sounds.mutations`: `mutation`, `sound`, `becomes` and `example`. |
|