@heroiclands/package-build 23.6.0 → 23.7.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.
@@ -451,47 +451,161 @@ These fields are accepted by every note type. A field's value can still be irrel
451
451
 
452
452
  **Subtypes:** `social`, `nature`, `craft`, `lore`, `language`, `script`, `mystical`, `physical`, `combat`, `combattechnique`.
453
453
 
454
- | Field | Shape | Meaning |
455
- | ----------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
456
- | `data.icon` | an Address | The document's profile art — an `icon` address, resolved into `img`. |
457
- | `data.templatePriority` | number | Template priority; unset means the note is not a template. |
458
- | `data.masteryLevel` | number | Mastery before any modifier. |
459
- | `data.parentSkill` | an Address | The skill this one specialises. |
460
- | `data.names` | a language's name lists | How this language's speakers are named, for `package-build npc new`: `pattern` builds a name from placeholders such as "{given} {clan}" and literal text, `given` maps a gender to a list of given names, `female` and `male` required, and every other key is a list of names a placeholder of the same name draws from. A language skill note only. See [name lists](format-details.md#name-lists). |
461
- | `data.family` | an Address | The parent language, as a language skill note: this language reads the parent's words, and its parents' in turn, as its own. A language skill note only. See [a language's words](format-details.md#a-languages-words). |
462
- | `data.abbreviation` | a string, such as `Prov.` | The tag a dictionary prints for the language, beside an entry's class and in an etymology, as `Prov.`; the language's full name where unstated. A language skill note only. See [a language's words](format-details.md#a-languages-words). |
463
- | `data.classModifiers` | list of word class modifiers | The class modifiers the language uses, from the master word classes. A word's class may carry only these. Empty when unstated. A language skill note only. |
464
- | `data.fields` | list of `{ name, holds }` | The fields the language's words are grouped under. A language skill note only. |
465
- | `data.words` | list of `{ form, class, field, gloss, … }` | The language's words, one map each, in the order they print. A language skill note only. See [a language's words](format-details.md#a-languages-words). |
466
- | `data.affixes` | list of `{ form, gloss, attaches?, examples? }` | The affixes a word's `built` pieces may name, each with its gloss. A language skill note only. |
454
+ | Field | Shape | Meaning |
455
+ | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
456
+ | `data.icon` | an Address | The document's profile art — an `icon` address, resolved into `img`. |
457
+ | `data.templatePriority` | number | Template priority; unset means the note is not a template. |
458
+ | `data.masteryLevel` | number | Mastery before any modifier. |
459
+ | `data.parentSkill` | an Address | The skill this one specialises. |
460
+ | `data.names` | a language's name lists | How this language's speakers are named, for `package-build npc new`: `pattern` builds a name from placeholders such as "{given} {clan}" and literal text, `given` maps a gender to a list of given names, `female` and `male` required, and every other key is a list of names a placeholder of the same name draws from. A language skill note only. See [name lists](format-details.md#name-lists). |
461
+ | `data.family` | an Address | The parent language, as a language skill note: this language reads the parent's words, and its parents' in turn, as its own. A language skill note only. See [a language's words](format-details.md#a-languages-words). |
462
+ | `data.abbreviation` | a string, such as `Prov.` | The tag a dictionary prints for the language, beside an entry's class and in an etymology, as `Prov.`; the language's full name where unstated. A language skill note only. See [a language's words](format-details.md#a-languages-words). |
463
+ | `data.classModifiers` | list of word class modifiers | The class modifiers the language uses, from the master word classes. A word's class may carry only these. Empty when unstated. A language skill note only. |
464
+ | `data.fields` | list of `{ name, holds }` | The fields the language's words are grouped under. A language skill note only. |
465
+ | `data.words` | list of `{ form, class, field, gloss, … }` | The language's words, one map each, in the order they print. A language skill note only. See [a language's words](format-details.md#a-languages-words). |
466
+ | `data.affixes` | list of `{ form, gloss, attaches?, examples? }` | The affixes a word's `built` pieces may name, each with its gloss. A language skill note only. |
467
+ | `data.tongues` | list of `{ tag, meaning, language? }` | The tags a register row's `tongue` may name, each with what it means. A language skill note only. |
468
+ | `data.register` | list of `{ name, tongue?, kind?, built?, why? }` | Every name the setting gives in the language's reach, with its tongue and pieces; the notes carrying each name are derived. A language skill note only. |
469
+ | `data.retired` | list of `{ form, instead?, why }` | The forms the setting does not write, and why. A language skill note only. |
470
+ | `data.scope` | a map — `{ folders?, cultures?, lore?, parents?, addresses?, paths?, types?, skip? }` | The notes the register covers. A language skill note only. |
471
+ | `data.sounds` | a map — `{ letters?, edges?, clusters?, stress?, finals?, syllables?, joining?, joins?, marks?, skeleton?, frames?, readPast? }` | The letters the language writes and the rules its words keep. A language skill note only. |
472
+ | `data.soundChanges` | list of `{ name, from?, to?, steps }` | Named sets of ordered changes, each making one tongue's words from another's. A language skill note only. |
473
+ | `data.elements` | list of `{ form, variants?, position?, sense, examples? }` | The elements the language's names are built from. A language skill note only. |
474
+ | `data.roots` | list of `{ root, sense, field? }` | The consonantal roots the language's words are set from. A language skill note only. |
475
+ | `data.cognates` | list of `{ forms, proto?, gloss }` | Sets of forms one older word takes in several languages, stated on the eldest. A language skill note only. |
476
+ | `data.callingNames` | a map — `{ closings, minSyllables }` | The short name a long given name is called by. A language skill note only. |
467
477
 
468
478
  **Inner keys** — a key a field's value does not declare is an error at its own line and column.
469
479
 
470
- | Key | Shape | Required | Meaning |
471
- | ------------------------------ | --------------------------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
472
- | `data.names.pattern` | a pattern such as "{given} {clan}", a list of them, or a map of genders to either | yes | How a name is built: each `{list}` placeholder is filled from the list of that name, `{given.<gender>}` from that gender's given names, and the text around them is written as it stands. A list states every form a name may take; a map keyed by gender states each gender's forms, and a gender with none takes every pattern stated. |
473
- | `data.names.given` | a map of genders to lists of names | yes | Given names by gender word. A gender with no list draws from every given list together. |
474
- | `data.fields[].name` | a string | yes | The field's name, which a word's `field` names. |
475
- | `data.fields[].holds` | a string | yes | What the field holds. |
476
- | `data.words[].form` | the word as cited, bare | yes | The word as cited, with no backticks. |
477
- | `data.words[].name_sort` | a string | no | The sort key; the form when unstated. |
478
- | `data.words[].class` | a word class, base first, such as `n I f` | yes | A class from the master word classes: a base, then the modifiers the language declares in `classModifiers`. |
479
- | `data.words[].field` | one of the language's `fields` names | yes | The field the word is grouped under, named in the language's `fields`. |
480
- | `data.words[].gloss` | a string | yes | The meaning, in brief. |
481
- | `data.words[].source` | a map — `{ kind, language?, form? }` | no | Where the word comes from. |
482
- | `data.words[].source.kind` | one of inherited, borrowed, kept, worn, coined, substrate, island | yes | How the word came into the tongue. |
483
- | `data.words[].source.language` | a language skill Address | no | The tongue the word was borrowed from; required for `borrowed`. |
484
- | `data.words[].source.form` | a string | no | The form the word had in its source, bare. |
485
- | `data.words[].built` | a list of pieces | no | The pieces the word is built from, in order, as the language's words and affixes write them; absent for a root word. |
486
- | `data.words[].attested` | a list of Addresses | no | The notes the word is cited from. |
487
- | `data.words[].pronunciation` | a respelling such as `sol-MEH-reh` | no | A respelling in hyphen-separated syllables, the stressed one in capitals: letters, apostrophes and hyphens only, and at most one capitalised syllable. |
488
- | `data.words[].tones` | a string | no | A tone pattern, such as `LHL`. |
489
- | `data.words[].root` | a string | no | A consonantal skeleton, such as `d-l-k`. |
490
- | `data.words[].frame` | a string | no | The frame a root is set in. |
491
- | `data.affixes[].form` | the affix as written, such as `-rith` | yes | The affix as a word's `built` names it. |
492
- | `data.affixes[].gloss` | a string | yes | What the affix means. |
493
- | `data.affixes[].attaches` | a string | no | How it attaches, such as `replaces a closing vowel`. |
494
- | `data.affixes[].examples` | a list of strings | no | The names the affix is read from. |
480
+ | Key | Shape | Required | Meaning |
481
+ | ----------------------------------------- | --------------------------------------------------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
482
+ | `data.names.pattern` | a pattern such as "{given} {clan}", a list of them, or a map of genders to either | yes | How a name is built: each `{list}` placeholder is filled from the list of that name, `{given.<gender>}` from that gender's given names, and the text around them is written as it stands. A list states every form a name may take; a map keyed by gender states each gender's forms, and a gender with none takes every pattern stated. |
483
+ | `data.names.given` | a map of genders to lists of names | yes | Given names by gender word. A gender with no list draws from every given list together. |
484
+ | `data.fields[].name` | a string | yes | The field's name, which a word's `field` names. |
485
+ | `data.fields[].holds` | a string | yes | What the field holds. |
486
+ | `data.words[].form` | the word as cited, bare | yes | The word as cited, with no backticks. |
487
+ | `data.words[].variants` | a list of forms | no | The word's other forms, such as a long form beside a short one; a marked use of one cites the word. |
488
+ | `data.words[].name_sort` | a string | no | The sort key; the form when unstated. |
489
+ | `data.words[].class` | a word class, base first, such as `n I f` | yes | A class from the master word classes: a base, then the modifiers the language declares in `classModifiers`. |
490
+ | `data.words[].field` | one of the language's `fields` names | yes | The field the word is grouped under, named in the language's `fields`. |
491
+ | `data.words[].gloss` | a string, or a list of senses | yes | The meaning, in brief; a list states one sense per entry, which a dictionary numbers. |
492
+ | `data.words[].source` | a map — `{ kind, language?, form? }` | no | Where the word comes from. |
493
+ | `data.words[].source.kind` | one of inherited, borrowed, kept, worn, coined, substrate, island | yes | How the word came into the tongue. |
494
+ | `data.words[].source.language` | a language skill Address | no | The tongue the word was borrowed from; required for `borrowed`. |
495
+ | `data.words[].source.form` | a string | no | The form the word had in its source, bare. |
496
+ | `data.words[].built` | a list of pieces | no | The pieces the word is built from, in order, as the language's words and affixes write them; absent for a root word. |
497
+ | `data.words[].note` | a string | no | What a source says of the word beyond its pieces, such as a cognate it is read with. |
498
+ | `data.words[].pronunciation` | a respelling such as `sol-MEH-reh` | no | A respelling in hyphen-separated syllables, the stressed one in capitals: letters, apostrophes and hyphens only, and at most one capitalised syllable. |
499
+ | `data.words[].tones` | a string | no | A tone pattern, such as `LHL`. |
500
+ | `data.words[].root` | a string | no | A consonantal skeleton, such as `d-l-k`. |
501
+ | `data.words[].frame` | a frame of the language's `sounds.frames` | no | The frame a root is set in, named in the language's `sounds.frames`. |
502
+ | `data.affixes[].form` | the affix as written, such as `-rith` | yes | The affix as a word's `built` names it. |
503
+ | `data.affixes[].gloss` | a string | yes | What the affix means. |
504
+ | `data.affixes[].attaches` | a string | no | How it attaches, in words, such as `replaces a closing vowel`. |
505
+ | `data.affixes[].replaces` | `vowel`, or the letters, such as `a` | no | What it takes the place of at the close of the stem: `vowel` for any closing vowel, or the letters it replaces; added to the whole stem where absent. |
506
+ | `data.affixes[].lengthens` | `true` or `false` | no | Whether the stem's last vowel lengthens before the affix; `false` where unstated. An affix that `replaces` the stem's close does not also lengthen it. |
507
+ | `data.affixes[].front` | the affix as written, such as `-ür` | no | Its form after front vowels, where the language keeps vowel harmony. |
508
+ | `data.affixes[].examples` | a list of strings | no | The names the affix is read from. |
509
+ | `data.affixes[].tones` | a tone pattern, such as `L` | no | The tone pattern the affix carries, written as a word's `tones` is. |
510
+ | `data.tongues[].tag` | a tag such as `dunhari`, or `exonym:<tongue>` | yes | The tag a register row's `tongue` names: lowercase letters and digits, or a tag closing on `:<tongue>`, which declares one tag per tongue named after the colon. |
511
+ | `data.tongues[].meaning` | a string | yes | What a name of this tongue is. |
512
+ | `data.tongues[].language` | a language skill Address | no | The language note the tag names, where it is one. |
513
+ | `data.register[].name` | a name as the setting writes it | yes | A name the setting gives, as it is written. |
514
+ | `data.register[].tongue` | a tag of `data.tongues`, or `translation` | no | The tongue the name is in, as a tag `data.tongues` declares, or `translation`. A row states a `tongue`, a `kind`, or both. |
515
+ | `data.register[].kind` | one of byname, given, place | no | What kind of name it is, in a language that sorts its names by kind. |
516
+ | `data.register[].built` | a list of pieces | no | The pieces the name is built from, in order, as a word's `built` writes them. |
517
+ | `data.register[].why` | a string | no | Why the name stands outside the pattern the language's names are built by. |
518
+ | `data.retired[].form` | a string | yes | The form the setting does not write. |
519
+ | `data.retired[].instead` | a string, or a list of them | no | What is written in its place, one form or several; absent where nothing is. |
520
+ | `data.retired[].why` | a string | yes | Why the setting does not write it. |
521
+ | `data.scope.folders` | a list of folder Addresses | no | Every note whose `data.packFolder` is one of these folders. |
522
+ | `data.scope.cultures` | a list of culture Addresses | no | Every note whose `data.culture` is one of these cultures. |
523
+ | `data.scope.lore` | a list of lore Addresses | no | Every note whose `data.lore` names one of these notes. |
524
+ | `data.scope.parents` | a list of Addresses | no | Every note whose `data.parents` names one of these notes. |
525
+ | `data.scope.addresses` | a list of Addresses | no | These notes themselves. |
526
+ | `data.scope.paths` | a list of content paths | no | Every note whose file sits below one of these paths of the content tree. |
527
+ | `data.scope.types` | a list of note types | no | The note types the register covers; where stated, a note of another type is out of scope whatever else catches it. |
528
+ | `data.scope.skip` | a list of Addresses | no | Notes out of scope whatever else catches them. |
529
+ | `data.sounds.letters` | list of `{ letters, kind, like, tongue? }` | no | The letters the language writes, and the sounds they stand for. |
530
+ | `data.sounds.letters[].letters` | a list of letters | yes | The letters or digraphs the row describes, as written. |
531
+ | `data.sounds.letters[].kind` | a string, such as `consonant` or `long vowel` | yes | What kind of sound they write. |
532
+ | `data.sounds.letters[].like` | a string | yes | What they sound like. |
533
+ | `data.sounds.letters[].tongue` | a tag, or a list of them | no | The tongues that write them, as tags `data.tongues` declares; every one where absent. |
534
+ | `data.sounds.edges` | list of `{ edge, sounds }` | no | The sounds that may stand at each edge of a word, one entry per edge. |
535
+ | `data.sounds.edges[].edge` | one of openConsonant, openCluster, closeConsonant, closeCluster, innerCluster, vowelPair, glide, syllabic | yes | Which edge of a word the sounds stand at. |
536
+ | `data.sounds.edges[].sounds` | a list of sounds, or `any` | yes | The sounds, as written; `any` for every one, and an empty list for none. |
537
+ | `data.sounds.clusters` | a map — `{ max }` | no | How many consonants may stand together. |
538
+ | `data.sounds.clusters.max` | a whole number | yes | The most consonants that stand together inside a word. |
539
+ | `data.sounds.stress` | one of first syllable, penultimate or final, by weight, as marked | no | Where a word's stress falls. |
540
+ | `data.sounds.finals` | list of `{ final, like }` | no | The syllable finals, for a language whose syllables are parsed by them. |
541
+ | `data.sounds.finals[].final` | a final as written, such as `ang` | yes | The final. |
542
+ | `data.sounds.finals[].like` | a string | yes | What it sounds like. |
543
+ | `data.sounds.syllables` | a map of syllable rules | no | What a syllable and a word may open and close on. |
544
+ | `data.sounds.syllables.onsets` | one of single | no | What a syllable opens on: `single`, a single consonant. |
545
+ | `data.sounds.syllables.codas` | a list of sounds, or `any` | no | The consonants that may close a syllable; `any` for every one. |
546
+ | `data.sounds.syllables.finals` | a list of sounds, or `any` | no | The consonants that may close a word; `any` for every one. |
547
+ | `data.sounds.syllables.doubled` | a list of letters | no | The doubled consonants a word may hold; none where empty. |
548
+ | `data.sounds.syllables.vowelPairs` | a list of vowel pairs | no | The vowels that may stand together; none where empty. |
549
+ | `data.sounds.syllables.initialVowel` | `true` or `false` | no | Whether a word may open on a vowel. |
550
+ | `data.sounds.syllables.finalVowel` | `true` or `false` | no | Whether a word may close on a vowel; `true` where unstated. |
551
+ | `data.sounds.syllables.neverInitial` | a list of letters | no | The letters that never open a word. |
552
+ | `data.sounds.syllables.signature` | a list of letters | no | The letters that mark a word as the language's own. |
553
+ | `data.sounds.syllables.harmony` | a map — `{ back, front, neutral?, neutralAs? }` | no | The vowel harmony a word keeps. |
554
+ | `data.sounds.syllables.harmony.back` | a list of vowels | yes | The back vowels. |
555
+ | `data.sounds.syllables.harmony.front` | a list of vowels | yes | The front vowels. |
556
+ | `data.sounds.syllables.harmony.neutral` | a list of vowels | no | The vowels of neither set. |
557
+ | `data.sounds.syllables.harmony.neutralAs` | one of back, front | no | The set a word of neutral vowels alone counts as. |
558
+ | `data.sounds.joining` | list of `{ first, second, written, example? }` | no | How two parts are written where the first closes and the second opens on the given sounds. |
559
+ | `data.sounds.joining[].first` | a list of sounds | yes | The sounds the first part closes on. |
560
+ | `data.sounds.joining[].second` | a list of sounds | yes | The sounds the second part opens on. |
561
+ | `data.sounds.joining[].written` | a string, such as `â` or `y+` | yes | What is written where they meet: the sound that stands for both, or a join closing on `+`, which keeps both and sets it between. |
562
+ | `data.sounds.joining[].example` | a string | no | A word joined so. |
563
+ | `data.sounds.joins` | list of `{ meeting, rule, letters?, where? }` | no | What happens where two parts of a word meet, one entry per meeting. |
564
+ | `data.sounds.joins[].meeting` | one of C+C, V+C, V+V | yes | Which sounds meet: a consonant `C` or a vowel `V` closing the first part, then opening the second. |
565
+ | `data.sounds.joins[].rule` | one of merge, insert, drop, double | yes | What happens where they meet. |
566
+ | `data.sounds.joins[].letters` | a list of letters | no | The letters the rule takes: what `insert` sets between, or what `double` doubles. |
567
+ | `data.sounds.joins[].where` | a string, such as `between stems` | no | Where the rule holds; everywhere where absent. |
568
+ | `data.sounds.marks` | list of `{ mark, letters, kind, limit }` | no | The marks the language writes on its letters. |
569
+ | `data.sounds.marks[].mark` | a string, such as `acute` | yes | The mark's name. |
570
+ | `data.sounds.marks[].letters` | a list of letters | yes | The letters that carry it. |
571
+ | `data.sounds.marks[].kind` | one of stress, length | yes | What the mark says of its letter. |
572
+ | `data.sounds.marks[].limit` | one of one, any | yes | How many a word may carry: `one` at most, or `any`. |
573
+ | `data.sounds.skeleton` | list of `{ second, between? }` | no | The vowel set between a root's second and third consonants. |
574
+ | `data.sounds.skeleton[].second` | a list of sounds, or `any` | yes | The second consonants of a root the row holds for; `any` for every other. |
575
+ | `data.sounds.skeleton[].between` | a vowel, such as `a` | no | The vowel set between the second and third consonants; nothing where absent. |
576
+ | `data.sounds.frames` | list of `{ frame, shape, class, makes, examples? }` | no | The patterns a root is set in. |
577
+ | `data.sounds.frames[].frame` | a string, such as `bare` | yes | The frame's name, which a word's `frame` names. |
578
+ | `data.sounds.frames[].shape` | a pattern, such as `K1aK2K3` | yes | The pattern, the root's consonants numbered `K1`, `K2`, `K3`. |
579
+ | `data.sounds.frames[].class` | a list of word class bases | yes | The classes of word the frame makes, each a base of the master word classes. |
580
+ | `data.sounds.frames[].makes` | a string | yes | What the frame makes of a root. |
581
+ | `data.sounds.frames[].examples` | a map of roots to forms | no | The form a root takes in the frame, keyed by the root. |
582
+ | `data.sounds.readPast` | list of `{ written, readAs?, what }` | no | Marks and spellings a word is read through before the sound rules hold it. |
583
+ | `data.sounds.readPast[].written` | a string | yes | A mark or spelling the pages write. |
584
+ | `data.sounds.readPast[].readAs` | a string | no | What a word is read with in its place; absent where it is read as nothing. |
585
+ | `data.sounds.readPast[].what` | a string | yes | What the mark or spelling is. |
586
+ | `data.soundChanges[].name` | a string, such as `From Helonic to Byzarian` | yes | The set's name, which no other set of the note shares. |
587
+ | `data.soundChanges[].from` | a language skill Address | no | The language whose words the steps start from. |
588
+ | `data.soundChanges[].to` | a language skill Address | no | The language whose words the steps make. |
589
+ | `data.soundChanges[].steps` | list of `{ step, change, where? }` | yes | The steps, in the order they apply; no step label stands twice in a set. |
590
+ | `data.soundChanges[].steps[].step` | a string, such as `A1` or `"1"` | yes | The step's label, in the order the changes apply. |
591
+ | `data.soundChanges[].steps[].change` | a change in arrow notation, such as `` `ph` > `f`; `kh` > `h` `` | yes | The change, in arrow notation: one or more `` `sources` > `targets` `` rules separated by `;`, or the operation a step names in words. |
592
+ | `data.soundChanges[].steps[].where` | a string, such as `word end` | no | Where the change holds; everywhere where absent. |
593
+ | `data.elements[].form` | the element as written, such as `arn-` | yes | The element a name is built from. |
594
+ | `data.elements[].variants` | a list of forms | no | The element's other forms, such as `aldr-` beside `ald-`. |
595
+ | `data.elements[].position` | one of opening, closing, either, link | no | Where in a name the element stands. |
596
+ | `data.elements[].sense` | a string | yes | What the element means. |
597
+ | `data.elements[].examples` | a list of names | no | The names the element is read from. |
598
+ | `data.roots[].root` | a consonantal skeleton, such as `d-l-k` | yes | The root. |
599
+ | `data.roots[].sense` | a string | yes | What the root means. |
600
+ | `data.roots[].field` | a string, such as `stone` | no | The field the root belongs to. |
601
+ | `data.cognates[].forms` | a map of language Addresses to forms | yes | The form the set takes in each language, keyed by the language note's Address. |
602
+ | `data.cognates[].proto` | a form, bare | no | The reconstructed form the set descends from, in no attested language; printed with an asterisk. |
603
+ | `data.cognates[].gloss` | a string | yes | What the forms mean. |
604
+ | `data.callingNames.closings` | list of `{ form?, doubled?, usual }` | yes | What a calling name closes on. |
605
+ | `data.callingNames.closings[].form` | an ending, such as `-u` | no | The ending; a row states `form` or `doubled`, never both. |
606
+ | `data.callingNames.closings[].doubled` | `true` | no | The calling name doubles the first syllable rather than taking an ending. |
607
+ | `data.callingNames.closings[].usual` | one of man, woman, either | yes | Whose name it usually makes. |
608
+ | `data.callingNames.minSyllables` | a whole number | yes | The fewest syllables a given name has that the pages give a calling name. |
495
609
 
496
610
  **System mappings**
497
611
 
@@ -211,6 +211,16 @@ types:
211
211
  - fields
212
212
  - words
213
213
  - affixes
214
+ - tongues
215
+ - register
216
+ - retired
217
+ - scope
218
+ - sounds
219
+ - soundChanges
220
+ - elements
221
+ - roots
222
+ - cognates
223
+ - callingNames
214
224
  subTypes:
215
225
  - social
216
226
  - nature
@@ -113,6 +113,7 @@ import { addressSlug, canonicalKey } from "./content-address.mjs";
113
113
  import { isAddressTuple, ownDocumentSystem, readCanonicalKey, renderAddress } from "./address.mjs";
114
114
  import { NOTE_SYSTEM } from "./systems.mjs";
115
115
  import { dictionaryAndTermRows, serializeRows } from "./dictionary-rows.mjs";
116
+ import { attachCitations } from "./word-citations.mjs";
116
117
  import { assetAddressIndex } from "./art-fields.mjs";
117
118
  import { embedRole } from "./content-embeds.mjs";
118
119
  // One reader for a note's anchors, shared with the link checker and with the
@@ -1112,6 +1113,8 @@ export function collectContentIndex(
1112
1113
  contentPackage,
1113
1114
  );
1114
1115
 
1116
+ // Each recorded note with its body, for the words its prose cites.
1117
+ const bodies = [];
1115
1118
  for (const { frontmatter, body, bodyLine, absPath } of parsedNotes) {
1116
1119
  // Before the index derives anything onto the frontmatter, so a later
1117
1120
  // pass reads the note as authored.
@@ -1120,20 +1123,20 @@ export function collectContentIndex(
1120
1123
  applyComputedBeingAge(fm, present, dates);
1121
1124
  const relPath = path.relative(contentBase, absPath);
1122
1125
  try {
1123
- records.push(
1124
- ...indexRecordsForNote({
1125
- frontmatter: fm,
1126
- relPath,
1127
- absPath,
1128
- contentPackage,
1129
- body,
1130
- bodyLine,
1131
- manifest,
1132
- addressContext: decodeContext,
1133
- dateContext: dates,
1134
- resolveRole,
1135
- }),
1136
- );
1126
+ const made = indexRecordsForNote({
1127
+ frontmatter: fm,
1128
+ relPath,
1129
+ absPath,
1130
+ contentPackage,
1131
+ body,
1132
+ bodyLine,
1133
+ manifest,
1134
+ addressContext: decodeContext,
1135
+ dateContext: dates,
1136
+ resolveRole,
1137
+ });
1138
+ records.push(...made);
1139
+ bodies.push({ record: made[0], body });
1137
1140
  } catch (err) {
1138
1141
  if (fm.shortcode && !isAddressSegment(fm.shortcode) && err.keyPath) {
1139
1142
  err.identity = { type: fm.type, shortcode: fm.shortcode };
@@ -1176,6 +1179,10 @@ export function collectContentIndex(
1176
1179
  }
1177
1180
  }
1178
1181
 
1182
+ // The words each note's prose cites, read once every language's words
1183
+ // are recorded; the index keeps the citing Addresses and no text.
1184
+ attachCitations(records, bodies);
1185
+
1179
1186
  // Every note record exists and every Address in it is a tuple, so a parent
1180
1187
  // is found by its canonical address. Before the sort, which reads nothing
1181
1188
  // the pass writes.
@@ -21,8 +21,9 @@
21
21
  * column is read where the query selects it. The output is Markdown, so every
22
22
  * surface sets it as it sets a note:
23
23
  *
24
- * - **the key**, once, at the head: the abbreviations this rendering uses,
25
- * each with its expansion, then the common mark where an entry carries it;
24
+ * - **the key**, once, at the head unless the fence sets `key=false`: the abbreviations this rendering uses,
25
+ * each with its expansion, then the common mark where an entry carries it.
26
+ * A fence setting `key=only` prints the key alone;
26
27
  * - **a heading per letter**, from `letter`, at the fence's `section-level`;
27
28
  * - **one paragraph per entry**: the common mark, the bold headword, the
28
29
  * pronunciation between slashes, the language tag (and for a word its
@@ -92,6 +93,8 @@ function sentence(text) {
92
93
  * @property {object} [addressContext] - Address resolution context.
93
94
  * @property {(address: string) => string|undefined} [labelOf] - A note's
94
95
  * `name.full`, by its Address.
96
+ * @property {boolean|"only"} [showKey=true] - Whether the key is printed;
97
+ * `"only"` prints the key and nothing else.
95
98
  * @property {string} [pageLanguage] - The language of the page the fence is
96
99
  * on, which no entry is tagged with.
97
100
  */
@@ -189,6 +192,7 @@ function render(
189
192
  sectionLevel = 2,
190
193
  addressContext,
191
194
  labelOf = () => undefined,
195
+ showKey = true,
192
196
  pageLanguage,
193
197
  },
194
198
  words,
@@ -284,7 +288,9 @@ function render(
284
288
  if (usedModifiers.has(modifier.token))
285
289
  key.push(`_${modifier.abbreviation}_ ${modifier.expansion}`);
286
290
  if (anyCommon) key.push(`${COMMON_MARK} ${COMMON_KEY}`);
287
- if (key.length) paragraphs.unshift(`**Key:** ${key.join("; ")}.`);
291
+ const line = key.length ? `**Key:** ${key.join("; ")}.` : "";
292
+ if (showKey === "only") return line;
293
+ if (showKey && line) paragraphs.unshift(line);
288
294
  return paragraphs.join("\n\n");
289
295
  }
290
296
 
@@ -53,7 +53,8 @@ import { parseAddress, renderAddress } from "./address.mjs";
53
53
  import { glossaryLanguage } from "./glossary-language.mjs";
54
54
  import { isNoteRecord } from "./index-records.mjs";
55
55
  import { parseWordClass, WORD_CLASS_BASES } from "./word-classes.mjs";
56
- import { isLanguageRecord, pieceGlosses } from "./word-rows.mjs";
56
+ import { citationLookup, isLanguageRecord, lineageChain, pieceGlosses } from "./word-rows.mjs";
57
+ import { glossSenses } from "./word-terms.mjs";
57
58
 
58
59
  /** Every column of the `dictionary` relation, in order. */
59
60
  export const DICTIONARY_COLUMNS = Object.freeze([
@@ -224,17 +225,14 @@ export function dictionaryAndTermRows(records, all = records) {
224
225
  const full = record.name?.full;
225
226
  return typeof full === "string" && full ? full : null;
226
227
  };
227
- const lineage = (language) => {
228
- const chain = [];
229
- const seen = new Set();
230
- for (let current = language; current && languages.has(current) && !seen.has(current);) {
231
- seen.add(current);
232
- chain.push(current);
233
- const family = languages.get(current).data?.family;
234
- current = typeof family === "string" && family ? family : undefined;
235
- }
236
- return chain;
237
- };
228
+ const lineage = (language) =>
229
+ lineageChain(language, {
230
+ has: (key) => languages.has(key),
231
+ parentOf: (key) => {
232
+ const family = languages.get(key).data?.family;
233
+ return typeof family === "string" && family ? family : undefined;
234
+ },
235
+ });
238
236
  const ownWords = new Map();
239
237
  for (const [key, record] of languages) {
240
238
  const list = [];
@@ -470,7 +468,7 @@ export function dictionaryAndTermRows(records, all = records) {
470
468
  };
471
469
  const source = isMap(word.source) ? word.source : {};
472
470
  const built = Array.isArray(word.built) ? word.built.map(String) : [];
473
- const glossOf = pieceGlosses(languages.get(statedIn)?.data);
471
+ const glossOf = pieceGlosses(...lineage(statedIn).map((key) => languages.get(key).data));
474
472
  const out = {
475
473
  ...blank,
476
474
  kind: typeof source.kind === "string" ? source.kind : null,
@@ -484,9 +482,10 @@ export function dictionaryAndTermRows(records, all = records) {
484
482
  return ETYMOLOGY_KEYS.some((key) => out[key] !== null) ? out : null;
485
483
  };
486
484
 
485
+ const citedBy = citationLookup(byKey.values());
487
486
  const dictionary = [];
488
487
  for (const { language, name, found, marks } of wordRows.values()) {
489
- const { word, depth } = found;
488
+ const { word, depth, statedIn } = found;
490
489
  const nameSort =
491
490
  marked(marks, "name_sort") ??
492
491
  (typeof word.name_sort === "string" && word.name_sort ? word.name_sort : name);
@@ -501,17 +500,8 @@ export function dictionaryAndTermRows(records, all = records) {
501
500
  (typeof word.pronunciation === "string" ? word.pronunciation : null),
502
501
  class: typeof word.class === "string" ? word.class : null,
503
502
  etymology: etymologyOf(found),
504
- senses:
505
- typeof word.gloss === "string" && word.gloss.trim() ?
506
- [{ text: word.gloss, bodies: [] }]
507
- : [],
508
- usage: [
509
- ...new Set(
510
- (Array.isArray(word.attested) ? word.attested : []).filter(
511
- (value) => typeof value === "string" && citable(value),
512
- ),
513
- ),
514
- ].sort(compare),
503
+ senses: glossSenses(word.gloss).map((text) => ({ text, bodies: [] })),
504
+ usage: [...new Set(citedBy(statedIn, word.form).filter(citable))].sort(compare),
515
505
  common: marks.some((one) => one.entry.common === true),
516
506
  depth,
517
507
  });
@@ -62,6 +62,7 @@ export const DERIVED_KEYS = Object.freeze([
62
62
  "documents",
63
63
  "asset",
64
64
  "resolvedDates",
65
+ "citations",
65
66
  ]);
66
67
 
67
68
  /**