@gmb/bitmark-parser-generator 5.35.0 → 5.36.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/dist/cli/main.js CHANGED
@@ -1316,6 +1316,7 @@ var propertyKeys = {
1316
1316
  property_dateEnd: "@dateEnd",
1317
1317
  property_decimalPlaces: "@decimalPlaces",
1318
1318
  property_deeplink: "@deeplink",
1319
+ property_displayName: "@displayName",
1319
1320
  property_diffContext: "@diffContext",
1320
1321
  property_diffOp: "@diffOp",
1321
1322
  property_diffRef: "@diffRef",
@@ -2456,9 +2457,30 @@ var CARDSETS = {
2456
2457
  [CardSetConfigKey.definitionList]: {
2457
2458
  jsonKey: "definitions",
2458
2459
  exportJsonKey: { definitions: "$" },
2460
+ // PLAN-141 F1 (NISO import): each <def-item> is one card; the sides
2461
+ // read <term>/<def>; the enclosing <legend>'s <title> lands on the
2462
+ // term side's heading tag ([#Key] header card).
2463
+ // PLAN-141 F3: a <tbx:langSet> is ALSO one card (a terminology entry —
2464
+ // its enclosing <tbx:termEntry> is a transparent claim wrapper); its
2465
+ // children compose the term/definition sides via the side rules below.
2466
+ mappingKeys: {
2467
+ "xml-niso-iec": [
2468
+ { "@el": "def-item", "@children": "$" },
2469
+ { "@el": "tbx:langSet", "@children": "$" }
2470
+ ]
2471
+ },
2459
2472
  sides: [
2460
2473
  {
2461
2474
  name: "term",
2475
+ // F3: every <tbx:tig>'s <tbx:term> STACKS one-per-line onto the
2476
+ // single term side (the "$\n" template's authored separator; the
2477
+ // trailing one is trimmed) — the PDF's Maus/Mus/M/Müsli stack.
2478
+ mappingKeys: {
2479
+ "xml-niso-iec": [
2480
+ { "@el": "term", "@text": "$" },
2481
+ { "@el": "tbx:tig", "@children": { "@el": "tbx:term", "@text": "$\n" } }
2482
+ ]
2483
+ },
2462
2484
  variants: [
2463
2485
  {
2464
2486
  jsonKey: "term.text",
@@ -2474,7 +2496,8 @@ var CARDSETS = {
2474
2496
  format: TagFormat.plainText,
2475
2497
  nullable: true,
2476
2498
  jsonKey: "^heading.forKeys",
2477
- exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2499
+ exportJsonKey: { "@bit": { heading: { forKeys: "$" } } },
2500
+ mappingKeys: { "xml-niso-iec": { "@el": "title", "@text": "$" } }
2478
2501
  },
2479
2502
  {
2480
2503
  key: ConfigKey.group_resourceIcon,
@@ -2500,6 +2523,24 @@ var CARDSETS = {
2500
2523
  },
2501
2524
  {
2502
2525
  name: "definition",
2526
+ // F3: the definition side COMPOSES from the entry's fields in
2527
+ // document order, with the ES-rendered locale affixes AUTHORED as
2528
+ // value-position templates (never engine text): the subject field
2529
+ // in ⟨⟩ glues (trailing space) onto the definition line; example /
2530
+ // notes / source follow as blank-line-separated lines. The TBX
2531
+ // grammar flags (normativeAuthorization, termType, partOfSpeech,
2532
+ // grammaticalNumber) are unrendered machine-only data — dropped and
2533
+ // recorded (catalog R-2, reviewed under D7 max-preservation).
2534
+ mappingKeys: {
2535
+ "xml-niso-iec": [
2536
+ { "@el": "def", "@children": "$" },
2537
+ { "@el": "tbx:subjectField", "@text": "\u27E8$\u27E9 " },
2538
+ { "@el": "tbx:definition", "@children": "$" },
2539
+ { "@el": "tbx:example", "@children": "BEISPIEL $" },
2540
+ { "@el": "tbx:note", "@children": "Anmerkung zu Begriff: $" },
2541
+ { "@el": "tbx:source", "@text": "[QUELLE: $]" }
2542
+ ]
2543
+ },
2503
2544
  variants: [
2504
2545
  {
2505
2546
  jsonKey: "definition.text",
@@ -3890,6 +3931,11 @@ var CARDSETS = {
3890
3931
  { table: { header: { rows: ["$"] } } }
3891
3932
  ],
3892
3933
  htmlKey: { "@el": "thead", "@children": { "@el": "tr", "@children": "$" } },
3934
+ // PLAN-141 F2 (NISO import): the XHTML table model NISO uses — a
3935
+ // <thead> SECTION whose <tr> rows are the header cards.
3936
+ mappingKeys: {
3937
+ "xml-niso-iec": { "@el": "thead", "@children": { "@el": "tr", "@children": "$" } }
3938
+ },
3893
3939
  sideJsonKey: "cells[{s}]|set(title=true)",
3894
3940
  sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } },
3895
3941
  // Header cells are `<th>`. The `width` attribute is contributed by the
@@ -3901,12 +3947,21 @@ var CARDSETS = {
3901
3947
  jsonKey: "table.body.rows",
3902
3948
  exportJsonKey: { table: { body: { rows: "$" } } },
3903
3949
  htmlKey: { "@el": "tbody", "@children": { "@el": "tr", "@children": "$" } },
3950
+ // PLAN-141 F2 (NISO import): <tbody> rows are the (default) data cards.
3951
+ mappingKeys: {
3952
+ "xml-niso-iec": { "@el": "tbody", "@children": { "@el": "tr", "@children": "$" } }
3953
+ },
3904
3954
  isDefault: true
3905
3955
  },
3906
3956
  "table-footer": {
3907
3957
  jsonKey: "table.footer.rows",
3908
3958
  exportJsonKey: { table: { footer: { rows: "$" } } },
3909
3959
  htmlKey: { "@el": "tfoot", "@children": { "@el": "tr", "@children": "$" } },
3960
+ // PLAN-141 F2 (NISO import): NISO has no <tfoot> — the footer card's
3961
+ // source is the <table-wrap-foot> block (CONTENT-shaped: no rows; its
3962
+ // prose/notes flatten into one footer card — catalog table-wrap-foot
3963
+ // row; a contained <def-list> promotes as a sibling legend bit).
3964
+ mappingKeys: { "xml-niso-iec": { "@el": "table-wrap-foot", "@children": "$" } },
3910
3965
  sideJsonKey: "cells[{s}]|set(title=true)",
3911
3966
  sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } },
3912
3967
  // Footer cells render as `<th>` (mirrors the header `title: true`
@@ -3923,6 +3978,8 @@ var CARDSETS = {
3923
3978
  // Default (body) cell → `<td>`; the header/footer sections override the
3924
3979
  // side to `<th>` via their sideHtmlKey (HTML.md §8).
3925
3980
  htmlKey: { "@el": "td", "@children": "$" },
3981
+ // PLAN-141 F2 (NISO import): a <td> row child is a body cell side.
3982
+ mappingKeys: { "xml-niso-iec": { "@el": "td", "@children": "$" } },
3926
3983
  variants: [
3927
3984
  {
3928
3985
  jsonKey: "content",
@@ -3940,7 +3997,11 @@ var CARDSETS = {
3940
3997
  // cell with `title: true` automatically.
3941
3998
  jsonKey: "content",
3942
3999
  exportJsonKey: { content: "$" },
3943
- description: "Title text of the table cell (header rows)."
4000
+ description: "Title text of the table cell (header rows).",
4001
+ // PLAN-141 F2 (NISO import): a <th> row child is a TITLE cell —
4002
+ // its content lands in the `[#…]` tag (an empty <th> keeps its
4003
+ // slot as a bare `[#]`).
4004
+ mappingKeys: { "xml-niso-iec": { "@el": "th", "@children": "$" } }
3944
4005
  },
3945
4006
  {
3946
4007
  key: ConfigKey.property_tableCellType,
@@ -3959,6 +4020,9 @@ var CARDSETS = {
3959
4020
  // HTML-C2: contribute a `rowspan` attribute onto the enclosing
3960
4021
  // cell element (`<th>`/`<td>`).
3961
4022
  htmlKey: { "@el": { "@attr": { rowspan: "$" } } },
4023
+ // PLAN-141 F2 (NISO import): recover the source cell's own
4024
+ // `rowspan` attribute (element-scope attr form).
4025
+ mappingKeys: { "xml-niso-iec": { "@el": { "@attr": { rowspan: "$" } } } },
3962
4026
  description: "Number of rows the cell spans.",
3963
4027
  format: TagFormat.number
3964
4028
  },
@@ -3969,6 +4033,9 @@ var CARDSETS = {
3969
4033
  // HTML-C2: contribute a `colspan` attribute onto the enclosing
3970
4034
  // cell element (`<th>`/`<td>`).
3971
4035
  htmlKey: { "@el": { "@attr": { colspan: "$" } } },
4036
+ // PLAN-141 F2 (NISO import): recover the source cell's own
4037
+ // `colspan` attribute (element-scope attr form).
4038
+ mappingKeys: { "xml-niso-iec": { "@el": { "@attr": { colspan: "$" } } } },
3972
4039
  description: "Number of columns the cell spans.",
3973
4040
  format: TagFormat.number
3974
4041
  },
@@ -3990,6 +4057,13 @@ var CARDSETS = {
3990
4057
  // HTML.md §8 + HTML-C2: contribute a `width` attribute onto the
3991
4058
  // enclosing cell element (`<th>`/`<td>`).
3992
4059
  htmlKey: { "@el": { "@attr": { width: "$" } } },
4060
+ // PLAN-141 F2 (NISO import): NISO carries widths as PER-COLUMN
4061
+ // <col width="…"> descriptors at container level, not on cells.
4062
+ // The matched values distribute positionally onto the first
4063
+ // (header) card's sides. Number format ⇒ only an integral
4064
+ // percentage survives ("20.0000%" → 20); a fractional one
4065
+ // (renderer-equalised "4.7619%") is dropped — catalog `col` row.
4066
+ mappingKeys: { "xml-niso-iec": { "@el": "col", "@attr": { width: "$" } } },
3993
4067
  description: "Width for the column.",
3994
4068
  format: TagFormat.number
3995
4069
  }
@@ -4363,7 +4437,22 @@ var GROUPS = {
4363
4437
  key: ConfigKey.property_externalId,
4364
4438
  description: "The external identifier for the bit",
4365
4439
  format: TagFormat.plainText,
4366
- maxCount: Count.infinity
4440
+ maxCount: Count.infinity,
4441
+ // PLAN-140 refs family (NISO import): the machine identifier of a
4442
+ // referenced standard. NESTED content slot — the tag reads (and
4443
+ // consumes) ONLY the <std-id> inside a <std> child; the remaining
4444
+ // designation/title text stays bit body. A <std> without <std-id>
4445
+ // does not fire the key.
4446
+ // PLAN-141 F5: on the [.book] bit, the DATED <std-ref> designation
4447
+ // is the document's external id. Safe rule order: <std-ref> is a
4448
+ // direct bit-element child only under <std-meta> (everywhere else
4449
+ // it nests inside <std>, which the tag spine never reaches).
4450
+ mappingKeys: {
4451
+ "xml-niso-iec": [
4452
+ { "@el": "std", "@children": { "@el": "std-id", "@text": "$" } },
4453
+ { "@el": "std-ref", "@attr": { type: "dated" }, "@text": "$" }
4454
+ ]
4455
+ }
4367
4456
  },
4368
4457
  {
4369
4458
  key: ConfigKey.property_sourceRL,
@@ -4504,7 +4593,8 @@ var GROUPS = {
4504
4593
  {
4505
4594
  key: ConfigKey.property_diffTime,
4506
4595
  description: "The diff time for the bit",
4507
- format: TagFormat.number
4596
+ format: TagFormat.number,
4597
+ nullable: true
4508
4598
  },
4509
4599
  {
4510
4600
  key: ConfigKey.property_ageRange,
@@ -4515,7 +4605,18 @@ var GROUPS = {
4515
4605
  {
4516
4606
  key: ConfigKey.property_lang,
4517
4607
  description: "The language for the bit",
4518
- format: TagFormat.plainText
4608
+ format: TagFormat.plainText,
4609
+ // PLAN-141 F3 (NISO import): a term-sec's language rides
4610
+ // <tbx:termEntry><tbx:langSet xml:lang> — a nested content slot
4611
+ // whose leaf is a $-in-ATTR-position slot (the nested counterpart
4612
+ // of the value-attr slot). Only termEntry elements match, so the
4613
+ // shared tag is inert everywhere else.
4614
+ mappingKeys: {
4615
+ "xml-niso-iec": {
4616
+ "@el": "tbx:termEntry",
4617
+ "@children": { "@el": "tbx:langSet", "@attr": { "xml:lang": "$" } }
4618
+ }
4619
+ }
4519
4620
  },
4520
4621
  {
4521
4622
  key: ConfigKey.property_publisher,
@@ -4714,6 +4815,9 @@ var GROUPS = {
4714
4815
  key: ConfigKey.tag_item,
4715
4816
  jsonKey: "item",
4716
4817
  exportJsonKey: { item: "$" },
4818
+ // PLAN-140 W3 (NISO import): the clause/note label of a mapped
4819
+ // source element ([%1], [%ANMERKUNG 1]).
4820
+ mappingKeys: { "xml-niso-iec": { "@el": "label", "@text": "$" } },
4717
4821
  description: "The item for the bit",
4718
4822
  chain: [
4719
4823
  {
@@ -5676,7 +5780,20 @@ var GROUPS = {
5676
5780
  key: ConfigKey.property_language,
5677
5781
  description: "The language of the book",
5678
5782
  format: TagFormat.plainText,
5679
- maxCount: Count.infinity
5783
+ maxCount: Count.infinity,
5784
+ // PLAN-141 F5 (NISO import): only the PRIMARY (first)
5785
+ // <content-language> survives — the maxEmits cap realises the
5786
+ // catalog's document-language rule (extras drop, R-4).
5787
+ mappingKeys: {
5788
+ "xml-niso-iec": [
5789
+ { predicates: [], maxEmits: 1, rule: { "@el": "content-language", "@text": "$" } }
5790
+ ]
5791
+ }
5792
+ },
5793
+ {
5794
+ key: ConfigKey.property_displayName,
5795
+ description: "The display name of the book",
5796
+ format: TagFormat.plainText
5680
5797
  },
5681
5798
  {
5682
5799
  key: ConfigKey.property_customerExternalId,
@@ -5752,7 +5869,18 @@ var GROUPS = {
5752
5869
  description: "The title of the book",
5753
5870
  maxCount: 2,
5754
5871
  jsonKey: "title|multi(count=2, key=subtitle)",
5755
- exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
5872
+ exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }],
5873
+ // PLAN-141 F5 (NISO import): the PRIMARY (first) <title-wrap>'s
5874
+ // assembled <full> title → [#]; the per-language extras drop (R-4).
5875
+ mappingKeys: {
5876
+ "xml-niso-iec": [
5877
+ {
5878
+ predicates: [],
5879
+ maxEmits: 1,
5880
+ rule: { "@el": "title-wrap", "@children": { "@el": "full", "@text": "$" } }
5881
+ }
5882
+ ]
5883
+ }
5756
5884
  },
5757
5885
  {
5758
5886
  key: ConfigKey.property_subtype,
@@ -6065,17 +6193,20 @@ var GROUPS = {
6065
6193
  {
6066
6194
  key: ConfigKey.property_platformMargin,
6067
6195
  description: "The platform margin",
6068
- format: TagFormat.number
6196
+ format: TagFormat.number,
6197
+ nullable: true
6069
6198
  },
6070
6199
  {
6071
6200
  key: ConfigKey.property_platformBorderRadius,
6072
6201
  description: "The platform border radius",
6073
- format: TagFormat.number
6202
+ format: TagFormat.number,
6203
+ nullable: true
6074
6204
  },
6075
6205
  {
6076
6206
  key: ConfigKey.property_platformSelectionBorderRadius,
6077
6207
  description: "The platform selection border radius",
6078
- format: TagFormat.number
6208
+ format: TagFormat.number,
6209
+ nullable: true
6079
6210
  },
6080
6211
  {
6081
6212
  key: ConfigKey.property_platformNeedsShadow,
@@ -6182,7 +6313,13 @@ var GROUPS = {
6182
6313
  {
6183
6314
  key: ConfigKey.property_caption,
6184
6315
  description: "The caption for the resource",
6185
- format: TagFormat.bitmarkText
6316
+ format: TagFormat.bitmarkText,
6317
+ // PLAN-141 F1 (NISO import): a figure's <caption><title> — the
6318
+ // nested content slot reads the title text; the caption rides the
6319
+ // resource chain ([&image:…][@caption:…], catalog D5).
6320
+ mappingKeys: {
6321
+ "xml-niso-iec": { "@el": "caption", "@children": { "@el": "title", "@text": "$" } }
6322
+ }
6186
6323
  },
6187
6324
  {
6188
6325
  key: ConfigKey.property_showInIndex,
@@ -6456,6 +6593,10 @@ var GROUPS = {
6456
6593
  {
6457
6594
  key: ConfigKey.resource_image,
6458
6595
  exportJsonKey: { resource: { type: "image", image: { src: "$" } } },
6596
+ // PLAN-141 F1 (NISO import): the image URL rides the `$`-in-attr
6597
+ // value slot — a <graphic xlink:href> child of the mapped bit
6598
+ // element roots the [&image:URL] chain.
6599
+ mappingKeys: { "xml-niso-iec": { "@el": "graphic", "@attr": { "xlink:href": "$" } } },
6459
6600
  description: "The image resource",
6460
6601
  chain: [
6461
6602
  {
@@ -7330,6 +7471,8 @@ var BITS = {
7330
7471
  maxCount: 2,
7331
7472
  jsonKey: "title|multi(count=2, key=subtitle)",
7332
7473
  exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }],
7474
+ // PLAN-140 W3 (NISO import): the title of a mapped source element.
7475
+ mappingKeys: { "xml-niso-iec": { "@el": "title", "@text": "$" } },
7333
7476
  key: ConfigKey.tag_title,
7334
7477
  description: "The title of the article"
7335
7478
  }
@@ -7371,12 +7514,56 @@ var BITS = {
7371
7514
  [BitType.smartStandardArticleNormative]: {
7372
7515
  since: "1.28.0",
7373
7516
  baseBitType: BitType.standardArticleNormative,
7374
- description: "Smart standard normative article bit"
7517
+ description: "Smart standard normative article bit",
7518
+ // PLAN-140 W3 (NISO import, tranche 1): one article bit per NISO
7519
+ // paragraph (catalog D1). CONTENT keys (@children): the subtree is the
7520
+ // bit's body; nothing inside it promotes. (Ancestor-context normativity
7521
+ // is the non-normative sibling's @ancestor key — plan Q4, resolved.)
7522
+ //
7523
+ // Second rule (catalog D1 push-down): a NUMBERED-PARAGRAPH sec is an
7524
+ // article, not a chapter — the sec-type literal outranks the chapter
7525
+ // key's plain sec|app rule (most-specific-wins). Content key: the sec's
7526
+ // label rides [%] via the label tag key, its inner <p> is the body, its
7527
+ // id is the bit's customerId, and the anchor slot marks it
7528
+ // anchor-bearing.
7529
+ mappingKeys: {
7530
+ "xml-niso-iec": [
7531
+ { "@el": "p", "@attr": { id: "$customerId" }, "@children": "$" },
7532
+ {
7533
+ "@el": "sec",
7534
+ "@attr": { "sec-type": "numbered-paragraph", id: "$customerId" },
7535
+ "@children": "$",
7536
+ "\u25BC": "$anchor"
7537
+ }
7538
+ ]
7539
+ }
7375
7540
  },
7376
7541
  [BitType.smartStandardArticleNonNormative]: {
7377
7542
  since: "1.28.0",
7378
7543
  baseBitType: BitType.standardArticleNonNormative,
7379
- description: "Smart standard non-normative article bit"
7544
+ description: "Smart standard non-normative article bit",
7545
+ // PLAN-140 Q4 (normativity inheritance): a <p> is non-normative because
7546
+ // of an ANCESTOR element — a foreword/intro sec or an informative annex.
7547
+ // @ancestor is a reverse-match-only constraint (forward emission ignores
7548
+ // it); the rules are alternatives, first-satisfied wins, and the
7549
+ // @ancestor literals give this key higher specificity than the plain
7550
+ // normative-article <p> key wherever the context applies.
7551
+ mappingKeys: {
7552
+ "xml-niso-iec": [
7553
+ {
7554
+ "@el": "p",
7555
+ "@attr": { id: "$customerId" },
7556
+ "@ancestor": { "@attr": { "sec-type": "foreword|intro" } },
7557
+ "@children": "$"
7558
+ },
7559
+ {
7560
+ "@el": "p",
7561
+ "@attr": { id: "$customerId" },
7562
+ "@ancestor": { "@attr": { "content-type": "informative" } },
7563
+ "@children": "$"
7564
+ }
7565
+ ]
7566
+ }
7380
7567
  },
7381
7568
  [BitType.smartStandardArticleNormativeCollapsible]: {
7382
7569
  since: "1.28.0",
@@ -8007,7 +8194,8 @@ var BITS = {
8007
8194
  {
8008
8195
  key: ConfigKey.property_maxCreatedBits,
8009
8196
  description: "The maximum number of bits that can be created from this bit",
8010
- format: TagFormat.number
8197
+ format: TagFormat.number,
8198
+ nullable: true
8011
8199
  }
8012
8200
  ],
8013
8201
  textFormatDefault: TextFormat.plainText
@@ -8137,6 +8325,13 @@ var BITS = {
8137
8325
  since: "1.3.0",
8138
8326
  baseBitType: BitType._standard,
8139
8327
  description: "Book bit, used to represent a book",
8328
+ // PLAN-141 F5 (NISO import): the <std-meta> front-matter container is
8329
+ // the [.book] bit (STRUCTURAL, first in document order): primary
8330
+ // title-wrap → [#], primary content-language → [@language], dated
8331
+ // std-ref → [@externalId] (tag keys with maxEmits caps — the NISO
8332
+ // convention puts the document language first). std-meta has no id, so
8333
+ // no anchor/customerId. Remaining leaves drop as recorded loss (R-4).
8334
+ mappingKeys: { "xml-niso-iec": { "@el": "std-meta" } },
8140
8335
  tags: [
8141
8336
  {
8142
8337
  key: ConfigKey.group_bookCommon,
@@ -8423,12 +8618,14 @@ var BITS = {
8423
8618
  {
8424
8619
  key: ConfigKey.property_focusX,
8425
8620
  description: "The X coordinate for focusing the image in the browser",
8426
- format: TagFormat.number
8621
+ format: TagFormat.number,
8622
+ nullable: true
8427
8623
  },
8428
8624
  {
8429
8625
  key: ConfigKey.property_focusY,
8430
8626
  description: "The Y coordinate for focusing the image in the browser",
8431
- format: TagFormat.number
8627
+ format: TagFormat.number,
8628
+ nullable: true
8432
8629
  }
8433
8630
  ]
8434
8631
  },
@@ -8459,6 +8656,15 @@ var BITS = {
8459
8656
  since: "1.3.0",
8460
8657
  baseBitType: BitType._standard,
8461
8658
  description: "Chapter bit, used to define chapters in books or articles",
8659
+ // PLAN-140 W3 (NISO import, tranche 1): recover a chapter from a NISO
8660
+ // section or annex. STRUCTURAL key (no @children content slot): the
8661
+ // element carries no body of its own — tag children (label/title) map
8662
+ // via tag keys, every mapped descendant promotes to a following sibling
8663
+ // bit, and the chapter level derives from nesting depth (catalog D1).
8664
+ // The source id lands as [@customerId] (two-id model, D2).
8665
+ mappingKeys: {
8666
+ "xml-niso-iec": { "@el": "sec|app", "@attr": { id: "$customerId" }, "\u25BC": "$anchor" }
8667
+ },
8462
8668
  tags: [
8463
8669
  {
8464
8670
  exportJsonKey: { anchor: "$" },
@@ -8470,7 +8676,10 @@ var BITS = {
8470
8676
  key: ConfigKey.tag_title,
8471
8677
  description: "The title of the chapter",
8472
8678
  jsonKey: "title|setMulti(level)",
8473
- exportJsonKey: { title: "$", level: "$level" }
8679
+ exportJsonKey: { title: "$", level: "$level" },
8680
+ // PLAN-140 W3 (NISO import): the section/annex title; the heading
8681
+ // level rides the normalizer-derived nesting depth (plan Q2).
8682
+ mappingKeys: { "xml-niso-iec": { "@el": "title", "@text": "$" } }
8474
8683
  },
8475
8684
  {
8476
8685
  key: ConfigKey.property_toc,
@@ -8676,11 +8885,28 @@ var BITS = {
8676
8885
  since: "1.3.0",
8677
8886
  baseBitType: BitType._standard,
8678
8887
  description: "Code bit, used for code snippets in articles or documents",
8888
+ // PLAN-141 F4 (NISO import): a <code> block is a CONTENT bit with a
8889
+ // literal text body; @language recovers as [@computerLanguage] (absent
8890
+ // attr → no tag). Anchor = the source id (D2 revised).
8891
+ mappingKeys: {
8892
+ "xml-niso-iec": {
8893
+ "@el": "code",
8894
+ "@attr": { id: "$customerId", language: "$computerLanguage" },
8895
+ "\u25BC": "$anchor",
8896
+ "@text": "$"
8897
+ }
8898
+ },
8679
8899
  tags: [
8680
8900
  {
8681
8901
  key: ConfigKey.property_computerLanguage,
8682
8902
  description: "The programming language of the code snippet",
8683
- format: TagFormat.plainText
8903
+ format: TagFormat.plainText,
8904
+ // PLAN-141 F4 (NISO import): the bit key's `language` sigil recovers
8905
+ // a present attr; this `@absent` rule supplies the AUTHORED default
8906
+ // when the source carries none (catalog code row — an untyped block
8907
+ // is `[@computerLanguage:text]`). Fires only on foreign imports,
8908
+ // never the carrier round-trip.
8909
+ mappingKeys: { "xml-niso-iec": [{ "@absent": "text" }] }
8684
8910
  },
8685
8911
  {
8686
8912
  key: ConfigKey.property_codeLineNumbers,
@@ -8719,7 +8945,20 @@ var BITS = {
8719
8945
  [BitType.smartStandardFormulaNormative]: {
8720
8946
  since: "3.11.0",
8721
8947
  baseBitType: BitType.formula,
8722
- description: "Smart standard normative formula bit, used for mathematical formulas in smart standards that are normative"
8948
+ description: "Smart standard normative formula bit, used for mathematical formulas in smart standards that are normative",
8949
+ // PLAN-141 F4 (NISO import): a <disp-formula> is a CONTENT bit whose
8950
+ // latex-format body carries the <mml:math> subtree VERBATIM (G1 — no
8951
+ // MathML↔LaTeX transform; ids stripped); <label> → [%]; a contained
8952
+ // <legend> PROMOTES as a sibling legend bit (cards cannot nest in a
8953
+ // body). Anchor = the source id (D2 revised).
8954
+ mappingKeys: {
8955
+ "xml-niso-iec": {
8956
+ "@el": "disp-formula",
8957
+ "@attr": { id: "$customerId" },
8958
+ "\u25BC": "$anchor",
8959
+ "@children": "$"
8960
+ }
8961
+ }
8723
8962
  },
8724
8963
  [BitType.smartStandardRemarkFormula]: {
8725
8964
  since: "3.11.0",
@@ -9246,7 +9485,8 @@ var BITS = {
9246
9485
  {
9247
9486
  key: ConfigKey.property_reasonableNumOfChars,
9248
9487
  description: "The reasonable number of characters for the essay",
9249
- format: TagFormat.number
9488
+ format: TagFormat.number,
9489
+ nullable: true
9250
9490
  },
9251
9491
  {
9252
9492
  key: ConfigKey.property_sampleSolution,
@@ -9679,7 +9919,14 @@ var BITS = {
9679
9919
  [BitType.smartStandardList]: {
9680
9920
  since: "1.28.0",
9681
9921
  baseBitType: BitType.standardList,
9682
- description: "Smart standard list bit, used to create smart standard lists in articles or books"
9922
+ description: "Smart standard list bit, used to create smart standard lists in articles or books",
9923
+ // PLAN-140 refs family (NISO import): a reference list is a STRUCTURAL
9924
+ // bit (no @children — it takes a path ordinal anchor and its <ref>
9925
+ // children promote to sibling list-item bits); its <title> rides [#]
9926
+ // via the title tag key.
9927
+ mappingKeys: {
9928
+ "xml-niso-iec": { "@el": "ref-list", "@attr": { id: "$customerId" }, "\u25BC": "$anchor" }
9929
+ }
9683
9930
  },
9684
9931
  [BitType.smartStandardListCollapsible]: {
9685
9932
  since: "1.28.0",
@@ -9724,7 +9971,17 @@ var BITS = {
9724
9971
  [BitType.smartStandardNoteNonNormative]: {
9725
9972
  since: "1.28.0",
9726
9973
  baseBitType: BitType.standardNoteNonNormative,
9727
- description: "Smart standard non-normative note bit, used to provide non-normative notes in smart standards"
9974
+ description: "Smart standard non-normative note bit, used to provide non-normative notes in smart standards",
9975
+ // PLAN-140 W3 (NISO import, tranche 1). CONTENT key (@children): a
9976
+ // note's inner paragraphs are note body, never separate bits.
9977
+ mappingKeys: {
9978
+ "xml-niso-iec": {
9979
+ "@el": "non-normative-note",
9980
+ "@attr": { id: "$customerId" },
9981
+ "@children": "$",
9982
+ "\u25BC": "$anchor"
9983
+ }
9984
+ }
9728
9985
  },
9729
9986
  [BitType.smartStandardNoteNormativeCollapsible]: {
9730
9987
  since: "1.28.0",
@@ -9831,7 +10088,19 @@ var BITS = {
9831
10088
  [BitType.smartStandardRemarkNonNormative]: {
9832
10089
  since: "1.28.0",
9833
10090
  baseBitType: BitType.standardRemarkNonNormative,
9834
- description: "Smart standard non-normative remark bit, used to provide non-normative remarks in smart standards"
10091
+ description: "Smart standard non-normative remark bit, used to provide non-normative remarks in smart standards",
10092
+ // PLAN-140 Q4 rider: a warning/caution note routes to the remark bit —
10093
+ // the same element as the note key, distinguished by the content-type
10094
+ // attr literal (alias value: forward emits the first alternative,
10095
+ // reverse accepts any). Most-specific-wins beats the plain note key.
10096
+ mappingKeys: {
10097
+ "xml-niso-iec": {
10098
+ "@el": "non-normative-note",
10099
+ "@attr": { "content-type": "warning|caution", id: "$customerId" },
10100
+ "@children": "$",
10101
+ "\u25BC": "$anchor"
10102
+ }
10103
+ }
9835
10104
  },
9836
10105
  [BitType.smartStandardRemarkNormativeCollapsible]: {
9837
10106
  since: "1.28.0",
@@ -10287,7 +10556,8 @@ var BITS = {
10287
10556
  {
10288
10557
  key: ConfigKey.property_pageNo,
10289
10558
  description: "Page number for the block, used to indicate the page on which the block appears",
10290
- format: TagFormat.number
10559
+ format: TagFormat.number,
10560
+ nullable: true
10291
10561
  },
10292
10562
  {
10293
10563
  key: ConfigKey.property_x,
@@ -10304,17 +10574,20 @@ var BITS = {
10304
10574
  {
10305
10575
  key: ConfigKey.property_width,
10306
10576
  description: "Width of the block, used to define the size of the block on the page",
10307
- format: TagFormat.number
10577
+ format: TagFormat.number,
10578
+ nullable: true
10308
10579
  },
10309
10580
  {
10310
10581
  key: ConfigKey.property_height,
10311
10582
  description: "Height of the block, used to define the size of the block on the page",
10312
- format: TagFormat.number
10583
+ format: TagFormat.number,
10584
+ nullable: true
10313
10585
  },
10314
10586
  {
10315
10587
  key: ConfigKey.property_index,
10316
10588
  description: "Index of the block, used to order blocks within the extractor page",
10317
- format: TagFormat.number
10589
+ format: TagFormat.number,
10590
+ nullable: true
10318
10591
  },
10319
10592
  {
10320
10593
  key: ConfigKey.property_classification,
@@ -10624,7 +10897,20 @@ var BITS = {
10624
10897
  [BitType.smartStandardLegendNormative]: {
10625
10898
  since: "3.12.0",
10626
10899
  baseBitType: BitType.legend,
10627
- description: "Smart standard normative legend bit, used to provide normative smart standard legends in articles or books"
10900
+ description: "Smart standard normative legend bit, used to provide normative smart standard legends in articles or books",
10901
+ // PLAN-141 F2 (NISO import): a free-standing <legend> (a formula's) or
10902
+ // bare <def-list> (a table footer's — no <legend> wrapper there) that is
10903
+ // NOT the claimed card content of its enclosing bit is a legend bit:
10904
+ // STRUCTURAL-shaped, its <title> and <def-item>s build the
10905
+ // definition-list cards via the card set's authored keys. A <legend>
10906
+ // inside a figure/table bit stays that bit's claimed card content and
10907
+ // never reaches this key. Anchor = the source id (D2 revised).
10908
+ mappingKeys: {
10909
+ "xml-niso-iec": [
10910
+ { "@el": "legend", "@attr": { id: "$customerId" }, "\u25BC": "$anchor" },
10911
+ { "@el": "def-list", "@attr": { id: "$customerId" }, "\u25BC": "$anchor" }
10912
+ ]
10913
+ }
10628
10914
  },
10629
10915
  [BitType.smartStandardRemarkLegend]: {
10630
10916
  since: "3.12.0",
@@ -10679,7 +10965,16 @@ var BITS = {
10679
10965
  [BitType.smartStandardDefinitionListNormative]: {
10680
10966
  since: "5.24.0",
10681
10967
  baseBitType: BitType.standardDefinitionListNormative,
10682
- description: "Smart standard normative definition list bit, used to create normative smart standard definition lists in articles or books"
10968
+ description: "Smart standard normative definition list bit, used to create normative smart standard definition lists in articles or books",
10969
+ // PLAN-141 F3 (NISO import): a terms-and-definitions clause. STRUCTURAL-
10970
+ // shaped: <label> → [%], the tbx:termEntry/langSet subtree builds the
10971
+ // definition-list card via the card set's authored keys (all tig terms
10972
+ // stacked on the term side; definition/example/notes/source composed on
10973
+ // the definition side with authored locale affixes), langSet @xml:lang →
10974
+ // [@lang] (nested attr slot on the tag key). Anchor = the source id.
10975
+ mappingKeys: {
10976
+ "xml-niso-iec": { "@el": "term-sec", "@attr": { id: "$customerId" }, "\u25BC": "$anchor" }
10977
+ }
10683
10978
  },
10684
10979
  [BitType.smartStandardDefinitionListNonNormative]: {
10685
10980
  since: "5.24.0",
@@ -10748,12 +11043,14 @@ var BITS = {
10748
11043
  {
10749
11044
  key: ConfigKey.property_focusX,
10750
11045
  description: "X-coordinate for the focus point, used to define the focus area in the image",
10751
- format: TagFormat.number
11046
+ format: TagFormat.number,
11047
+ nullable: true
10752
11048
  },
10753
11049
  {
10754
11050
  key: ConfigKey.property_focusY,
10755
11051
  description: "Y-coordinate for the focus point, used to define the focus area in the image",
10756
- format: TagFormat.number
11052
+ format: TagFormat.number,
11053
+ nullable: true
10757
11054
  }
10758
11055
  ]
10759
11056
  },
@@ -10860,7 +11157,15 @@ var BITS = {
10860
11157
  [BitType.smartStandardImageFigureNormative]: {
10861
11158
  since: "1.28.0",
10862
11159
  baseBitType: BitType.standardImageFigureNormative,
10863
- description: "Smart standard normative image figure bit, used to create smart standard normative image figures in articles or books"
11160
+ description: "Smart standard normative image figure bit, used to create smart standard normative image figures in articles or books",
11161
+ // PLAN-141 F1 (NISO import): a figure is STRUCTURAL-shaped (no
11162
+ // @children — no body): <label> → [%], <caption>/<graphic> ride the
11163
+ // [&image] resource chain, the <legend> def-list becomes the bit's
11164
+ // definition-list cards, and an inner note PROMOTES as a sibling bit.
11165
+ // Anchor = the source id (D2 revised).
11166
+ mappingKeys: {
11167
+ "xml-niso-iec": { "@el": "fig", "@attr": { id: "$customerId" }, "\u25BC": "$anchor" }
11168
+ }
10864
11169
  },
10865
11170
  [BitType.smartStandardImageFigureNonNormative]: {
10866
11171
  since: "1.28.0",
@@ -11588,7 +11893,19 @@ var BITS = {
11588
11893
  [BitType.smartStandardListItem]: {
11589
11894
  since: "1.28.0",
11590
11895
  baseBitType: BitType.standardListItem,
11591
- description: "Smart standard list item bit, used to create smart standard list items in articles or books"
11896
+ description: "Smart standard list item bit, used to create smart standard list items in articles or books",
11897
+ // PLAN-140 refs family (NISO import): one list-item bit per <ref> —
11898
+ // CONTENT key (its citation subtree is the body), counter anchor scoped
11899
+ // to the containing list, <label> → [%], nested <std-id> → [@externalId]
11900
+ // (the externalId tag key's nested content slot).
11901
+ mappingKeys: {
11902
+ "xml-niso-iec": {
11903
+ "@el": "ref",
11904
+ "@attr": { id: "$customerId" },
11905
+ "@children": "$",
11906
+ "\u25BC": "$anchor"
11907
+ }
11908
+ }
11592
11909
  },
11593
11910
  [BitType.smartStandardListItemCollapsible]: {
11594
11911
  since: "1.28.0",
@@ -12695,7 +13012,13 @@ var BITS = {
12695
13012
  // `<caption>` — placed inside the idiomatic `<table>` container as
12696
13013
  // its first child. Outside a table context it falls back to the
12697
13014
  // residual carrier.
12698
- htmlKey: { "@el": "caption", "@children": "$" }
13015
+ htmlKey: { "@el": "caption", "@children": "$" },
13016
+ // PLAN-141 F2 (NISO import): a table-wrap's <caption><title> — the
13017
+ // nested content slot reads the title text (catalog D5: the caption
13018
+ // is a TOP-LEVEL bit property on table bits).
13019
+ mappingKeys: {
13020
+ "xml-niso-iec": { "@el": "caption", "@children": { "@el": "title", "@text": "$" } }
13021
+ }
12699
13022
  },
12700
13023
  {
12701
13024
  key: ConfigKey.property_tableFixedHeader,
@@ -12868,7 +13191,16 @@ var BITS = {
12868
13191
  [BitType.smartStandardTableExtendedNormative]: {
12869
13192
  since: "1.28.0",
12870
13193
  baseBitType: BitType.standardTableExtendedNormative,
12871
- description: "Smart standard normative extended table bit, used to create smart standard normative extended tables in articles or books"
13194
+ description: "Smart standard normative extended table bit, used to create smart standard normative extended tables in articles or books",
13195
+ // PLAN-141 F2 (NISO import): a table-wrap is STRUCTURAL-shaped (no
13196
+ // @children — no body): <label> → [%], <caption><title> → the bit-level
13197
+ // [@caption] (D5), the inner <table>/<table-wrap-foot> build the
13198
+ // table-extended card grid via the card set's authored keys, and a
13199
+ // footer <def-list> PROMOTES as a sibling legend bit. Anchor = the
13200
+ // source id (D2 revised).
13201
+ mappingKeys: {
13202
+ "xml-niso-iec": { "@el": "table-wrap", "@attr": { id: "$customerId" }, "\u25BC": "$anchor" }
13203
+ }
12872
13204
  },
12873
13205
  [BitType.smartStandardTableExtendedNonNormative]: {
12874
13206
  since: "1.28.0",
@@ -12943,7 +13275,8 @@ var BITS = {
12943
13275
  {
12944
13276
  key: ConfigKey.property_maxDisplayLevel,
12945
13277
  description: "Maximum display level for the chapter in the table of contents",
12946
- format: TagFormat.number
13278
+ format: TagFormat.number,
13279
+ nullable: true
12947
13280
  }
12948
13281
  ]
12949
13282
  },
@@ -12955,7 +13288,8 @@ var BITS = {
12955
13288
  {
12956
13289
  key: ConfigKey.property_maxTocChapterLevel,
12957
13290
  description: "Maximum chapter level for the inline table of contents",
12958
- format: TagFormat.number
13291
+ format: TagFormat.number,
13292
+ nullable: true
12959
13293
  }
12960
13294
  ]
12961
13295
  },
@@ -13378,13 +13712,15 @@ var BITS = {
13378
13712
  key: ConfigKey.property_width,
13379
13713
  // Same as image
13380
13714
  description: "Width for the embedded content, used to define the width in pixels",
13381
- format: TagFormat.number
13715
+ format: TagFormat.number,
13716
+ nullable: true
13382
13717
  },
13383
13718
  {
13384
13719
  key: ConfigKey.property_height,
13385
13720
  // Same as image
13386
13721
  description: "Height for the embedded content, used to define the height in pixels",
13387
- format: TagFormat.number
13722
+ format: TagFormat.number,
13723
+ nullable: true
13388
13724
  },
13389
13725
  {
13390
13726
  key: ConfigKey.property_vendorUrl,
@@ -13422,7 +13758,8 @@ var BITS = {
13422
13758
  {
13423
13759
  key: ConfigKey.property_jupyterExecutionCount,
13424
13760
  description: "Execution count for the Jupyter output, used to define the execution order",
13425
- format: TagFormat.number
13761
+ format: TagFormat.number,
13762
+ nullable: true
13426
13763
  }
13427
13764
  ],
13428
13765
  textFormatDefault: TextFormat.plainText
@@ -13972,7 +14309,7 @@ var instance2 = new Config();
13972
14309
  // src/generated/package_info.ts
13973
14310
  var PACKAGE_INFO = {
13974
14311
  "name": "@gmb/bitmark-parser-generator",
13975
- "version": "5.35.0",
14312
+ "version": "5.36.0",
13976
14313
  "license": "ISC"};
13977
14314
  var Environment = {
13978
14315
  unknown: "",
@@ -14469,6 +14806,8 @@ var NodeType = {
14469
14806
  definition: "definition",
14470
14807
  definitions: "definitions",
14471
14808
  definitionsValue: "definitionsValue",
14809
+ displayName: "displayName",
14810
+ displayNameValue: "displayNameValue",
14472
14811
  diffContext: "diffContext",
14473
14812
  diffContextValue: "diffContextValue",
14474
14813
  diffOp: "diffOp",
@@ -28206,6 +28545,12 @@ var Builder = class extends BaseBuilder {
28206
28545
  data.publisherName,
28207
28546
  options
28208
28547
  ),
28548
+ displayName: this.toAstProperty(
28549
+ bitType,
28550
+ ConfigKey.property_displayName,
28551
+ data.displayName,
28552
+ options
28553
+ ),
28209
28554
  theme: this.toAstProperty(bitType, ConfigKey.property_theme, data.theme, options),
28210
28555
  rtl: this.toAstProperty(bitType, ConfigKey.property_rtl, data.rtl, options),
28211
28556
  computerLanguage: this.toAstProperty(
@@ -44171,7 +44516,7 @@ var ConfigBuilder = class {
44171
44516
  }
44172
44517
  const outputFolder = opts.outputDir ?? "assets/config";
44173
44518
  const outputFolderBits = path3.join(outputFolder, "bits");
44174
- const outputFolderGroups = path3.join(outputFolder, "partials");
44519
+ const outputFolderGroups = path3.join(outputFolder, "groups");
44175
44520
  const outputFolderCards = path3.join(outputFolder, "cards");
44176
44521
  fs4.ensureDirSync(outputFolderBits);
44177
44522
  fs4.ensureDirSync(outputFolderGroups);
@@ -44206,6 +44551,15 @@ var ConfigBuilder = class {
44206
44551
  }
44207
44552
  return [{ key: groupKey }];
44208
44553
  };
44554
+ const mappingKeysField = (base, json, html) => {
44555
+ const record = {};
44556
+ for (const [id, value] of Object.entries(base ?? {})) {
44557
+ if (value != null) record[id] = value;
44558
+ }
44559
+ if (json.present && json.value != null) record.json = json.value;
44560
+ if (html.present && html.value != null) record.html = html.value;
44561
+ return Object.keys(record).length > 0 ? { mappingKeys: record } : {};
44562
+ };
44209
44563
  const bareKeyForProperty = (key) => {
44210
44564
  if (key.startsWith("@") || key.startsWith("&")) return key.substring(1);
44211
44565
  return void 0;
@@ -44226,22 +44580,20 @@ var ConfigBuilder = class {
44226
44580
  if (tag.format === TagFormat.plainText) {
44227
44581
  format = "string";
44228
44582
  } else if (tag.format === TagFormat.boolean) {
44229
- format = "bool";
44230
- } else if (tag.format === TagFormat.bitmarkText) {
44231
- format = "bitmark";
44583
+ format = "boolean";
44232
44584
  } else if (tag.format === TagFormat.number) {
44233
44585
  format = "number";
44234
44586
  } else {
44235
- format = "bitmark--";
44587
+ format = "bitmark+";
44236
44588
  }
44237
44589
  } else if (tagType === BitTagConfigKeyType.property) {
44238
44590
  tagName = tag.key;
44239
44591
  if (tag.format === TagFormat.plainText) {
44240
44592
  format = "string";
44241
44593
  } else if (tag.format === TagFormat.boolean) {
44242
- format = "bool";
44594
+ format = "boolean";
44243
44595
  } else if (tag.format === TagFormat.bitmarkText) {
44244
- format = "bitmark";
44596
+ format = "bitmark+";
44245
44597
  } else if (tag.format === TagFormat.number) {
44246
44598
  format = "number";
44247
44599
  } else if (tag.format === TagFormat.coordinates) {
@@ -44273,8 +44625,11 @@ var ConfigBuilder = class {
44273
44625
  tags2.push({
44274
44626
  type: "group",
44275
44627
  key: ref.key,
44276
- ...hasExportChosen ? { jsonKey: exportJsonKeyChosen } : {},
44277
- ...hasHtmlChosen ? { htmlKey: htmlKeyChosen } : {},
44628
+ ...mappingKeysField(
44629
+ { ...ref.extraKeys ?? {}, ...tag.mappingKeys ?? {} },
44630
+ { value: exportJsonKeyChosen, present: hasExportChosen },
44631
+ { value: htmlKeyChosen, present: hasHtmlChosen }
44632
+ ),
44278
44633
  ...min != null ? { min } : {},
44279
44634
  ...max != null ? { max } : {},
44280
44635
  ...description ? { description } : {}
@@ -44291,53 +44646,48 @@ var ConfigBuilder = class {
44291
44646
  chain = chainTags;
44292
44647
  }
44293
44648
  const hasExport = Object.prototype.hasOwnProperty.call(tag, "exportJsonKey");
44294
- let exportJsonKeyField;
44295
- if (hasExport) {
44296
- exportJsonKeyField = { jsonKey: tag.exportJsonKey };
44297
- } else if (legacyIsTrivialDefault(tag)) {
44298
- exportJsonKeyField = {};
44299
- } else {
44649
+ if (!hasExport && !legacyIsTrivialDefault(tag)) {
44300
44650
  const headingPath = [...pathStack, `tags.${tag.key}`].join(" / ");
44301
44651
  exportJsonKeyErrors.push(
44302
44652
  `Missing exportJsonKey for non-default jsonKey at ${headingPath}` + (tag.jsonKey ? ` (legacy: \`${tag.jsonKey}\`)` : ` (symbol-mapped tag \`${tag.key}\`)`)
44303
44653
  );
44304
- exportJsonKeyField = {};
44305
44654
  }
44306
44655
  const hasHtml = Object.prototype.hasOwnProperty.call(tag, "htmlKey");
44307
- const htmlKeyField = hasHtml ? { htmlKey: tag.htmlKey } : {};
44308
44656
  const t = {
44309
44657
  type: "tag",
44310
44658
  key: tagName,
44311
- ...exportJsonKeyField,
44312
- ...htmlKeyField,
44313
- format,
44314
- default: tag.defaultValue ?? null,
44659
+ ...mappingKeysField(
44660
+ tag.mappingKeys,
44661
+ { value: tag.exportJsonKey, present: hasExport },
44662
+ { value: tag.htmlKey, present: hasHtml }
44663
+ ),
44664
+ ...format && format !== "string" ? { format } : {},
44665
+ ...tag.defaultValue != null ? { default: tag.defaultValue } : {},
44315
44666
  ...tag.nullable ? { nullable: true } : {},
44316
- min: tag.minCount == null ? 0 : tag.minCount,
44317
- max: tag.maxCount == null ? 1 : tag.maxCount,
44667
+ ...tag.minCount != null && tag.minCount !== 0 ? { min: tag.minCount } : {},
44668
+ ...tag.maxCount != null && tag.maxCount !== 1 ? { max: tag.maxCount } : {},
44318
44669
  description: tag.description ?? "",
44319
44670
  tags: chain
44320
44671
  };
44321
44672
  tags2.push(t);
44322
44673
  return tags2;
44323
44674
  };
44324
- const cardJsonKeyField = (container, legacyKey, exportKey, pathHeading) => {
44675
+ const cardMappingKeysField = (container, base, legacyKey, exportKey, htmlExportKey, pathHeading) => {
44325
44676
  const c = container;
44326
44677
  const hasExport = Object.prototype.hasOwnProperty.call(c, exportKey);
44327
- if (hasExport) return { jsonKey: c[exportKey] };
44328
- const legacy = c[legacyKey];
44329
- if (legacy == null) return {};
44330
- exportJsonKeyErrors.push(
44331
- `Missing exportJsonKey for non-default jsonKey at ${pathHeading} (legacy: \`${legacy}\`)`
44332
- );
44333
- return {};
44334
- };
44335
- const cardHtmlKeyField = (container, htmlExportKey) => {
44336
- const c = container;
44337
- if (Object.prototype.hasOwnProperty.call(c, htmlExportKey)) {
44338
- return { htmlKey: c[htmlExportKey] };
44678
+ if (!hasExport && c[legacyKey] != null) {
44679
+ exportJsonKeyErrors.push(
44680
+ `Missing exportJsonKey for non-default jsonKey at ${pathHeading} (legacy: \`${c[legacyKey]}\`)`
44681
+ );
44339
44682
  }
44340
- return {};
44683
+ return mappingKeysField(
44684
+ base,
44685
+ { value: c[exportKey], present: hasExport },
44686
+ {
44687
+ value: c[htmlExportKey],
44688
+ present: Object.prototype.hasOwnProperty.call(c, htmlExportKey)
44689
+ }
44690
+ );
44341
44691
  };
44342
44692
  const serializeCardSet = (cardSetKey) => {
44343
44693
  const variantBodyFormat = (variant) => variant.format ?? TextFormat.bitmarkText;
@@ -44368,11 +44718,17 @@ var ConfigBuilder = class {
44368
44718
  variantTags.push(...processTagEntries(variantTag, [variantPath]));
44369
44719
  }
44370
44720
  return {
44371
- ...cardJsonKeyField(variant, "jsonKey", "exportJsonKey", variantPath),
44372
- ...cardHtmlKeyField(variant, "htmlKey"),
44373
- format: variantBodyFormat(variant),
44721
+ ...cardMappingKeysField(
44722
+ variant,
44723
+ void 0,
44724
+ "jsonKey",
44725
+ "exportJsonKey",
44726
+ "htmlKey",
44727
+ variantPath
44728
+ ),
44729
+ bodyFormat: variantBodyFormat(variant),
44374
44730
  tags: variantTags,
44375
- repeatCount: variant.repeatCount ?? 1,
44731
+ ...variant.repeatCount != null && variant.repeatCount !== 1 ? { repeatCount: variant.repeatCount } : {},
44376
44732
  ...variant.bodyRequired ? { bodyRequired: true } : {},
44377
44733
  ...variant.bodyAllowed === false ? { bodyForbidden: true } : {}
44378
44734
  };
@@ -44380,8 +44736,14 @@ var ConfigBuilder = class {
44380
44736
  return {
44381
44737
  name: side.name,
44382
44738
  ...side.repeat ? { repeat: side.repeat } : {},
44383
- ...cardJsonKeyField(side, "jsonKey", "exportJsonKey", sidePath),
44384
- ...cardHtmlKeyField(side, "htmlKey"),
44739
+ ...cardMappingKeysField(
44740
+ side,
44741
+ side.mappingKeys,
44742
+ "jsonKey",
44743
+ "exportJsonKey",
44744
+ "htmlKey",
44745
+ sidePath
44746
+ ),
44385
44747
  variants
44386
44748
  };
44387
44749
  });
@@ -44392,20 +44754,40 @@ var ConfigBuilder = class {
44392
44754
  const hasSideHtml = Object.prototype.hasOwnProperty.call(section, "sideHtmlKey");
44393
44755
  let cardSides = sides;
44394
44756
  if (hasSideExport || section.sideJsonKey != null || hasSideHtml) {
44395
- const sideOverride = cardJsonKeyField(
44396
- section,
44397
- "sideJsonKey",
44398
- "sideExportJsonKey",
44399
- `${sectionPath} / sides.*`
44400
- );
44401
- const sideHtmlOverride = cardHtmlKeyField(section, "sideHtmlKey");
44402
- cardSides = sides.map((s) => ({ ...s, ...sideOverride, ...sideHtmlOverride }));
44757
+ if (!hasSideExport && section.sideJsonKey != null) {
44758
+ exportJsonKeyErrors.push(
44759
+ `Missing exportJsonKey for non-default jsonKey at ${sectionPath} / sides.* (legacy: \`${section.sideJsonKey}\`)`
44760
+ );
44761
+ }
44762
+ cardSides = sides.map((s) => {
44763
+ const record = { ...s.mappingKeys ?? {} };
44764
+ if (hasSideExport) {
44765
+ if (section.sideExportJsonKey != null) record.json = section.sideExportJsonKey;
44766
+ else delete record.json;
44767
+ }
44768
+ if (hasSideHtml) {
44769
+ if (section.sideHtmlKey != null) record.html = section.sideHtmlKey;
44770
+ else delete record.html;
44771
+ }
44772
+ return {
44773
+ name: s.name,
44774
+ ...s.repeat ? { repeat: s.repeat } : {},
44775
+ ...Object.keys(record).length > 0 ? { mappingKeys: record } : {},
44776
+ variants: s.variants
44777
+ };
44778
+ });
44403
44779
  }
44404
44780
  return {
44405
44781
  name: sectionName,
44406
44782
  ...section.isDefault ? { isDefault: true } : {},
44407
- ...cardJsonKeyField(section, "jsonKey", "exportJsonKey", sectionPath),
44408
- ...cardHtmlKeyField(section, "htmlKey"),
44783
+ ...cardMappingKeysField(
44784
+ section,
44785
+ section.mappingKeys,
44786
+ "jsonKey",
44787
+ "exportJsonKey",
44788
+ "htmlKey",
44789
+ sectionPath
44790
+ ),
44409
44791
  // PLAN-085: per-section cardinality. Emit only when non-default
44410
44792
  // (treat `0` / undefined as "unbounded — omit").
44411
44793
  ...section.minCount != null && section.minCount !== 0 ? { min: section.minCount } : {},
@@ -44413,7 +44795,18 @@ var ConfigBuilder = class {
44413
44795
  sides: cardSides
44414
44796
  };
44415
44797
  });
44416
- return { name: normalizedKey, ...cardHtmlKeyField(cardSetConfig, "htmlKey"), cards };
44798
+ return {
44799
+ name: normalizedKey,
44800
+ ...mappingKeysField(
44801
+ void 0,
44802
+ { present: false },
44803
+ {
44804
+ value: cardSetConfig.htmlKey,
44805
+ present: Object.prototype.hasOwnProperty.call(cardSetConfig, "htmlKey")
44806
+ }
44807
+ ),
44808
+ cards
44809
+ };
44417
44810
  }
44418
44811
  const cardSetPath = `cardSets.${normalizedKey} / cards.default`;
44419
44812
  return {
@@ -44422,8 +44815,14 @@ var ConfigBuilder = class {
44422
44815
  {
44423
44816
  name: "default",
44424
44817
  isDefault: true,
44425
- ...cardJsonKeyField(cardSetConfig, "jsonKey", "exportJsonKey", cardSetPath),
44426
- ...cardHtmlKeyField(cardSetConfig, "htmlKey"),
44818
+ ...cardMappingKeysField(
44819
+ cardSetConfig,
44820
+ cardSetConfig.mappingKeys,
44821
+ "jsonKey",
44822
+ "exportJsonKey",
44823
+ "htmlKey",
44824
+ cardSetPath
44825
+ ),
44427
44826
  sides
44428
44827
  }
44429
44828
  ]
@@ -44459,14 +44858,19 @@ var ConfigBuilder = class {
44459
44858
  ...t.max != null ? { max: t.max } : {},
44460
44859
  ...t.description ? { description: t.description } : {}
44461
44860
  };
44462
- if (Object.prototype.hasOwnProperty.call(t, "jsonKey")) {
44463
- ref.exportJsonKey = t.jsonKey;
44861
+ const record = t.mappingKeys ?? {};
44862
+ if (Object.prototype.hasOwnProperty.call(record, "json")) {
44863
+ ref.exportJsonKey = record.json;
44464
44864
  ref.hasExportJsonKey = true;
44465
44865
  }
44466
- if (Object.prototype.hasOwnProperty.call(t, "htmlKey")) {
44467
- ref.htmlKey = t.htmlKey;
44866
+ if (Object.prototype.hasOwnProperty.call(record, "html")) {
44867
+ ref.htmlKey = record.html;
44468
44868
  ref.hasHtmlKey = true;
44469
44869
  }
44870
+ const extras = Object.fromEntries(
44871
+ Object.entries(record).filter(([id]) => id !== "json" && id !== "html")
44872
+ );
44873
+ if (Object.keys(extras).length > 0) ref.extraKeys = extras;
44470
44874
  replacements.push(ref);
44471
44875
  }
44472
44876
  squashedGroups.set(groupKey, replacements);
@@ -44500,8 +44904,11 @@ var ConfigBuilder = class {
44500
44904
  pushOrReplace({
44501
44905
  type: "group",
44502
44906
  key: ref.key,
44503
- ...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
44504
- ...ref.hasHtmlKey ? { htmlKey: ref.htmlKey } : {},
44907
+ ...mappingKeysField(
44908
+ ref.extraKeys,
44909
+ { value: ref.exportJsonKey, present: !!ref.hasExportJsonKey },
44910
+ { value: ref.htmlKey, present: !!ref.hasHtmlKey }
44911
+ ),
44505
44912
  ...ref.min != null ? { min: ref.min } : {},
44506
44913
  ...ref.max != null ? { max: ref.max } : {},
44507
44914
  ...ref.description ? { description: ref.description } : {}
@@ -44514,8 +44921,11 @@ var ConfigBuilder = class {
44514
44921
  pushOrReplace({
44515
44922
  type: "group",
44516
44923
  key: ref.key,
44517
- ...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
44518
- ...ref.hasHtmlKey ? { htmlKey: ref.htmlKey } : {},
44924
+ ...mappingKeysField(
44925
+ ref.extraKeys,
44926
+ { value: ref.exportJsonKey, present: !!ref.hasExportJsonKey },
44927
+ { value: ref.htmlKey, present: !!ref.hasHtmlKey }
44928
+ ),
44519
44929
  ...ref.min != null ? { min: ref.min } : {},
44520
44930
  ...ref.max != null ? { max: ref.max } : {},
44521
44931
  ...ref.description ? { description: ref.description } : {}
@@ -44542,20 +44952,17 @@ var ConfigBuilder = class {
44542
44952
  description: b.description ?? "",
44543
44953
  since: resolvedBitConfig.since,
44544
44954
  deprecated: resolvedBitConfig.deprecated,
44545
- history: [
44546
- {
44547
- version: resolvedBitConfig.since,
44548
- changes: ["Initial version"]
44549
- }
44550
- ],
44551
- format: resolvedBitConfig.textFormatDefault ?? "bitmark--",
44552
- bodyRequired: resolvedBitConfig.bodyRequired ?? false,
44553
- bodyForbidden: !(resolvedBitConfig.bodyAllowed ?? true),
44554
- footerRequired: resolvedBitConfig.footerRequired ?? false,
44555
- footerForbidden: !(resolvedBitConfig.footerAllowed ?? true),
44556
- resourceAttachmentAllowed: resolvedBitConfig.resourceAttachmentAllowed ?? true,
44955
+ bodyFormat: resolvedBitConfig.textFormatDefault ?? "bitmark--",
44956
+ ...resolvedBitConfig.bodyRequired ? { bodyRequired: true } : {},
44957
+ ...resolvedBitConfig.bodyAllowed === false ? { bodyForbidden: true } : {},
44958
+ ...resolvedBitConfig.footerRequired ? { footerRequired: true } : {},
44959
+ ...resolvedBitConfig.footerAllowed === false ? { footerForbidden: true } : {},
44960
+ ...resolvedBitConfig.resourceAttachmentAllowed === false ? { resourceAttachmentAllowed: false } : {},
44961
+ // Bit-level named key mappings (element keys for markup import),
44962
+ // carried verbatim from the raw config.
44963
+ ...mappingKeysField(b.mappingKeys, { present: false }, { present: false }),
44557
44964
  tags: tags2,
44558
- ...cardRef ? { card: cardRef } : {}
44965
+ ...cardRef ? { cardSet: cardRef } : {}
44559
44966
  };
44560
44967
  const output = path3.join(outputFolderBits, `${b.bitType}.jsonc`);
44561
44968
  const str = JSON.stringify(bitJson, null, 2);
@@ -44583,14 +44990,7 @@ var ConfigBuilder = class {
44583
44990
  const bitJson = {
44584
44991
  name: groupKey,
44585
44992
  description: g.description ?? "",
44586
- since: "UNKNOWN",
44587
44993
  deprecated: g.deprecated,
44588
- history: [
44589
- {
44590
- version: "UNKNOWN",
44591
- changes: ["Initial version"]
44592
- }
44593
- ],
44594
44994
  tags: tags2
44595
44995
  // cards: [
44596
44996
  // {
@@ -44644,8 +45044,11 @@ var ConfigBuilder = class {
44644
45044
  tags2.push({
44645
45045
  type: "group",
44646
45046
  key: ref.key,
44647
- ...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
44648
- ...ref.hasHtmlKey ? { htmlKey: ref.htmlKey } : {},
45047
+ ...mappingKeysField(
45048
+ ref.extraKeys,
45049
+ { value: ref.exportJsonKey, present: !!ref.hasExportJsonKey },
45050
+ { value: ref.htmlKey, present: !!ref.hasHtmlKey }
45051
+ ),
44649
45052
  ...ref.min != null ? { min: ref.min } : {},
44650
45053
  ...ref.max != null ? { max: ref.max } : {},
44651
45054
  ...ref.description ? { description: ref.description } : {}
@@ -44666,14 +45069,7 @@ var ConfigBuilder = class {
44666
45069
  const bitJson = {
44667
45070
  name: groupKey,
44668
45071
  description: b.description ?? "",
44669
- since: "UNKNOWN",
44670
45072
  deprecated: b.deprecated,
44671
- history: [
44672
- {
44673
- version: "UNKNOWN",
44674
- changes: ["Initial version"]
44675
- }
44676
- ],
44677
45073
  tags: tags2
44678
45074
  };
44679
45075
  const output = path3.join(outputFolderGroups, `${groupKey}.jsonc`);
@@ -44714,7 +45110,7 @@ var ConfigBuilder = class {
44714
45110
  validateConfigTree(outputFolder) {
44715
45111
  const errors = [];
44716
45112
  const outputFolderBits = path3.join(outputFolder, "bits");
44717
- const outputFolderGroups = path3.join(outputFolder, "partials");
45113
+ const outputFolderGroups = path3.join(outputFolder, "groups");
44718
45114
  const outputFolderCards = path3.join(outputFolder, "cards");
44719
45115
  const availableGroups = /* @__PURE__ */ new Set();
44720
45116
  if (fs4.existsSync(outputFolderGroups)) {
@@ -44788,7 +45184,7 @@ var ConfigBuilder = class {
44788
45184
  const content = fs4.readFileSync(filePath, "utf-8");
44789
45185
  const config = JSON.parse(content);
44790
45186
  if (config.tags && Array.isArray(config.tags)) {
44791
- checkTags(config.tags, `partials/${file}`, 15);
45187
+ checkTags(config.tags, `groups/${file}`, 15);
44792
45188
  }
44793
45189
  } catch (err) {
44794
45190
  errors.push(`Failed to parse ${file}: ${err}`);