@heroiclands/package-build 25.2.1 → 25.4.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 +26 -0
- package/README.md +1 -1
- package/assets/styles/content-base.css +97 -116
- package/docs/api.md +30 -6
- package/docs/authoring/links-and-markup.md +214 -126
- package/docs/commands.md +2 -2
- package/docs/content-format.md +31 -6
- package/docs/diagnostics.md +27 -27
- package/docs/guides/writing-in-invented-scripts.md +89 -83
- package/docs/reference/format-details.md +6 -7
- package/docs/reference/note-types.md +15 -15
- package/docs/reference/theme-pages.md +38 -57
- package/engine/anchors.mjs +14 -0
- package/engine/code-fences.mjs +15 -6
- package/engine/content-blocks.mjs +7 -4
- package/engine/content-figures.mjs +19 -5
- package/engine/content-footnotes.mjs +60 -1
- package/engine/content-index.mjs +1 -1
- package/engine/content-render.mjs +66 -48
- package/engine/content-scripts.mjs +357 -101
- package/engine/content-spans.mjs +76 -10
- package/engine/content-verse.mjs +687 -358
- package/engine/first-use.mjs +43 -12
- package/engine/heading-attributes.mjs +2 -1
- package/engine/journals.mjs +8 -1
- package/engine/markdown-blocks.mjs +3 -2
- package/engine/markup-validation.mjs +17 -0
- package/engine/name-markup.mjs +1 -0
- package/engine/note-vocabulary.mjs +2 -2
- package/engine/pdf-render.mjs +89 -130
- package/engine/prose-lint.mjs +14 -2
- package/engine/roman-verse.mjs +68 -57
- package/engine/run-rows.mjs +1 -1
- package/engine/sql-tables.mjs +1 -1
- package/engine/verse-format.mjs +77 -0
- package/engine/verse-metre.mjs +49 -47
- package/engine/verse-regions.mjs +181 -0
- package/engine/wikilink-pattern.mjs +31 -0
- package/engine/wikilink-syntax.mjs +2 -16
- package/package.json +1 -1
- package/site-theme/static/css/style.css +68 -96
- package/types/engine/code-fences.d.mts +1 -3
- package/types/engine/content-blocks.d.mts +3 -1
- package/types/engine/content-footnotes.d.mts +23 -0
- package/types/engine/content-scripts.d.mts +12 -7
- package/types/engine/content-spans.d.mts +3 -1
- package/types/engine/content-verse.d.mts +263 -82
- package/types/engine/name-markup.d.mts +5 -0
- package/types/engine/roman-verse.d.mts +7 -6
- package/types/engine/verse-format.d.mts +9 -0
- package/types/engine/verse-metre.d.mts +4 -4
- package/types/engine/verse-regions.d.mts +78 -0
- package/types/engine/wikilink-pattern.d.mts +17 -0
- package/types/engine/wikilink-syntax.d.mts +1 -41
|
@@ -72,9 +72,15 @@ keys makes a separate presentation choice. `enc=default` inside an encoded
|
|
|
72
72
|
parent keeps the inherited language but does not inherit its inferred script
|
|
73
73
|
face. An explicitly authored font remains a font choice.
|
|
74
74
|
|
|
75
|
+
Footnotes are not letters of the tongue. A defined `[^key]` in any encoded span
|
|
76
|
+
is removed before encoding and restored after the span, outside the script font.
|
|
77
|
+
In an encoded verse div, a reference appears only in the Roman column, beside
|
|
78
|
+
its authored word, with no duplicate number, definition or backlink. Footnotes
|
|
79
|
+
never change verse shape. See [footnotes in works and encoded spans](../authoring/links-and-markup.md#footnotes-in-works-and-encoded-spans).
|
|
80
|
+
|
|
75
81
|
A name's braces use the shared name controls. Resolved references encode only
|
|
76
82
|
their visible labels, retaining URLs and presentation cues. These keys apply
|
|
77
|
-
to spans, divs
|
|
83
|
+
to spans, divs and scroll fences. A scroll's selected font must
|
|
78
84
|
belong to a script whose note declares `direction: vertical-rl`.
|
|
79
85
|
|
|
80
86
|
## Roman source and literal characters
|
|
@@ -106,10 +112,9 @@ escapes are removed before encoding, and diagnostics retain the source position.
|
|
|
106
112
|
|
|
107
113
|
Every `Zs` space separator and U+0009 through U+000D count as whitespace. A run
|
|
108
114
|
of them is one word separator, which the encoding writes by its own rule.
|
|
109
|
-
Newlines
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
fence; an inline quotation of verse may use it. Verse indentation is layout,
|
|
115
|
+
Newlines join as whitespace. In a verse div, `/` ends a logical line,
|
|
116
|
+
blank lines or `//` end stanzas, and `--- {.canto}` after a blank line ends a canto. A literal
|
|
117
|
+
slash is written `\/`. Indentation at a logical line boundary is layout,
|
|
113
118
|
not a punctuation character added to the encoded words.
|
|
114
119
|
|
|
115
120
|
A `.name` child in a language run reaches the encoding with standard `{…}`
|
|
@@ -486,67 +491,76 @@ The keys are checked where they sit:
|
|
|
486
491
|
|
|
487
492
|
## Verse
|
|
488
493
|
|
|
489
|
-
### A poem in a verse
|
|
494
|
+
### A poem in a verse div
|
|
490
495
|
|
|
491
|
-
A
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
496
|
+
A `.verse` div holds inline Markdown and explicit verse structure. It is opaque
|
|
497
|
+
to lists, headings, quotes and code-block syntax. Its source newlines join unless
|
|
498
|
+
`/` ends a logical line. The authoring formatter preserves the complete div and
|
|
499
|
+
its attributes byte for byte, and also preserves inline `.verse` quotations.
|
|
495
500
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
Lokazor lonak
|
|
499
|
-
|
|
501
|
+
```markdown
|
|
502
|
+
::: {.verse lang=vyl font=semaron-kuriale enc=vylsemaronenc}
|
|
503
|
+
Lokazor lonak./
|
|
504
|
+
.lokamen zaron.
|
|
505
|
+
:::
|
|
500
506
|
```
|
|
501
|
-
````
|
|
502
507
|
|
|
503
|
-
|
|
508
|
+
Quoted verse is a span within prose, such as
|
|
509
|
+
`[Lokazor lonak zaron./..Lokamen lonak zaron.//]{.verse lang=vyl}`.
|
|
510
|
+
A concrete `enc=` sets a quotation in script only, continuously in the prose.
|
|
511
|
+
Its `/` and `//` become the encoding's verse marks; only a div has paired script
|
|
512
|
+
and Roman columns. An unencoded quotation keeps Roman line and stanza layout.
|
|
513
|
+
Quotations take no `work=`, `form=`, `scan=`, labels or canto breaks.
|
|
514
|
+
A div's canto separator can carry a heading and an anchor:
|
|
504
515
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
every content line starts with a column number and one or more spaces.
|
|
509
|
-
Blank lines separate logical verse rows, and `***` separates stanzas.
|
|
516
|
+
```markdown
|
|
517
|
+
::: {.verse lang=en}
|
|
518
|
+
The watch arrives.
|
|
510
519
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
520
|
+
--- {.canto #choosing title="The Choosing"}
|
|
521
|
+
The captain answers.
|
|
522
|
+
:::
|
|
523
|
+
```
|
|
515
524
|
|
|
516
|
-
|
|
517
|
-
|
|
525
|
+
The title is shown once as heading text; the encoder receives its Roman `***`
|
|
526
|
+
canto control. Authored `***` inside verse is a finding. The canto stays within
|
|
527
|
+
the work and does not open a separate journal page.
|
|
518
528
|
|
|
519
|
-
|
|
520
|
-
```verse {numstep=1 lang=vyl cols=3}
|
|
521
|
-
1 [Lokazor lonak zaron.]{lang=vyl enc=vylsemaronenc}
|
|
522
|
-
3 [He walks the oath road.]{lang=en}
|
|
523
|
-
3 [Lokazor lonak zaron.]{lang=vyl enc=default}
|
|
529
|
+
### Versions of a work
|
|
524
530
|
|
|
525
|
-
|
|
526
|
-
2 [Nothing to say]{lang=en}
|
|
527
|
-
3 [I walk the oath road.]{lang=en}
|
|
528
|
-
3 [Lokamen lonak zaron.]{lang=vyl enc=default}
|
|
531
|
+
`form=epic` records the author's literary form without inferring layout or metre.
|
|
529
532
|
|
|
530
|
-
|
|
533
|
+
A `.verse` div with a concrete `enc=` sets one original in its script on the
|
|
534
|
+
left and Roman on the right. The author writes the text once; the two
|
|
535
|
+
presentations align logical lines at full weight. `/` ends a logical line,
|
|
536
|
+
source newlines otherwise join, a blank line or `//` ends a stanza, and a line
|
|
537
|
+
of `--- {.canto}`, preceded by a blank line, ends a canto. Leading periods at a logical line boundary indent
|
|
538
|
+
that line. Use `\/` for a literal slash.
|
|
531
539
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
```
|
|
536
|
-
````
|
|
540
|
+
```markdown
|
|
541
|
+
::: {.verse work=walking lang=en}
|
|
542
|
+
He walks the oath road.
|
|
537
543
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
`lang=` identifies the language without choosing a column; number prefixes
|
|
541
|
-
alone place the readings. Inline links, language changes and authored spaces
|
|
542
|
-
remain inside the chosen reading. Leading periods indent that reading.
|
|
544
|
+
I walk the oath road.
|
|
545
|
+
:::
|
|
543
546
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
547
|
+
::: {.verse work=walking lang=vyl enc=vylsemaronenc}
|
|
548
|
+
Lokazor lonak zaron.
|
|
549
|
+
|
|
550
|
+
Lokamen lonak zaron.
|
|
551
|
+
:::
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
`work=` groups the versions within the page. Their stanza labels match, and the
|
|
555
|
+
build checks that their canto counts and stanza counts per canto agree. The
|
|
556
|
+
English div is one column, and `enc=default` also stays one Roman column.
|
|
557
|
+
The original's encoded and Roman presentations share one label per stanza.
|
|
558
|
+
Names, `⟦…⟧` codage, language gaps and other inline spans retain their meaning;
|
|
559
|
+
codage draws its glyphs on the left and appears as codage on the right. The
|
|
560
|
+
content index records the original once with its div language and encoding.
|
|
561
|
+
See [versions and stanza labels](../authoring/links-and-markup.md#versions-and-stanza-labels)
|
|
562
|
+
for poetry and prose examples, and [directions and speakers](../authoring/links-and-markup.md#directions-and-speakers)
|
|
563
|
+
for plain semantic span hooks.
|
|
550
564
|
|
|
551
565
|
### Metre
|
|
552
566
|
|
|
@@ -562,15 +576,15 @@ data:
|
|
|
562
576
|
`name` is lowercase letters, digits and `-`, unique in the package; `beats` is
|
|
563
577
|
the beats of one line, a whole number above zero; `kind` is `accentual`, the
|
|
564
578
|
only kind: a beat falls on a stressed syllable and the length of a syllable is
|
|
565
|
-
not counted. A
|
|
579
|
+
not counted. A div that states `scan=` with the declared name and a `lang=`
|
|
566
580
|
whose language note states `data.sounds.stress` is counted line by line:
|
|
567
581
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
Lokazor lonak zaron
|
|
582
|
+
```markdown
|
|
583
|
+
::: {.verse lang=vyl scan=trimeter}
|
|
584
|
+
Lokazor lonak zaron./
|
|
571
585
|
Lokamen lonak zaron.
|
|
586
|
+
:::
|
|
572
587
|
```
|
|
573
|
-
````
|
|
574
588
|
|
|
575
589
|
**The stress rule** is `data.sounds.stress`, `{ two, longer, mark }`. `two`
|
|
576
590
|
(`first` or `last`) places the stress in a word of two syllables; `longer`
|
|
@@ -600,21 +614,19 @@ the second beats and, in brackets, with all of them:
|
|
|
600
614
|
|
|
601
615
|
> ``this line has 4 beats (5 with secondary beats); the metre `hexameter` has 6``
|
|
602
616
|
|
|
603
|
-
**The check is author-side.** Readers see nothing of it: the rendered
|
|
604
|
-
carries `data-metre` with the metre's name and nothing a reader sees. A
|
|
617
|
+
**The check is author-side.** Readers see nothing of it: the rendered div
|
|
618
|
+
carries `data-metre` with the metre's name and nothing a reader sees. A div
|
|
605
619
|
without `scan=` is not counted. `scan=` is refused where it cannot mean
|
|
606
620
|
anything, each an error:
|
|
607
621
|
|
|
608
622
|
> `` `hexamter` is not a declared metre: `scan=` names the `name` of a `data.metres` entry of a `doc` note; did you mean `hexameter`? ``
|
|
609
623
|
|
|
610
|
-
> `` `scan=` counts beats by a language's stress rule: the
|
|
624
|
+
> `` `scan=` counts beats by a language's stress rule: the div needs a `lang=` ``
|
|
611
625
|
|
|
612
626
|
> ``the language `vyl` states no `data.sounds.stress`, which `scan=` counts beats by``
|
|
613
627
|
|
|
614
628
|
> ``the language `vyl` is not a configured language with a `note`, so it has no stress rule for `scan=` to count beats by``
|
|
615
629
|
|
|
616
|
-
> `` `scan=` counts the beats of one language's lines; a verse with cols>1 groups independent physical lines ``
|
|
617
|
-
|
|
618
630
|
A repeated metre name is an error too:
|
|
619
631
|
|
|
620
632
|
> `` `data.metres[1].name` is `trimeter`, which this note declares twice; a metre's name is unique ``
|
|
@@ -1158,13 +1170,12 @@ where the characters are the code points above: `Lokazor` begins with the
|
|
|
1158
1170
|
capital `L` of the rows, `zaron` is the exception's long vowel, and each period
|
|
1159
1171
|
writes the script's pause point.
|
|
1160
1172
|
|
|
1161
|
-
A
|
|
1162
|
-
|
|
1163
|
-
Vylari in column three, with a sparse middle cell, and the second's lines each carry three beats.
|
|
1173
|
+
A work's English and original versions sit on one note. Its original is written
|
|
1174
|
+
once and appears beside its Roman presentation; a separate div checks metre.
|
|
1164
1175
|
|
|
1165
1176
|
**`assets/content/Lore/Walking.md`**
|
|
1166
1177
|
|
|
1167
|
-
|
|
1178
|
+
```markdown
|
|
1168
1179
|
---
|
|
1169
1180
|
shortcode: walking
|
|
1170
1181
|
name: { full: The Walking }
|
|
@@ -1175,28 +1186,23 @@ The walking of the oath road is sung in two settings. The first sets the poem
|
|
|
1175
1186
|
beside its translation, and the second keeps the metre that the court keeps, so
|
|
1176
1187
|
that a line with the wrong count is reported to the author who wrote it.
|
|
1177
1188
|
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
3 [He walks the oath road.]{lang=en}
|
|
1181
|
-
3 [Lokazor lonak zaron.]{lang=vyl enc=default}
|
|
1189
|
+
::: {.verse work=walking lang=en}
|
|
1190
|
+
He walks the oath road.
|
|
1182
1191
|
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
3 [I walk the oath road.]{lang=en}
|
|
1186
|
-
3 [Lokamen lonak zaron.]{lang=vyl enc=default}
|
|
1192
|
+
I walk the oath road.
|
|
1193
|
+
:::
|
|
1187
1194
|
|
|
1188
|
-
|
|
1195
|
+
::: {.verse work=walking lang=vyl enc=vylsemaronenc}
|
|
1196
|
+
Lokazor lonak zaron.
|
|
1189
1197
|
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
3 [alathos lokazor.]{lang=vyl enc=default}
|
|
1193
|
-
```
|
|
1198
|
+
Lokamen lonak zaron.
|
|
1199
|
+
:::
|
|
1194
1200
|
|
|
1195
|
-
|
|
1196
|
-
Lokazor lonak zaron
|
|
1201
|
+
::: {.verse lang=vyl scan=trimeter}
|
|
1202
|
+
Lokazor lonak zaron./
|
|
1197
1203
|
Lokamen lonak zaron.
|
|
1204
|
+
:::
|
|
1198
1205
|
```
|
|
1199
|
-
````
|
|
1200
1206
|
|
|
1201
1207
|
A script note gives Semaron its emphasis convention, and a run with double stars then
|
|
1202
1208
|
sets them in red:
|
|
@@ -2107,7 +2107,7 @@ face. An explicitly authored font remains a font choice.
|
|
|
2107
2107
|
|
|
2108
2108
|
A name's braces use the shared name controls. Resolved references encode only
|
|
2109
2109
|
their visible labels, retaining URLs and presentation cues. These keys apply
|
|
2110
|
-
to spans, divs
|
|
2110
|
+
to spans, divs and scroll fences. A scroll's selected font must
|
|
2111
2111
|
belong to a script whose note declares `direction: vertical-rl`.
|
|
2112
2112
|
|
|
2113
2113
|
#### Encodings
|
|
@@ -2273,7 +2273,7 @@ keeps a lexicon to its exceptions.
|
|
|
2273
2273
|
|
|
2274
2274
|
#### Metres
|
|
2275
2275
|
|
|
2276
|
-
A verse
|
|
2276
|
+
A verse div that states `scan=` is counted against a metre declared in a
|
|
2277
2277
|
`doc` note's `data.metres`, each entry `{ name, beats, kind }`. `name` is
|
|
2278
2278
|
lowercase letters, digits and `-`, unique in the package, and a name declared
|
|
2279
2279
|
twice is an error at the second. `beats` is a whole number above zero. `kind` is
|
|
@@ -2297,7 +2297,6 @@ its count can be the metre's.
|
|
|
2297
2297
|
| A `scan=` no `data.metres` entry names, at the value | error |
|
|
2298
2298
|
| A `scan=` on a fence with no `lang=`, at the key | error |
|
|
2299
2299
|
| A `scan=` on a fence whose language states no stress rule or names no language note, at `lang=` | error |
|
|
2300
|
-
| A `scan=` on a verse in columns, at the key | error |
|
|
2301
2300
|
|
|
2302
2301
|
> ``this line has 4 beats (5 with secondary beats); the metre `hexameter` has 6``
|
|
2303
2302
|
|
|
@@ -3593,7 +3592,7 @@ metadata supplies `names` in that package's SQL schema. Public queries exclude
|
|
|
3593
3592
|
GM-only owners; all/native contexts retain them. Only authored occurrences
|
|
3594
3593
|
contribute rows, so generated queries and sections add no further names.
|
|
3595
3594
|
|
|
3596
|
-
**`runs`** is one row per span, generic div and verse
|
|
3595
|
+
**`runs`** is one row per span, generic div and verse div an authored note
|
|
3597
3596
|
body marks with `lang=`, `font=` or `enc=`. Each row has these columns,
|
|
3598
3597
|
including on an empty relation:
|
|
3599
3598
|
|
|
@@ -4034,7 +4033,7 @@ The caption attaches to exactly the next supported block:
|
|
|
4034
4033
|
| Markdown table | `table` | Table |
|
|
4035
4034
|
| Image, Markdown or wikilink | `figure` | Figure |
|
|
4036
4035
|
| SQL fence, including backtick SQL | `table` | Table |
|
|
4037
|
-
| Verse
|
|
4036
|
+
| Verse div | `verse` | Poem |
|
|
4038
4037
|
| Any other code fence | `code` | Code |
|
|
4039
4038
|
| Paragraph, quote block or fenced div | `prose` | Prose |
|
|
4040
4039
|
|
|
@@ -6856,7 +6855,7 @@ closed list where its values are words:
|
|
|
6856
6855
|
end, `antepenultimate`, `penultimate` or `final`; `mark` is the diacritic, `acute`,
|
|
6857
6856
|
`grave` or `circumflex`, that marks a stress the rule would not choose and
|
|
6858
6857
|
moves it to the syllable it sits on. Syllables are vowel groups, a pair listed
|
|
6859
|
-
in `syllables.vowelPairs` counting as one. A verse
|
|
6858
|
+
in `syllables.vowelPairs` counting as one. A verse div's `scan=` counts
|
|
6860
6859
|
beats by this rule; see [metres](#metres).
|
|
6861
6860
|
- `finals`: the syllable finals, each with what it sounds like and, as `ipa`,
|
|
6862
6861
|
its sound in the International Phonetic Alphabet, for a language whose
|
|
@@ -8275,7 +8274,7 @@ Content prepared to be played — a situation with its cast, places, and possibl
|
|
|
8275
8274
|
| `concepts[].id` | string | Required: lowercase letters, digits and `-`, unique in the package |
|
|
8276
8275
|
| `concepts[].gloss` | string | Required: what the concept means, in brief |
|
|
8277
8276
|
| `concepts[].group` | string | Required: the group the report lists the concept under |
|
|
8278
|
-
| `metres` | `{ name, beats, kind }[]` | The metres a verse
|
|
8277
|
+
| `metres` | `{ name, beats, kind }[]` | The metres a verse div's `scan=` names; any subType. See [metres](#metres) |
|
|
8279
8278
|
| `metres[].name` | string | Required: what `scan=` names it by, lowercase letters, digits and `-`, unique in the package |
|
|
8280
8279
|
| `metres[].beats` | `integer`, required | The beats of one line, above zero |
|
|
8281
8280
|
| `metres[].kind` | `accentual` | Required: how the beats are counted |
|
|
@@ -997,20 +997,20 @@ Lore records in-world knowledge. A `culture` describes a people; a `custom` desc
|
|
|
997
997
|
|
|
998
998
|
**Subtypes:** `rules`, `userguide`, `reference`, `howto`, `concept`, `settingguide`, `post`.
|
|
999
999
|
|
|
1000
|
-
| Field | Shape | Meaning
|
|
1001
|
-
| --------------- | ------------------------------------ |
|
|
1002
|
-
| `data.language` | a configured language alias | The configured language alias an encoding document writes.
|
|
1003
|
-
| `data.font` | an installed font slug | The encoding's installed font, which supplies all glyph codes.
|
|
1004
|
-
| `data.accepts` | a list of characters or ranges | Accepted Roman letters and additions to standard punctuation.
|
|
1005
|
-
| `data.vowels` | a string | The letters a contextual vowel match reads as vowels.
|
|
1006
|
-
| `data.mappings` | Roman strings to glyph codes | Roman source strings mapped to codes published by the selected font.
|
|
1007
|
-
| `data.rules` | the closed encoding rules vocabulary | Executable normalization, matching, case, stress, vowel groups, accents and contextual mappings.
|
|
1008
|
-
| `data.concepts` | list of `{ id, gloss, group }` | The concepts of a core vocabulary, in the order the report lists them. See [the core vocabulary](format-details.md#the-core-vocabulary).
|
|
1009
|
-
| `data.date` | string | The day a post was published, as `YYYY-MM-DD`. Required on a `post`; no other subType states it. Posts are listed and fed newest first by it.
|
|
1010
|
-
| `data.author` | string | Who wrote a post, as the byline prints them. A post that names none carries the site's byline, the first entry of `authors`; no other subType states it.
|
|
1011
|
-
| `data.culture` | an Address | The culture a setting guide introduces, as a culture lore note. Required on `settingguide`; no other subType states it.
|
|
1012
|
-
| `data.sounds` | a map — `{ letters?, marks? }` | A spelling guide's letters and the marks written on them, for every tongue of the setting: each letter row's `tongue` names the language notes that write it.
|
|
1013
|
-
| `data.metres` | list of `{ name, beats, kind }` | The metres a verse
|
|
1000
|
+
| Field | Shape | Meaning |
|
|
1001
|
+
| --------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1002
|
+
| `data.language` | a configured language alias | The configured language alias an encoding document writes. |
|
|
1003
|
+
| `data.font` | an installed font slug | The encoding's installed font, which supplies all glyph codes. |
|
|
1004
|
+
| `data.accepts` | a list of characters or ranges | Accepted Roman letters and additions to standard punctuation. |
|
|
1005
|
+
| `data.vowels` | a string | The letters a contextual vowel match reads as vowels. |
|
|
1006
|
+
| `data.mappings` | Roman strings to glyph codes | Roman source strings mapped to codes published by the selected font. |
|
|
1007
|
+
| `data.rules` | the closed encoding rules vocabulary | Executable normalization, matching, case, stress, vowel groups, accents and contextual mappings. |
|
|
1008
|
+
| `data.concepts` | list of `{ id, gloss, group }` | The concepts of a core vocabulary, in the order the report lists them. See [the core vocabulary](format-details.md#the-core-vocabulary). |
|
|
1009
|
+
| `data.date` | string | The day a post was published, as `YYYY-MM-DD`. Required on a `post`; no other subType states it. Posts are listed and fed newest first by it. |
|
|
1010
|
+
| `data.author` | string | Who wrote a post, as the byline prints them. A post that names none carries the site's byline, the first entry of `authors`; no other subType states it. |
|
|
1011
|
+
| `data.culture` | an Address | The culture a setting guide introduces, as a culture lore note. Required on `settingguide`; no other subType states it. |
|
|
1012
|
+
| `data.sounds` | a map — `{ letters?, marks? }` | A spelling guide's letters and the marks written on them, for every tongue of the setting: each letter row's `tongue` names the language notes that write it. |
|
|
1013
|
+
| `data.metres` | list of `{ name, beats, kind }` | The metres a verse div's `scan=` names. A div that states one is warned at each line that cannot have its beats. See [metres](../authoring/links-and-markup.md#metre). |
|
|
1014
1014
|
|
|
1015
1015
|
**Inner keys** — a key a field's value does not declare is an error at its own line and column.
|
|
1016
1016
|
|
|
@@ -1065,7 +1065,7 @@ Lore records in-world knowledge. A `culture` describes a people; a `custom` desc
|
|
|
1065
1065
|
| `data.sounds.marks[].letters` | a list of letters | yes | The letters that carry it. |
|
|
1066
1066
|
| `data.sounds.marks[].kind` | one of stress, length, apart | yes | What the mark says of its letter. |
|
|
1067
1067
|
| `data.sounds.marks[].limit` | one of one, any | yes | How many a word may carry: `one` at most, or `any`. |
|
|
1068
|
-
| `data.metres[].name` | string | yes | What a verse
|
|
1068
|
+
| `data.metres[].name` | string | yes | What a verse div's `scan=` names the metre by: lowercase letters, digits and `-`, unique in the package. |
|
|
1069
1069
|
| `data.metres[].beats` | a whole number above zero | yes | The beats of one line. |
|
|
1070
1070
|
| `data.metres[].kind` | one of accentual | yes | How the beats are counted: `accentual`, one beat for each stressed syllable the language's stress rule and the beat convention give. |
|
|
1071
1071
|
|
|
@@ -333,63 +333,44 @@ Caption classes are unrestricted. The built-in `border` class draws the block as
|
|
|
333
333
|
|
|
334
334
|
## Verse
|
|
335
335
|
|
|
336
|
-
A verse
|
|
337
|
-
stanza and
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
A
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
A numbered verse in columns gives every logical row a `.verse-number`, empty
|
|
376
|
-
on rows it does not number, so repeated readings do not advance the counter.
|
|
377
|
-
The grid remains left to right while inline text follows its own script
|
|
378
|
-
direction. Each row has its own grid and aligns all its cells at the top. Below a block width of `32rem` a row stacks
|
|
379
|
-
its columns in order; it is a container query, so a narrow journal window
|
|
380
|
-
stacks as well. The Foundry stylesheet draws the same.
|
|
381
|
-
|
|
382
|
-
| class | drawn as |
|
|
383
|
-
| ------------------ | ------------------------------------------------------------- |
|
|
384
|
-
| `.verse` | the poem |
|
|
385
|
-
| `.verse-line` | one line of a poem without columns |
|
|
386
|
-
| `.verse-numbered` | a numbered poem, with a margin for its numbers |
|
|
387
|
-
| `.verse-number` | a line's number, muted |
|
|
388
|
-
| `.verse-columns` | a poem in columns, and the container its rows are measured by |
|
|
389
|
-
| `.verse-row` | one logical verse row: its number and its cells |
|
|
390
|
-
| `.verse-column` | one numbered cell, possibly empty, with its readings stacked |
|
|
391
|
-
| `.verse-part` | one entry's text, in the body serif unless its face sets it |
|
|
392
|
-
| `.verse-secondary` | every reading after a column's first in that row, grey |
|
|
336
|
+
A `.verse` div reaches the page as `.verse`, with one `.verse-stanza` per
|
|
337
|
+
stanza and `.verse-line` per logical line. Indentation uses `i1` through `i8`;
|
|
338
|
+
deeper levels carry their complete `--verse-indent`. `.verse-canto-break`
|
|
339
|
+
separates cantos. A work-labelled div adds `.verse-labelled`, and each stanza
|
|
340
|
+
opens with a small `.verse-label` shared across its presentations.
|
|
341
|
+
|
|
342
|
+
A concrete div encoding adds `.verse-paired`. Each `.verse-row` aligns one
|
|
343
|
+
`.verse-native` cell with one `.verse-roman` cell at full weight. The script is
|
|
344
|
+
on the left; its direction applies within its cell. A narrow container stacks
|
|
345
|
+
the native presentation before the Roman presentation. An unencoded div or
|
|
346
|
+
`enc=default` is one Roman column. See [versions of a work](../authoring/links-and-markup.md#versions-and-stanza-labels).
|
|
347
|
+
|
|
348
|
+
An unencoded quotation uses `.verse-inline` with inline-safe layout wrappers.
|
|
349
|
+
An encoded quotation is a script-only span flowing within prose, with no verse
|
|
350
|
+
grid or Roman companion. Its verse signs come from the encoding. Footnote
|
|
351
|
+
references follow encoded spans outside their script font. In a paired div,
|
|
352
|
+
references occur only in `.verse-roman`, beside their authored words.
|
|
353
|
+
|
|
354
|
+
| Class | Meaning |
|
|
355
|
+
| ---------------------- | ------------------------------------------------- |
|
|
356
|
+
| `.verse` | A block or unencoded quoted verse |
|
|
357
|
+
| `.verse-inline` | A quotation with inline-safe span wrappers |
|
|
358
|
+
| `.verse-canto-heading` | A canto title and optional anchor within the work |
|
|
359
|
+
| `.verse-stanza` | One stanza or prose paragraph |
|
|
360
|
+
| `.verse-line` | One logical line |
|
|
361
|
+
| `.verse-labelled` | A version carrying automatic stanza labels |
|
|
362
|
+
| `.verse-label` | The stanza number or canto:stanza label |
|
|
363
|
+
| `.verse-paired` | Script and Roman presentations of one original |
|
|
364
|
+
| `.verse-row` | Matching logical lines in both presentations |
|
|
365
|
+
| `.verse-native` | Encoded text on the left |
|
|
366
|
+
| `.verse-roman` | Roman text on the right |
|
|
367
|
+
| `.verse-canto-break` | A canto boundary |
|
|
368
|
+
| `.direction` | An instruction, inside or outside verse |
|
|
369
|
+
| `.speaker` | A speaker label, inside or outside verse |
|
|
370
|
+
|
|
371
|
+
Direction and speaker classes have plain defaults. The book preserves the same
|
|
372
|
+
classes through `book-span`, with plain `book-direction` and `book-speaker`
|
|
373
|
+
hooks for their presentation.
|
|
393
374
|
|
|
394
375
|
## Emphasis in a script
|
|
395
376
|
|
package/engine/anchors.mjs
CHANGED
|
@@ -124,6 +124,20 @@ export function collectAnchors(body, bodyLine = 1, resolveRole, syntax) {
|
|
|
124
124
|
});
|
|
125
125
|
}
|
|
126
126
|
for (const poem of scanVerse(body).blocks) {
|
|
127
|
+
for (const group of poem.model.groups)
|
|
128
|
+
if (group.cantoBreak && group.id)
|
|
129
|
+
anchors.push({
|
|
130
|
+
slug: slugify(group.id),
|
|
131
|
+
name: group.title || group.id,
|
|
132
|
+
level: 0,
|
|
133
|
+
line:
|
|
134
|
+
bodyLine +
|
|
135
|
+
String(body)
|
|
136
|
+
.slice(0, poem.bodyStart + group.from)
|
|
137
|
+
.split("\n").length -
|
|
138
|
+
1,
|
|
139
|
+
kind: "prose",
|
|
140
|
+
});
|
|
127
141
|
if (poem.id)
|
|
128
142
|
anchors.push({
|
|
129
143
|
slug: slugify(poem.id),
|
package/engine/code-fences.mjs
CHANGED
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
* prevent.
|
|
47
47
|
*/
|
|
48
48
|
|
|
49
|
+
import { verseRegions } from "./verse-regions.mjs";
|
|
49
50
|
import { parseExtensionAttributes } from "./extension-attributes.mjs";
|
|
50
51
|
|
|
51
52
|
/** A fence line, capturing its indent, its marker, and its info string. */
|
|
@@ -104,11 +105,10 @@ function column(space) {
|
|
|
104
105
|
* @param {object} [options]
|
|
105
106
|
* @param {boolean} [options.spans=true] - Include inline code spans. Set false
|
|
106
107
|
* to consider only block-level code.
|
|
107
|
-
* @param {boolean} [options.verseAsProse=true] - Treat verse bodies as inline prose.
|
|
108
108
|
* @returns {Array<{start: number, end: number}>} Non-overlapping regions, in
|
|
109
109
|
* source order. `end` is exclusive.
|
|
110
110
|
*/
|
|
111
|
-
export function codeRegions(markdown, { spans = true
|
|
111
|
+
export function codeRegions(markdown, { spans = true } = {}) {
|
|
112
112
|
const src = String(markdown ?? "");
|
|
113
113
|
if (!src) return [];
|
|
114
114
|
const lines = src.split("\n");
|
|
@@ -127,6 +127,16 @@ export function codeRegions(markdown, { spans = true, verseAsProse = true } = {}
|
|
|
127
127
|
});
|
|
128
128
|
|
|
129
129
|
const regions = [];
|
|
130
|
+
const verses = verseRegions(src);
|
|
131
|
+
const verseLines = new Set(
|
|
132
|
+
verses.flatMap((region) =>
|
|
133
|
+
Array.from({ length: region.end - region.start + 1 }, (_, i) => region.start + i),
|
|
134
|
+
),
|
|
135
|
+
);
|
|
136
|
+
for (const verse of verses) {
|
|
137
|
+
regions.push(through(verse.start, verse.start));
|
|
138
|
+
if (verse.closed) regions.push(through(verse.end, verse.end));
|
|
139
|
+
}
|
|
130
140
|
// The content column of the innermost open list item: an indented block
|
|
131
141
|
// has to clear *that*, not column zero, or every list continuation would
|
|
132
142
|
// read as code.
|
|
@@ -137,6 +147,7 @@ export function codeRegions(markdown, { spans = true, verseAsProse = true } = {}
|
|
|
137
147
|
|
|
138
148
|
for (let i = 0; i < lines.length; i++) {
|
|
139
149
|
const line = lines[i];
|
|
150
|
+
if (verseLines.has(i)) continue;
|
|
140
151
|
|
|
141
152
|
const fence = FENCE_LINE.exec(line);
|
|
142
153
|
if (fence) {
|
|
@@ -145,10 +156,7 @@ export function codeRegions(markdown, { spans = true, verseAsProse = true } = {}
|
|
|
145
156
|
let close = i + 1;
|
|
146
157
|
while (close < lines.length && !closer.test(lines[close])) close++;
|
|
147
158
|
// An unclosed fence runs to the end of the document.
|
|
148
|
-
|
|
149
|
-
regions.push(through(i, i));
|
|
150
|
-
if (close < lines.length) regions.push(through(close, close));
|
|
151
|
-
} else regions.push(through(i, Math.min(close, lines.length - 1)));
|
|
159
|
+
regions.push(through(i, Math.min(close, lines.length - 1)));
|
|
152
160
|
i = close;
|
|
153
161
|
afterBlank = false;
|
|
154
162
|
continue;
|
|
@@ -186,6 +194,7 @@ export function codeRegions(markdown, { spans = true, verseAsProse = true } = {}
|
|
|
186
194
|
afterBlank = false;
|
|
187
195
|
}
|
|
188
196
|
|
|
197
|
+
regions.sort((a, b) => a.start - b.start);
|
|
189
198
|
if (spans) regions.push(...codeSpans(src, regions));
|
|
190
199
|
regions.sort((a, b) => a.start - b.start);
|
|
191
200
|
return regions;
|
|
@@ -111,7 +111,9 @@ export function scanBlocks(source) {
|
|
|
111
111
|
for (const token of blockTokens(source)) {
|
|
112
112
|
if (
|
|
113
113
|
!token.map ||
|
|
114
|
-
!["blockquote_open", "fence", "code_block", "html_block"].includes(
|
|
114
|
+
!["blockquote_open", "fence", "code_block", "html_block", "verse_div"].includes(
|
|
115
|
+
token.type,
|
|
116
|
+
)
|
|
115
117
|
)
|
|
116
118
|
continue;
|
|
117
119
|
for (let line = token.map[0]; line < token.map[1]; line++) literalLines.add(line);
|
|
@@ -256,11 +258,12 @@ function attributeText(block, target, classes) {
|
|
|
256
258
|
* @param {object} [options]
|
|
257
259
|
* @param {(markdown: string) => string} [options.renderInline] - How a title
|
|
258
260
|
* is rendered; omitted, a title is plain inline Markdown.
|
|
261
|
+
* @param {Map<string, object>} [options.verses] - Shared encoded verse presentations.
|
|
259
262
|
* @returns {{markdown: string, errors: Array<{line: number, column: number, message: string}>}}
|
|
260
263
|
*/
|
|
261
|
-
export function renderBlocks(source, target, { renderInline } = {}) {
|
|
264
|
+
export function renderBlocks(source, target, { renderInline, verses } = {}) {
|
|
262
265
|
const { errors } = scanBlocks(source);
|
|
263
|
-
source = renderScroll(renderVerse(source).markdown).markdown;
|
|
266
|
+
source = renderScroll(renderVerse(source, { verses }).markdown).markdown;
|
|
264
267
|
const renderedBlocks = scanBlocks(source).blocks;
|
|
265
268
|
if (!renderedBlocks.length) return { markdown: String(source ?? ""), errors };
|
|
266
269
|
const lines = String(source ?? "").split("\n");
|
|
@@ -276,7 +279,7 @@ export function renderBlocks(source, target, { renderInline } = {}) {
|
|
|
276
279
|
// at every depth, never a rendered fragment.
|
|
277
280
|
const held =
|
|
278
281
|
BLOCK_CONTAINERS.includes(block.name) ?
|
|
279
|
-
renderBlocks(block.body, target, { renderInline }).markdown
|
|
282
|
+
renderBlocks(block.body, target, { renderInline, verses }).markdown
|
|
280
283
|
: block.body;
|
|
281
284
|
if (block.name === "div") {
|
|
282
285
|
output.push("", `<div ${attributes}>`, "", held, "", "</div>", "");
|