@heroiclands/package-build 23.7.0 → 23.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,13 +15,15 @@
15
15
  * The keys a language note states beside its words: the register of the names
16
16
  * the setting gives in the language's reach, the tags the register uses, the
17
17
  * forms it does not write, the notes the register covers, the letters and sound
18
- * rules, the sound changes, the name elements, the roots and the cognates.
18
+ * rules, the sound changes, the name elements, the roots, the cognates, the
19
+ * forms older than the rules and the negative particle.
19
20
  *
20
21
  * A leaf module, importing nothing: the note vocabulary reads these
21
22
  * declarations as it loads, and `language-data.mjs` checks what the values
22
23
  * mean. Every closed list here — the edges, element positions, register
23
- * kinds, stress rules, joins, marks, onsets, harmony sets and calling-name
24
- * uses — holds the labels the setting's own tables use, one word for each.
24
+ * kinds, stress rules, joins, marks, onsets, harmony sets, cluster uses and
25
+ * calling-name uses — holds the labels the setting's own tables use, one word
26
+ * for each.
25
27
  *
26
28
  * @module
27
29
  */
@@ -38,6 +40,9 @@ export const LANGUAGE_DATA_KEYS = Object.freeze([
38
40
  "roots",
39
41
  "cognates",
40
42
  "callingNames",
43
+ "older",
44
+ "negation",
45
+ "naming",
41
46
  ]);
42
47
 
43
48
  /**
@@ -89,9 +94,37 @@ export const ANY_SOUND = "any";
89
94
  */
90
95
  export const ELEMENT_POSITIONS = Object.freeze(["opening", "closing", "either", "link"]);
91
96
 
92
- /** What a register name is, where a language sorts its names by kind. */
97
+ /**
98
+ * What a register name is, where a language sorts its names by kind, and the
99
+ * kind of name an element builds.
100
+ */
93
101
  export const REGISTER_KINDS = Object.freeze(["byname", "given", "place"]);
94
102
 
103
+ /**
104
+ * The class of name a naming shape or edge holds for: every name, a given or a
105
+ * clan name, or a name by how it is built — `bound` a stem and an ending,
106
+ * `compound` elements alone.
107
+ */
108
+ export const NAME_CLASSES = Object.freeze(["name", "given", "clan", "bound", "compound"]);
109
+
110
+ /** The class of name a naming edge holds for where it states none. */
111
+ export const ANY_NAME = "name";
112
+
113
+ /**
114
+ * What a place name takes first from what it is held from: a name-stem, a
115
+ * god's name, a founder's given name, or one of the listed elements.
116
+ */
117
+ export const HELD_TAKES = Object.freeze(["stem", "godName", "givenName", "element"]);
118
+
119
+ /** The `takes` values that are a name a place name shapes. */
120
+ export const HELD_NAMES = Object.freeze(["godName", "givenName"]);
121
+
122
+ /** How a name is clipped where a place name takes it. */
123
+ export const HELD_CLIPS = Object.freeze(["first"]);
124
+
125
+ /** How often a group of clusters stands inside a word. */
126
+ export const CLUSTER_USES = Object.freeze(["common", "sparing"]);
127
+
95
128
  /** Where a language's stress falls. */
96
129
  export const STRESS_RULES = Object.freeze([
97
130
  "first syllable",
@@ -192,6 +225,12 @@ export const REGISTER_FIELDS = Object.freeze([
192
225
  entries: STRINGS,
193
226
  describe: "The pieces the name is built from, in order, as a word's `built` writes them.",
194
227
  }),
228
+ Object.freeze({
229
+ name: "gloss",
230
+ kind: "string",
231
+ shape: "a string",
232
+ describe: "What the name means, where the pages give its sense.",
233
+ }),
195
234
  Object.freeze({
196
235
  name: "why",
197
236
  kind: "string",
@@ -320,9 +359,14 @@ export const LETTER_FIELDS = Object.freeze([
320
359
  Object.freeze({
321
360
  name: "like",
322
361
  kind: "string",
323
- required: true,
324
362
  shape: "a string",
325
- describe: "What they sound like.",
363
+ describe: "What they sound like; absent where the row states only their kind and place.",
364
+ }),
365
+ Object.freeze({
366
+ name: "place",
367
+ kind: "string",
368
+ shape: "a string, such as `lips` or `tongue-tip`",
369
+ describe: "Where in the mouth they are made.",
326
370
  }),
327
371
  Object.freeze({
328
372
  name: "tongue",
@@ -359,6 +403,38 @@ export const EDGE_FIELDS = Object.freeze([
359
403
  }),
360
404
  ]);
361
405
 
406
+ /**
407
+ * The keys of one `data.sounds.clusters.groups` entry: clusters of one kind,
408
+ * and how often they stand.
409
+ *
410
+ * @type {readonly import("./data-keys.mjs").InnerKeySpec[]}
411
+ */
412
+ export const CLUSTER_GROUP_FIELDS = Object.freeze([
413
+ Object.freeze({
414
+ name: "what",
415
+ kind: "string",
416
+ required: true,
417
+ shape: "a string, such as `a nasal and a fricative`",
418
+ describe: "What the clusters of the group are made of.",
419
+ }),
420
+ Object.freeze({
421
+ name: "clusters",
422
+ kind: "list",
423
+ required: true,
424
+ shape: "a list of clusters",
425
+ entries: STRINGS,
426
+ describe: "The clusters, as written; a digraph counts as one consonant.",
427
+ }),
428
+ Object.freeze({
429
+ name: "use",
430
+ kind: "string",
431
+ required: true,
432
+ allowed: CLUSTER_USES,
433
+ shape: `one of ${CLUSTER_USES.join(", ")}`,
434
+ describe: "How often the group's clusters stand inside a word.",
435
+ }),
436
+ ]);
437
+
362
438
  /**
363
439
  * The keys of a language's `data.sounds.clusters`.
364
440
  *
@@ -372,6 +448,19 @@ export const CLUSTER_FIELDS = Object.freeze([
372
448
  shape: "a whole number",
373
449
  describe: "The most consonants that stand together inside a word.",
374
450
  }),
451
+ Object.freeze({
452
+ name: "groups",
453
+ kind: "list",
454
+ shape: "list of `{ what, clusters, use }`",
455
+ entries: Object.freeze({
456
+ kind: "map",
457
+ shape: "a map — `{ what, clusters, use }`",
458
+ fields: CLUSTER_GROUP_FIELDS,
459
+ }),
460
+ describe:
461
+ "The clusters that may stand inside a word, in groups; a language stating them " +
462
+ "states no `innerCluster` edge.",
463
+ }),
375
464
  ]);
376
465
 
377
466
  /**
@@ -589,6 +678,15 @@ export const HARMONY_FIELDS = Object.freeze([
589
678
  shape: `one of ${HARMONY_SETS.join(", ")}`,
590
679
  describe: "The set a word of neutral vowels alone counts as.",
591
680
  }),
681
+ Object.freeze({
682
+ name: "partners",
683
+ kind: "map",
684
+ shape: "a map of vowels to front vowels",
685
+ values: Object.freeze({ kind: "string", shape: "a front vowel" }),
686
+ describe:
687
+ "The front vowel each vowel turns to in an affix's front form, keyed by the vowel; " +
688
+ "every key is a vowel of the harmony and every value one of its `front` vowels.",
689
+ }),
592
690
  ]);
593
691
 
594
692
  /**
@@ -658,7 +756,7 @@ export const SYLLABLE_FIELDS = Object.freeze([
658
756
  Object.freeze({
659
757
  name: "harmony",
660
758
  kind: "map",
661
- shape: "a map — `{ back, front, neutral?, neutralAs? }`",
759
+ shape: "a map — `{ back, front, neutral?, neutralAs?, partners? }`",
662
760
  fields: HARMONY_FIELDS,
663
761
  describe: "The vowel harmony a word keeps.",
664
762
  }),
@@ -729,6 +827,42 @@ export const FRAME_FIELDS = Object.freeze([
729
827
  }),
730
828
  ]);
731
829
 
830
+ /**
831
+ * The keys of one `data.sounds.mutations` entry: a sound and what it becomes
832
+ * where a named mutation holds.
833
+ *
834
+ * @type {readonly import("./data-keys.mjs").InnerKeySpec[]}
835
+ */
836
+ export const MUTATION_FIELDS = Object.freeze([
837
+ Object.freeze({
838
+ name: "mutation",
839
+ kind: "string",
840
+ required: true,
841
+ shape: "a string, such as `wearing`",
842
+ describe: "The mutation's name; its rows share it, and `data.negation` names it.",
843
+ }),
844
+ Object.freeze({
845
+ name: "sound",
846
+ kind: "string",
847
+ required: true,
848
+ shape: "a sound as written, such as `p`",
849
+ describe: "The sound as it stands where the mutation does not hold; once per mutation.",
850
+ }),
851
+ Object.freeze({
852
+ name: "becomes",
853
+ kind: "string",
854
+ required: true,
855
+ shape: "a sound as written, such as `v`",
856
+ describe: "What the sound becomes where the mutation holds.",
857
+ }),
858
+ Object.freeze({
859
+ name: "example",
860
+ kind: "string",
861
+ shape: "a string",
862
+ describe: "A word that shows it.",
863
+ }),
864
+ ]);
865
+
732
866
  /**
733
867
  * The keys of a language's `data.sounds`.
734
868
  *
@@ -760,7 +894,7 @@ export const SOUND_FIELDS = Object.freeze([
760
894
  Object.freeze({
761
895
  name: "clusters",
762
896
  kind: "map",
763
- shape: "a map — `{ max }`",
897
+ shape: "a map — `{ max, groups? }`",
764
898
  fields: CLUSTER_FIELDS,
765
899
  describe: "How many consonants may stand together.",
766
900
  }),
@@ -856,6 +990,19 @@ export const SOUND_FIELDS = Object.freeze([
856
990
  }),
857
991
  describe: "Marks and spellings a word is read through before the sound rules hold it.",
858
992
  }),
993
+ Object.freeze({
994
+ name: "mutations",
995
+ kind: "list",
996
+ shape: "list of `{ mutation, sound, becomes, example? }`",
997
+ entries: Object.freeze({
998
+ kind: "map",
999
+ shape: "a map — `{ mutation, sound, becomes, example? }`",
1000
+ fields: MUTATION_FIELDS,
1001
+ }),
1002
+ describe:
1003
+ "The sounds a word changes where a named mutation holds, one entry per sound, such " +
1004
+ "as a stop worn to a fricative or a consonant voiced inside a compound.",
1005
+ }),
859
1006
  ]);
860
1007
 
861
1008
  /**
@@ -914,6 +1061,13 @@ export const SOUND_CHANGE_FIELDS = Object.freeze([
914
1061
  shape: "a language skill Address",
915
1062
  describe: "The language whose words the steps make.",
916
1063
  }),
1064
+ Object.freeze({
1065
+ name: "takes",
1066
+ kind: "string",
1067
+ shape: "a case, such as `accusative`",
1068
+ describe:
1069
+ "The form of the older word the steps start from; its citation form where absent.",
1070
+ }),
917
1071
  Object.freeze({
918
1072
  name: "steps",
919
1073
  kind: "list",
@@ -955,6 +1109,15 @@ export const ELEMENT_FIELDS = Object.freeze([
955
1109
  shape: `one of ${ELEMENT_POSITIONS.join(", ")}`,
956
1110
  describe: "Where in a name the element stands.",
957
1111
  }),
1112
+ Object.freeze({
1113
+ name: "kind",
1114
+ kind: "string",
1115
+ allowed: REGISTER_KINDS,
1116
+ shape: `one of ${REGISTER_KINDS.join(", ")}`,
1117
+ describe:
1118
+ "The kind of name the element builds, in a language that keeps one set of elements " +
1119
+ "per kind; every kind where absent.",
1120
+ }),
958
1121
  Object.freeze({
959
1122
  name: "sense",
960
1123
  kind: "string",
@@ -969,6 +1132,20 @@ export const ELEMENT_FIELDS = Object.freeze([
969
1132
  entries: STRINGS,
970
1133
  describe: "The names the element is read from.",
971
1134
  }),
1135
+ Object.freeze({
1136
+ name: "word",
1137
+ kind: "string",
1138
+ shape: "a form of the language's words",
1139
+ describe:
1140
+ "The word the element is the stem of, a form of `data.words` of the language or an " +
1141
+ "ancestor.",
1142
+ }),
1143
+ Object.freeze({
1144
+ name: "genitive",
1145
+ kind: "string",
1146
+ shape: "the element as written, such as `-borgar`",
1147
+ describe: "The element in the genitive, where a name governing another word takes it.",
1148
+ }),
972
1149
  ]);
973
1150
 
974
1151
  /**
@@ -1087,6 +1264,317 @@ export const CALLING_NAME_FIELDS = Object.freeze([
1087
1264
  }),
1088
1265
  ]);
1089
1266
 
1267
+ /**
1268
+ * The keys of one `data.older` entry.
1269
+ *
1270
+ * @type {readonly import("./data-keys.mjs").InnerKeySpec[]}
1271
+ */
1272
+ export const OLDER_FIELDS = Object.freeze([
1273
+ Object.freeze({
1274
+ name: "form",
1275
+ kind: "string",
1276
+ required: true,
1277
+ shape: "a form as the setting writes it",
1278
+ describe: "A word or name whose shape the language's rules do not make.",
1279
+ }),
1280
+ Object.freeze({
1281
+ name: "gloss",
1282
+ kind: "string",
1283
+ shape: "a string",
1284
+ describe: "What it means.",
1285
+ }),
1286
+ Object.freeze({
1287
+ name: "layer",
1288
+ kind: "string",
1289
+ shape: "a string, such as `Primordial`",
1290
+ describe: "The historical layer it belongs to.",
1291
+ }),
1292
+ ]);
1293
+
1294
+ /**
1295
+ * The keys of a language's `data.negation`.
1296
+ *
1297
+ * @type {readonly import("./data-keys.mjs").InnerKeySpec[]}
1298
+ */
1299
+ export const NEGATION_FIELDS = Object.freeze([
1300
+ Object.freeze({
1301
+ name: "particle",
1302
+ kind: "string",
1303
+ required: true,
1304
+ shape: "a form of the language's words",
1305
+ describe:
1306
+ "The particle that stands before a verb to negate it, a form of `data.words` of the " +
1307
+ "language or an ancestor.",
1308
+ }),
1309
+ Object.freeze({
1310
+ name: "mutation",
1311
+ kind: "string",
1312
+ shape: "a mutation of `data.sounds.mutations`",
1313
+ describe: "The mutation the negated verb takes, named in `data.sounds.mutations`.",
1314
+ }),
1315
+ ]);
1316
+
1317
+ /**
1318
+ * The keys of a range: the least and the most.
1319
+ *
1320
+ * @param {string} kind - `integer` or `number`.
1321
+ * @param {string} what - What the range counts.
1322
+ * @returns {readonly import("./data-keys.mjs").InnerKeySpec[]}
1323
+ */
1324
+ const rangeFields = (kind, what) =>
1325
+ Object.freeze([
1326
+ Object.freeze({
1327
+ name: "min",
1328
+ kind,
1329
+ required: true,
1330
+ shape: kind === "integer" ? "a whole number" : "a number",
1331
+ describe: `The fewest ${what}.`,
1332
+ }),
1333
+ Object.freeze({
1334
+ name: "max",
1335
+ kind,
1336
+ required: true,
1337
+ shape: kind === "integer" ? "a whole number" : "a number",
1338
+ describe: `The most ${what}; never below \`min\`.`,
1339
+ }),
1340
+ ]);
1341
+
1342
+ /**
1343
+ * The keys of one `data.naming.shapes` entry: how long a class of name runs.
1344
+ *
1345
+ * @type {readonly import("./data-keys.mjs").InnerKeySpec[]}
1346
+ */
1347
+ export const NAME_SHAPE_FIELDS = Object.freeze([
1348
+ Object.freeze({
1349
+ name: "of",
1350
+ kind: "string",
1351
+ required: true,
1352
+ allowed: NAME_CLASSES,
1353
+ shape: `one of ${NAME_CLASSES.join(", ")}`,
1354
+ describe: "The class of name the shape holds for; once per class.",
1355
+ }),
1356
+ Object.freeze({
1357
+ name: "syllables",
1358
+ kind: "map",
1359
+ shape: "a map — `{ min, max }`",
1360
+ fields: rangeFields("integer", "syllables a name of the class runs to"),
1361
+ describe: "How many syllables a name of the class runs to.",
1362
+ }),
1363
+ Object.freeze({
1364
+ name: "perVowel",
1365
+ kind: "map",
1366
+ shape: "a map — `{ min, max }`",
1367
+ fields: rangeFields("number", "consonants a name of the class carries to each vowel"),
1368
+ describe:
1369
+ "How many consonants a name of the class carries to each vowel; a shape states this, " +
1370
+ "`syllables`, or both.",
1371
+ }),
1372
+ ]);
1373
+
1374
+ /**
1375
+ * The keys of one `data.naming.edges` entry: the sounds a name may open or
1376
+ * close on, where a name keeps edges ordinary words do not.
1377
+ *
1378
+ * @type {readonly import("./data-keys.mjs").InnerKeySpec[]}
1379
+ */
1380
+ export const NAME_EDGE_FIELDS = Object.freeze([
1381
+ Object.freeze({
1382
+ name: "edge",
1383
+ kind: "string",
1384
+ required: true,
1385
+ allowed: EDGE_KINDS,
1386
+ shape: `one of ${EDGE_KINDS.join(", ")}`,
1387
+ describe: "Which edge of a name the sounds stand at.",
1388
+ }),
1389
+ Object.freeze({
1390
+ name: "sounds",
1391
+ kind: "string-or-list",
1392
+ required: true,
1393
+ allowed: Object.freeze([ANY_SOUND]),
1394
+ shape: `a list of sounds, or \`${ANY_SOUND}\``,
1395
+ entries: STRINGS,
1396
+ describe: `The sounds, as written; \`${ANY_SOUND}\` for every one, and an empty list for none.`,
1397
+ }),
1398
+ Object.freeze({
1399
+ name: "vowel",
1400
+ kind: "boolean",
1401
+ shape: "`true` or `false`",
1402
+ describe: "Whether a vowel may stand at the edge too; `false` where unstated.",
1403
+ }),
1404
+ Object.freeze({
1405
+ name: "of",
1406
+ kind: "string",
1407
+ allowed: NAME_CLASSES,
1408
+ shape: `one of ${NAME_CLASSES.join(", ")}`,
1409
+ describe: `The class of name the edge holds for; \`${ANY_NAME}\`, every name, where absent.`,
1410
+ }),
1411
+ ]);
1412
+
1413
+ /**
1414
+ * The keys of one `data.naming.draws` entry: the element kinds a kind of name
1415
+ * is built from.
1416
+ *
1417
+ * @type {readonly import("./data-keys.mjs").InnerKeySpec[]}
1418
+ */
1419
+ export const NAME_DRAW_FIELDS = Object.freeze([
1420
+ Object.freeze({
1421
+ name: "kind",
1422
+ kind: "string",
1423
+ required: true,
1424
+ allowed: REGISTER_KINDS,
1425
+ shape: `one of ${REGISTER_KINDS.join(", ")}`,
1426
+ describe: "The kind of name; once per kind.",
1427
+ }),
1428
+ Object.freeze({
1429
+ name: "elements",
1430
+ kind: "list",
1431
+ required: true,
1432
+ shape: "a list of element kinds",
1433
+ entries: Object.freeze({
1434
+ kind: "string",
1435
+ allowed: REGISTER_KINDS,
1436
+ shape: `one of ${REGISTER_KINDS.join(", ")}`,
1437
+ }),
1438
+ describe: "The kinds of element, as `data.elements` states them, the name is built from.",
1439
+ }),
1440
+ ]);
1441
+
1442
+ /**
1443
+ * The keys of one `data.naming.heldFrom` entry: what a place name takes first
1444
+ * from what the place is held from.
1445
+ *
1446
+ * @type {readonly import("./data-keys.mjs").InnerKeySpec[]}
1447
+ */
1448
+ export const HELD_FROM_FIELDS = Object.freeze([
1449
+ Object.freeze({
1450
+ name: "source",
1451
+ kind: "string",
1452
+ required: true,
1453
+ shape: "a string, such as `a founder`",
1454
+ describe: "What the place is held from.",
1455
+ }),
1456
+ Object.freeze({
1457
+ name: "takes",
1458
+ kind: "string",
1459
+ required: true,
1460
+ allowed: HELD_TAKES,
1461
+ shape: `one of ${HELD_TAKES.join(", ")}`,
1462
+ describe:
1463
+ "What stands first: a name-stem in any grade, a god's name, a founder's given name, " +
1464
+ "or one of `elements`.",
1465
+ }),
1466
+ Object.freeze({
1467
+ name: "clip",
1468
+ kind: "string",
1469
+ allowed: HELD_CLIPS,
1470
+ shape: `one of ${HELD_CLIPS.join(", ")}`,
1471
+ describe: "How the name is clipped: `first`, to its first element; whole where absent.",
1472
+ }),
1473
+ Object.freeze({
1474
+ name: "genitive",
1475
+ kind: "list",
1476
+ shape: "a list of endings",
1477
+ entries: STRINGS,
1478
+ describe: "The genitive endings, one of which stands at the seam after the name.",
1479
+ }),
1480
+ Object.freeze({
1481
+ name: "elements",
1482
+ kind: "list",
1483
+ shape: "a list of elements",
1484
+ entries: STRINGS,
1485
+ describe: "The elements that may stand first, for a row that takes an `element`.",
1486
+ }),
1487
+ ]);
1488
+
1489
+ /**
1490
+ * The keys of one `data.naming.nearName.examples` entry.
1491
+ *
1492
+ * @type {readonly import("./data-keys.mjs").InnerKeySpec[]}
1493
+ */
1494
+ export const NEAR_NAME_EXAMPLE_FIELDS = Object.freeze([
1495
+ Object.freeze({
1496
+ name: "near",
1497
+ kind: "string",
1498
+ required: true,
1499
+ shape: "a near name, such as `Anlâ`",
1500
+ describe: "The near name.",
1501
+ }),
1502
+ Object.freeze({
1503
+ name: "given",
1504
+ kind: "string",
1505
+ required: true,
1506
+ shape: "a given name",
1507
+ describe: "The given name it is the near name of.",
1508
+ }),
1509
+ ]);
1510
+
1511
+ /**
1512
+ * The keys of a language's `data.naming.nearName`.
1513
+ *
1514
+ * @type {readonly import("./data-keys.mjs").InnerKeySpec[]}
1515
+ */
1516
+ export const NEAR_NAME_FIELDS = Object.freeze([
1517
+ Object.freeze({
1518
+ name: "minSyllables",
1519
+ kind: "integer",
1520
+ required: true,
1521
+ shape: "a whole number",
1522
+ describe: "The fewest syllables a given name has that carries a near name.",
1523
+ }),
1524
+ Object.freeze({
1525
+ name: "examples",
1526
+ kind: "list",
1527
+ shape: "list of `{ near, given }`",
1528
+ entries: Object.freeze({
1529
+ kind: "map",
1530
+ shape: "a map — `{ near, given }`",
1531
+ fields: NEAR_NAME_EXAMPLE_FIELDS,
1532
+ }),
1533
+ describe: "Worked near names, each beside its given name.",
1534
+ }),
1535
+ ]);
1536
+
1537
+ /** A list of maps, as an inner key's declaration. */
1538
+ const innerList = (name, fields, describe) => {
1539
+ const keys = fields.map((field) => (field.required ? field.name : `${field.name}?`)).join(", ");
1540
+ return Object.freeze({
1541
+ name,
1542
+ kind: "list",
1543
+ shape: `list of \`{ ${keys} }\``,
1544
+ entries: Object.freeze({ kind: "map", shape: `a map — \`{ ${keys} }\``, fields }),
1545
+ describe,
1546
+ });
1547
+ };
1548
+
1549
+ /**
1550
+ * The keys of a language's `data.naming`: the parameters its names keep
1551
+ * beyond the rules its words keep.
1552
+ *
1553
+ * @type {readonly import("./data-keys.mjs").InnerKeySpec[]}
1554
+ */
1555
+ export const NAMING_FIELDS = Object.freeze([
1556
+ innerList("shapes", NAME_SHAPE_FIELDS, "How long each class of name runs."),
1557
+ innerList(
1558
+ "edges",
1559
+ NAME_EDGE_FIELDS,
1560
+ "The sounds a name may open and close on, where names keep edges ordinary words do not; " +
1561
+ "an edge stands once for each class of name.",
1562
+ ),
1563
+ innerList("draws", NAME_DRAW_FIELDS, "The element kinds each kind of name is built from."),
1564
+ innerList(
1565
+ "heldFrom",
1566
+ HELD_FROM_FIELDS,
1567
+ "What a place name takes first, by what the place is held from.",
1568
+ ),
1569
+ Object.freeze({
1570
+ name: "nearName",
1571
+ kind: "map",
1572
+ shape: "a map — `{ minSyllables, examples? }`",
1573
+ fields: NEAR_NAME_FIELDS,
1574
+ describe: "The near name a long given name carries.",
1575
+ }),
1576
+ ]);
1577
+
1090
1578
  /**
1091
1579
  * A list of maps, as a `data` field's declaration.
1092
1580
  *
@@ -1138,7 +1626,7 @@ export const LANGUAGE_DATA_FIELDS = Object.freeze([
1138
1626
  kind: "map",
1139
1627
  shape:
1140
1628
  "a map — `{ letters?, edges?, clusters?, stress?, finals?, syllables?, joining?, " +
1141
- "joins?, marks?, skeleton?, frames?, readPast? }`",
1629
+ "joins?, marks?, skeleton?, frames?, readPast?, mutations? }`",
1142
1630
  fields: SOUND_FIELDS,
1143
1631
  describe:
1144
1632
  "The letters the language writes and the rules its words keep. A language skill " +
@@ -1163,6 +1651,27 @@ export const LANGUAGE_DATA_FIELDS = Object.freeze([
1163
1651
  fields: CALLING_NAME_FIELDS,
1164
1652
  describe: "The short name a long given name is called by. A language skill note only.",
1165
1653
  }),
1654
+ listOfMaps(
1655
+ "older",
1656
+ OLDER_FIELDS,
1657
+ "The words and names older than the language's rules, which no sound or name rule holds.",
1658
+ ),
1659
+ Object.freeze({
1660
+ name: "negation",
1661
+ kind: "map",
1662
+ shape: "a map — `{ particle, mutation? }`",
1663
+ fields: NEGATION_FIELDS,
1664
+ describe: "How a verb is negated. A language skill note only.",
1665
+ }),
1666
+ Object.freeze({
1667
+ name: "naming",
1668
+ kind: "map",
1669
+ shape: "a map — `{ shapes?, edges?, draws?, heldFrom?, nearName? }`",
1670
+ fields: NAMING_FIELDS,
1671
+ describe:
1672
+ "The shapes, edges and sources the language's names keep beyond its words' rules. A " +
1673
+ "language skill note only.",
1674
+ }),
1166
1675
  ]);
1167
1676
 
1168
1677
  /** The keys of {@link TONGUE_FIELDS}, in declared order. */
@@ -1199,5 +1708,11 @@ export const CALLING_CLOSING_KEYS = Object.freeze(
1199
1708
  export const ELEMENT_KEYS = Object.freeze(ELEMENT_FIELDS.map((field) => field.name));
1200
1709
  /** The keys of {@link ROOT_FIELDS}, in declared order. */
1201
1710
  export const ROOT_KEYS = Object.freeze(ROOT_FIELDS.map((field) => field.name));
1711
+ /** The keys of {@link MUTATION_FIELDS}, in declared order. */
1712
+ export const MUTATION_KEYS = Object.freeze(MUTATION_FIELDS.map((field) => field.name));
1713
+ /** The keys of {@link CLUSTER_GROUP_FIELDS}, in declared order. */
1714
+ export const CLUSTER_GROUP_KEYS = Object.freeze(CLUSTER_GROUP_FIELDS.map((field) => field.name));
1715
+ /** The keys of {@link OLDER_FIELDS}, in declared order. */
1716
+ export const OLDER_KEYS = Object.freeze(OLDER_FIELDS.map((field) => field.name));
1202
1717
  /** The keys of {@link SCOPE_FIELDS}, in declared order. */
1203
1718
  export const SCOPE_KINDS = Object.freeze(SCOPE_FIELDS.map((field) => field.name));