@gmb/bitmark-parser-generator 5.34.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/index.cjs CHANGED
@@ -332,6 +332,7 @@ var BitType = {
332
332
  extractorPageNumberCollapsible: "extractor-page-number-collapsible",
333
333
  extractorPageWithBlocks: "extractor-page-with-blocks",
334
334
  extractorPageWithBlocksCollapsible: "extractor-page-with-blocks-collapsible",
335
+ extractorReconcile: "extractor-reconcile",
335
336
  extractorRepeatedText: "extractor-repeated-text",
336
337
  extractorRule: "extractor-rule",
337
338
  extractorTheme: "extractor-theme",
@@ -1415,6 +1416,7 @@ var propertyKeys = {
1415
1416
  property_dateEnd: "@dateEnd",
1416
1417
  property_decimalPlaces: "@decimalPlaces",
1417
1418
  property_deeplink: "@deeplink",
1419
+ property_displayName: "@displayName",
1418
1420
  property_diffContext: "@diffContext",
1419
1421
  property_diffOp: "@diffOp",
1420
1422
  property_diffRef: "@diffRef",
@@ -1570,6 +1572,7 @@ var propertyKeys = {
1570
1572
  property_revealSolutions: "@revealSolutions",
1571
1573
  property_reviewTag: "@reviewTag",
1572
1574
  property_reviewerTag: "@reviewerTag",
1575
+ property_rightsPolicy: "@rightsPolicy",
1573
1576
  property_sampleSolution: "@sampleSolution",
1574
1577
  property_scormSource: "@scormSource",
1575
1578
  property_search: "@search",
@@ -2563,9 +2566,30 @@ var CARDSETS = {
2563
2566
  [CardSetConfigKey.definitionList]: {
2564
2567
  jsonKey: "definitions",
2565
2568
  exportJsonKey: { definitions: "$" },
2569
+ // PLAN-141 F1 (NISO import): each <def-item> is one card; the sides
2570
+ // read <term>/<def>; the enclosing <legend>'s <title> lands on the
2571
+ // term side's heading tag ([#Key] header card).
2572
+ // PLAN-141 F3: a <tbx:langSet> is ALSO one card (a terminology entry —
2573
+ // its enclosing <tbx:termEntry> is a transparent claim wrapper); its
2574
+ // children compose the term/definition sides via the side rules below.
2575
+ mappingKeys: {
2576
+ "xml-niso-iec": [
2577
+ { "@el": "def-item", "@children": "$" },
2578
+ { "@el": "tbx:langSet", "@children": "$" }
2579
+ ]
2580
+ },
2566
2581
  sides: [
2567
2582
  {
2568
2583
  name: "term",
2584
+ // F3: every <tbx:tig>'s <tbx:term> STACKS one-per-line onto the
2585
+ // single term side (the "$\n" template's authored separator; the
2586
+ // trailing one is trimmed) — the PDF's Maus/Mus/M/Müsli stack.
2587
+ mappingKeys: {
2588
+ "xml-niso-iec": [
2589
+ { "@el": "term", "@text": "$" },
2590
+ { "@el": "tbx:tig", "@children": { "@el": "tbx:term", "@text": "$\n" } }
2591
+ ]
2592
+ },
2569
2593
  variants: [
2570
2594
  {
2571
2595
  jsonKey: "term.text",
@@ -2579,8 +2603,10 @@ var CARDSETS = {
2579
2603
  key: ConfigKey.tag_title,
2580
2604
  description: "Title of the definition.",
2581
2605
  format: TagFormat.plainText,
2606
+ nullable: true,
2582
2607
  jsonKey: "^heading.forKeys",
2583
- exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2608
+ exportJsonKey: { "@bit": { heading: { forKeys: "$" } } },
2609
+ mappingKeys: { "xml-niso-iec": { "@el": "title", "@text": "$" } }
2584
2610
  },
2585
2611
  {
2586
2612
  key: ConfigKey.group_resourceIcon,
@@ -2606,6 +2632,24 @@ var CARDSETS = {
2606
2632
  },
2607
2633
  {
2608
2634
  name: "definition",
2635
+ // F3: the definition side COMPOSES from the entry's fields in
2636
+ // document order, with the ES-rendered locale affixes AUTHORED as
2637
+ // value-position templates (never engine text): the subject field
2638
+ // in ⟨⟩ glues (trailing space) onto the definition line; example /
2639
+ // notes / source follow as blank-line-separated lines. The TBX
2640
+ // grammar flags (normativeAuthorization, termType, partOfSpeech,
2641
+ // grammaticalNumber) are unrendered machine-only data — dropped and
2642
+ // recorded (catalog R-2, reviewed under D7 max-preservation).
2643
+ mappingKeys: {
2644
+ "xml-niso-iec": [
2645
+ { "@el": "def", "@children": "$" },
2646
+ { "@el": "tbx:subjectField", "@text": "\u27E8$\u27E9 " },
2647
+ { "@el": "tbx:definition", "@children": "$" },
2648
+ { "@el": "tbx:example", "@children": "BEISPIEL $" },
2649
+ { "@el": "tbx:note", "@children": "Anmerkung zu Begriff: $" },
2650
+ { "@el": "tbx:source", "@text": "[QUELLE: $]" }
2651
+ ]
2652
+ },
2609
2653
  variants: [
2610
2654
  {
2611
2655
  jsonKey: "definition.text",
@@ -2619,6 +2663,7 @@ var CARDSETS = {
2619
2663
  key: ConfigKey.tag_title,
2620
2664
  description: "Title of the definition.",
2621
2665
  format: TagFormat.plainText,
2666
+ nullable: true,
2622
2667
  jsonKey: "^heading.forValues",
2623
2668
  exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2624
2669
  },
@@ -2697,6 +2742,7 @@ var CARDSETS = {
2697
2742
  key: ConfigKey.tag_title,
2698
2743
  description: "Title of the definition.",
2699
2744
  format: TagFormat.plainText,
2745
+ nullable: true,
2700
2746
  jsonKey: "^heading.forKeys",
2701
2747
  exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2702
2748
  },
@@ -2738,6 +2784,7 @@ var CARDSETS = {
2738
2784
  key: ConfigKey.tag_title,
2739
2785
  description: "Title of the definition.",
2740
2786
  format: TagFormat.plainText,
2787
+ nullable: true,
2741
2788
  jsonKey: "^heading.forValues",
2742
2789
  exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2743
2790
  },
@@ -2851,6 +2898,7 @@ var CARDSETS = {
2851
2898
  key: ConfigKey.tag_title,
2852
2899
  description: "Title of the match pair.",
2853
2900
  format: TagFormat.plainText,
2901
+ nullable: true,
2854
2902
  jsonKey: "^heading.forKeys",
2855
2903
  exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2856
2904
  },
@@ -2980,6 +3028,7 @@ var CARDSETS = {
2980
3028
  key: ConfigKey.tag_title,
2981
3029
  description: "Title of the match pair.",
2982
3030
  format: TagFormat.plainText,
3031
+ nullable: true,
2983
3032
  jsonKey: "^heading.forValues",
2984
3033
  exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2985
3034
  },
@@ -3026,6 +3075,7 @@ var CARDSETS = {
3026
3075
  key: ConfigKey.tag_title,
3027
3076
  description: "Title of the audio match pair.",
3028
3077
  format: TagFormat.plainText,
3078
+ nullable: true,
3029
3079
  jsonKey: "^heading.forKeys",
3030
3080
  exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
3031
3081
  },
@@ -3057,6 +3107,7 @@ var CARDSETS = {
3057
3107
  key: ConfigKey.tag_title,
3058
3108
  description: "Title of the audio match pair.",
3059
3109
  format: TagFormat.plainText,
3110
+ nullable: true,
3060
3111
  jsonKey: "^heading.forValues",
3061
3112
  exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
3062
3113
  },
@@ -3094,6 +3145,7 @@ var CARDSETS = {
3094
3145
  key: ConfigKey.tag_title,
3095
3146
  description: "Title of the image match pair.",
3096
3147
  format: TagFormat.plainText,
3148
+ nullable: true,
3097
3149
  jsonKey: "^heading.forKeys",
3098
3150
  exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
3099
3151
  },
@@ -3125,6 +3177,7 @@ var CARDSETS = {
3125
3177
  key: ConfigKey.tag_title,
3126
3178
  description: "Title of the image match pair.",
3127
3179
  format: TagFormat.plainText,
3180
+ nullable: true,
3128
3181
  jsonKey: "^heading.forValues",
3129
3182
  exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
3130
3183
  },
@@ -3200,6 +3253,7 @@ var CARDSETS = {
3200
3253
  key: ConfigKey.tag_title,
3201
3254
  description: "Title of the match matrix.",
3202
3255
  format: TagFormat.plainText,
3256
+ nullable: true,
3203
3257
  jsonKey: "^heading.forKeys",
3204
3258
  exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
3205
3259
  },
@@ -3312,6 +3366,7 @@ var CARDSETS = {
3312
3366
  key: ConfigKey.tag_title,
3313
3367
  description: "Title of the match matrix.",
3314
3368
  format: TagFormat.plainText,
3369
+ nullable: true,
3315
3370
  jsonKey: "^heading.forValues",
3316
3371
  exportJsonKey: [
3317
3372
  { "@keyonly": { "@bit": { heading: { forValues: [""] } } } },
@@ -3594,6 +3649,7 @@ var CARDSETS = {
3594
3649
  key: ConfigKey.tag_title,
3595
3650
  description: "Title of the feedback.",
3596
3651
  format: TagFormat.plainText,
3652
+ nullable: true,
3597
3653
  jsonKey: "^heading.forKeys",
3598
3654
  exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
3599
3655
  }
@@ -3676,6 +3732,7 @@ var CARDSETS = {
3676
3732
  key: ConfigKey.tag_title,
3677
3733
  description: "Title of the feedback.",
3678
3734
  format: TagFormat.plainText,
3735
+ nullable: true,
3679
3736
  jsonKey: "^heading.forValues",
3680
3737
  exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
3681
3738
  }
@@ -3983,6 +4040,11 @@ var CARDSETS = {
3983
4040
  { table: { header: { rows: ["$"] } } }
3984
4041
  ],
3985
4042
  htmlKey: { "@el": "thead", "@children": { "@el": "tr", "@children": "$" } },
4043
+ // PLAN-141 F2 (NISO import): the XHTML table model NISO uses — a
4044
+ // <thead> SECTION whose <tr> rows are the header cards.
4045
+ mappingKeys: {
4046
+ "xml-niso-iec": { "@el": "thead", "@children": { "@el": "tr", "@children": "$" } }
4047
+ },
3986
4048
  sideJsonKey: "cells[{s}]|set(title=true)",
3987
4049
  sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } },
3988
4050
  // Header cells are `<th>`. The `width` attribute is contributed by the
@@ -3994,12 +4056,21 @@ var CARDSETS = {
3994
4056
  jsonKey: "table.body.rows",
3995
4057
  exportJsonKey: { table: { body: { rows: "$" } } },
3996
4058
  htmlKey: { "@el": "tbody", "@children": { "@el": "tr", "@children": "$" } },
4059
+ // PLAN-141 F2 (NISO import): <tbody> rows are the (default) data cards.
4060
+ mappingKeys: {
4061
+ "xml-niso-iec": { "@el": "tbody", "@children": { "@el": "tr", "@children": "$" } }
4062
+ },
3997
4063
  isDefault: true
3998
4064
  },
3999
4065
  "table-footer": {
4000
4066
  jsonKey: "table.footer.rows",
4001
4067
  exportJsonKey: { table: { footer: { rows: "$" } } },
4002
4068
  htmlKey: { "@el": "tfoot", "@children": { "@el": "tr", "@children": "$" } },
4069
+ // PLAN-141 F2 (NISO import): NISO has no <tfoot> — the footer card's
4070
+ // source is the <table-wrap-foot> block (CONTENT-shaped: no rows; its
4071
+ // prose/notes flatten into one footer card — catalog table-wrap-foot
4072
+ // row; a contained <def-list> promotes as a sibling legend bit).
4073
+ mappingKeys: { "xml-niso-iec": { "@el": "table-wrap-foot", "@children": "$" } },
4003
4074
  sideJsonKey: "cells[{s}]|set(title=true)",
4004
4075
  sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } },
4005
4076
  // Footer cells render as `<th>` (mirrors the header `title: true`
@@ -4016,6 +4087,8 @@ var CARDSETS = {
4016
4087
  // Default (body) cell → `<td>`; the header/footer sections override the
4017
4088
  // side to `<th>` via their sideHtmlKey (HTML.md §8).
4018
4089
  htmlKey: { "@el": "td", "@children": "$" },
4090
+ // PLAN-141 F2 (NISO import): a <td> row child is a body cell side.
4091
+ mappingKeys: { "xml-niso-iec": { "@el": "td", "@children": "$" } },
4019
4092
  variants: [
4020
4093
  {
4021
4094
  jsonKey: "content",
@@ -4033,7 +4106,11 @@ var CARDSETS = {
4033
4106
  // cell with `title: true` automatically.
4034
4107
  jsonKey: "content",
4035
4108
  exportJsonKey: { content: "$" },
4036
- description: "Title text of the table cell (header rows)."
4109
+ description: "Title text of the table cell (header rows).",
4110
+ // PLAN-141 F2 (NISO import): a <th> row child is a TITLE cell —
4111
+ // its content lands in the `[#…]` tag (an empty <th> keeps its
4112
+ // slot as a bare `[#]`).
4113
+ mappingKeys: { "xml-niso-iec": { "@el": "th", "@children": "$" } }
4037
4114
  },
4038
4115
  {
4039
4116
  key: ConfigKey.property_tableCellType,
@@ -4052,6 +4129,9 @@ var CARDSETS = {
4052
4129
  // HTML-C2: contribute a `rowspan` attribute onto the enclosing
4053
4130
  // cell element (`<th>`/`<td>`).
4054
4131
  htmlKey: { "@el": { "@attr": { rowspan: "$" } } },
4132
+ // PLAN-141 F2 (NISO import): recover the source cell's own
4133
+ // `rowspan` attribute (element-scope attr form).
4134
+ mappingKeys: { "xml-niso-iec": { "@el": { "@attr": { rowspan: "$" } } } },
4055
4135
  description: "Number of rows the cell spans.",
4056
4136
  format: TagFormat.number
4057
4137
  },
@@ -4062,6 +4142,9 @@ var CARDSETS = {
4062
4142
  // HTML-C2: contribute a `colspan` attribute onto the enclosing
4063
4143
  // cell element (`<th>`/`<td>`).
4064
4144
  htmlKey: { "@el": { "@attr": { colspan: "$" } } },
4145
+ // PLAN-141 F2 (NISO import): recover the source cell's own
4146
+ // `colspan` attribute (element-scope attr form).
4147
+ mappingKeys: { "xml-niso-iec": { "@el": { "@attr": { colspan: "$" } } } },
4065
4148
  description: "Number of columns the cell spans.",
4066
4149
  format: TagFormat.number
4067
4150
  },
@@ -4083,6 +4166,13 @@ var CARDSETS = {
4083
4166
  // HTML.md §8 + HTML-C2: contribute a `width` attribute onto the
4084
4167
  // enclosing cell element (`<th>`/`<td>`).
4085
4168
  htmlKey: { "@el": { "@attr": { width: "$" } } },
4169
+ // PLAN-141 F2 (NISO import): NISO carries widths as PER-COLUMN
4170
+ // <col width="…"> descriptors at container level, not on cells.
4171
+ // The matched values distribute positionally onto the first
4172
+ // (header) card's sides. Number format ⇒ only an integral
4173
+ // percentage survives ("20.0000%" → 20); a fractional one
4174
+ // (renderer-equalised "4.7619%") is dropped — catalog `col` row.
4175
+ mappingKeys: { "xml-niso-iec": { "@el": "col", "@attr": { width: "$" } } },
4086
4176
  description: "Width for the column.",
4087
4177
  format: TagFormat.number
4088
4178
  }
@@ -4456,13 +4546,44 @@ var GROUPS = {
4456
4546
  key: ConfigKey.property_externalId,
4457
4547
  description: "The external identifier for the bit",
4458
4548
  format: TagFormat.plainText,
4459
- maxCount: Count.infinity
4549
+ maxCount: Count.infinity,
4550
+ // PLAN-140 refs family (NISO import): the machine identifier of a
4551
+ // referenced standard. NESTED content slot — the tag reads (and
4552
+ // consumes) ONLY the <std-id> inside a <std> child; the remaining
4553
+ // designation/title text stays bit body. A <std> without <std-id>
4554
+ // does not fire the key.
4555
+ // PLAN-141 F5: on the [.book] bit, the DATED <std-ref> designation
4556
+ // is the document's external id. Safe rule order: <std-ref> is a
4557
+ // direct bit-element child only under <std-meta> (everywhere else
4558
+ // it nests inside <std>, which the tag spine never reaches).
4559
+ mappingKeys: {
4560
+ "xml-niso-iec": [
4561
+ { "@el": "std", "@children": { "@el": "std-id", "@text": "$" } },
4562
+ { "@el": "std-ref", "@attr": { type: "dated" }, "@text": "$" }
4563
+ ]
4564
+ }
4460
4565
  },
4461
4566
  {
4462
4567
  key: ConfigKey.property_sourceRL,
4463
4568
  description: "The original location of the information in the original source material",
4464
4569
  format: TagFormat.plainText
4465
4570
  },
4571
+ {
4572
+ key: ConfigKey.property_copyright,
4573
+ description: "The copyright information for the bit",
4574
+ format: TagFormat.plainText
4575
+ },
4576
+ {
4577
+ key: ConfigKey.property_license,
4578
+ description: "The license for the bit",
4579
+ format: TagFormat.plainText
4580
+ },
4581
+ {
4582
+ key: ConfigKey.property_rightsPolicy,
4583
+ description: "The rights policy or policies for the bit",
4584
+ format: TagFormat.plainText,
4585
+ maxCount: Count.infinity
4586
+ },
4466
4587
  {
4467
4588
  key: ConfigKey.property_isTemplate,
4468
4589
  description: "If true, the bit is a template",
@@ -4489,7 +4610,8 @@ var GROUPS = {
4489
4610
  {
4490
4611
  key: ConfigKey.property_aiGenerated,
4491
4612
  description: "If true, the bit is AI-generated",
4492
- format: TagFormat.boolean
4613
+ format: TagFormat.boolean,
4614
+ nullable: true
4493
4615
  },
4494
4616
  {
4495
4617
  key: ConfigKey.property_machineTranslated,
@@ -4504,7 +4626,8 @@ var GROUPS = {
4504
4626
  {
4505
4627
  key: ConfigKey.property_spansPageBreak,
4506
4628
  description: "If true, the bit spans a page break",
4507
- format: TagFormat.boolean
4629
+ format: TagFormat.boolean,
4630
+ nullable: true
4508
4631
  },
4509
4632
  {
4510
4633
  key: ConfigKey.property_searchIndex,
@@ -4579,7 +4702,8 @@ var GROUPS = {
4579
4702
  {
4580
4703
  key: ConfigKey.property_diffTime,
4581
4704
  description: "The diff time for the bit",
4582
- format: TagFormat.number
4705
+ format: TagFormat.number,
4706
+ nullable: true
4583
4707
  },
4584
4708
  {
4585
4709
  key: ConfigKey.property_ageRange,
@@ -4590,7 +4714,18 @@ var GROUPS = {
4590
4714
  {
4591
4715
  key: ConfigKey.property_lang,
4592
4716
  description: "The language for the bit",
4593
- format: TagFormat.plainText
4717
+ format: TagFormat.plainText,
4718
+ // PLAN-141 F3 (NISO import): a term-sec's language rides
4719
+ // <tbx:termEntry><tbx:langSet xml:lang> — a nested content slot
4720
+ // whose leaf is a $-in-ATTR-position slot (the nested counterpart
4721
+ // of the value-attr slot). Only termEntry elements match, so the
4722
+ // shared tag is inert everywhere else.
4723
+ mappingKeys: {
4724
+ "xml-niso-iec": {
4725
+ "@el": "tbx:termEntry",
4726
+ "@children": { "@el": "tbx:langSet", "@attr": { "xml:lang": "$" } }
4727
+ }
4728
+ }
4594
4729
  },
4595
4730
  {
4596
4731
  key: ConfigKey.property_publisher,
@@ -4607,6 +4742,7 @@ var GROUPS = {
4607
4742
  key: ConfigKey.property_theme,
4608
4743
  description: "The theme(s) for the bit",
4609
4744
  format: TagFormat.plainText,
4745
+ nullable: true,
4610
4746
  maxCount: Count.infinity
4611
4747
  },
4612
4748
  {
@@ -4625,6 +4761,7 @@ var GROUPS = {
4625
4761
  key: ConfigKey.property_tag,
4626
4762
  description: "The tag(s) for the bit",
4627
4763
  format: TagFormat.plainText,
4764
+ nullable: true,
4628
4765
  maxCount: Count.infinity
4629
4766
  },
4630
4767
  {
@@ -4644,6 +4781,7 @@ var GROUPS = {
4644
4781
  exportJsonKey: { tags: ["$"] },
4645
4782
  description: "The tag(s) for the group",
4646
4783
  format: TagFormat.plainText,
4784
+ nullable: true,
4647
4785
  maxCount: Count.infinity
4648
4786
  }
4649
4787
  ]
@@ -4761,6 +4899,20 @@ var GROUPS = {
4761
4899
  description: "The layer role(s) for the bit",
4762
4900
  format: TagFormat.plainText,
4763
4901
  maxCount: Count.infinity
4902
+ },
4903
+ {
4904
+ // Universal @internalComment — declares in config what Config.ts also
4905
+ // injects programmatically into every bit (its push runs last and wins
4906
+ // the keyed merge, so runtime behaviour is unchanged). Declared here so
4907
+ // the config export (ConfigBuilder → assets/config → configurator →
4908
+ // bitmark.json) carries the tag for downstream parsers. Empty
4909
+ // exportJsonKey: consumed but never emitted to the bit JSON (the value
4910
+ // is routed to parser.internalComments).
4911
+ key: ConfigKey.property_internalComment,
4912
+ description: "Internal comment for the bit.",
4913
+ format: TagFormat.plainText,
4914
+ maxCount: Count.infinity,
4915
+ exportJsonKey: {}
4764
4916
  }
4765
4917
  ]
4766
4918
  },
@@ -4772,6 +4924,9 @@ var GROUPS = {
4772
4924
  key: ConfigKey.tag_item,
4773
4925
  jsonKey: "item",
4774
4926
  exportJsonKey: { item: "$" },
4927
+ // PLAN-140 W3 (NISO import): the clause/note label of a mapped
4928
+ // source element ([%1], [%ANMERKUNG 1]).
4929
+ mappingKeys: { "xml-niso-iec": { "@el": "label", "@text": "$" } },
4775
4930
  description: "The item for the bit",
4776
4931
  chain: [
4777
4932
  {
@@ -4917,7 +5072,8 @@ var GROUPS = {
4917
5072
  {
4918
5073
  key: ConfigKey.property_size,
4919
5074
  description: "The size of the image",
4920
- format: TagFormat.number
5075
+ format: TagFormat.number,
5076
+ nullable: true
4921
5077
  },
4922
5078
  {
4923
5079
  key: ConfigKey.property_format,
@@ -5733,7 +5889,20 @@ var GROUPS = {
5733
5889
  key: ConfigKey.property_language,
5734
5890
  description: "The language of the book",
5735
5891
  format: TagFormat.plainText,
5736
- maxCount: Count.infinity
5892
+ maxCount: Count.infinity,
5893
+ // PLAN-141 F5 (NISO import): only the PRIMARY (first)
5894
+ // <content-language> survives — the maxEmits cap realises the
5895
+ // catalog's document-language rule (extras drop, R-4).
5896
+ mappingKeys: {
5897
+ "xml-niso-iec": [
5898
+ { predicates: [], maxEmits: 1, rule: { "@el": "content-language", "@text": "$" } }
5899
+ ]
5900
+ }
5901
+ },
5902
+ {
5903
+ key: ConfigKey.property_displayName,
5904
+ description: "The display name of the book",
5905
+ format: TagFormat.plainText
5737
5906
  },
5738
5907
  {
5739
5908
  key: ConfigKey.property_customerExternalId,
@@ -5809,7 +5978,18 @@ var GROUPS = {
5809
5978
  description: "The title of the book",
5810
5979
  maxCount: 2,
5811
5980
  jsonKey: "title|multi(count=2, key=subtitle)",
5812
- exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
5981
+ exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }],
5982
+ // PLAN-141 F5 (NISO import): the PRIMARY (first) <title-wrap>'s
5983
+ // assembled <full> title → [#]; the per-language extras drop (R-4).
5984
+ mappingKeys: {
5985
+ "xml-niso-iec": [
5986
+ {
5987
+ predicates: [],
5988
+ maxEmits: 1,
5989
+ rule: { "@el": "title-wrap", "@children": { "@el": "full", "@text": "$" } }
5990
+ }
5991
+ ]
5992
+ }
5813
5993
  },
5814
5994
  {
5815
5995
  key: ConfigKey.property_subtype,
@@ -5820,6 +6000,7 @@ var GROUPS = {
5820
6000
  key: ConfigKey.property_coverImage,
5821
6001
  description: "The cover image(s) of the book",
5822
6002
  format: TagFormat.plainText,
6003
+ nullable: true,
5823
6004
  maxCount: Count.infinity
5824
6005
  },
5825
6006
  {
@@ -6121,22 +6302,26 @@ var GROUPS = {
6121
6302
  {
6122
6303
  key: ConfigKey.property_platformMargin,
6123
6304
  description: "The platform margin",
6124
- format: TagFormat.number
6305
+ format: TagFormat.number,
6306
+ nullable: true
6125
6307
  },
6126
6308
  {
6127
6309
  key: ConfigKey.property_platformBorderRadius,
6128
6310
  description: "The platform border radius",
6129
- format: TagFormat.number
6311
+ format: TagFormat.number,
6312
+ nullable: true
6130
6313
  },
6131
6314
  {
6132
6315
  key: ConfigKey.property_platformSelectionBorderRadius,
6133
6316
  description: "The platform selection border radius",
6134
- format: TagFormat.number
6317
+ format: TagFormat.number,
6318
+ nullable: true
6135
6319
  },
6136
6320
  {
6137
6321
  key: ConfigKey.property_platformNeedsShadow,
6138
6322
  description: "If true, the platform needs shadow",
6139
- format: TagFormat.boolean
6323
+ format: TagFormat.boolean,
6324
+ nullable: true
6140
6325
  }
6141
6326
  ]
6142
6327
  },
@@ -6147,7 +6332,8 @@ var GROUPS = {
6147
6332
  {
6148
6333
  key: ConfigKey.property_revealSolutions,
6149
6334
  description: "If true, the quiz solutions are revealed",
6150
- format: TagFormat.boolean
6335
+ format: TagFormat.boolean,
6336
+ nullable: true
6151
6337
  // defaultValue: 'false',
6152
6338
  },
6153
6339
  {
@@ -6236,7 +6422,13 @@ var GROUPS = {
6236
6422
  {
6237
6423
  key: ConfigKey.property_caption,
6238
6424
  description: "The caption for the resource",
6239
- format: TagFormat.bitmarkText
6425
+ format: TagFormat.bitmarkText,
6426
+ // PLAN-141 F1 (NISO import): a figure's <caption><title> — the
6427
+ // nested content slot reads the title text; the caption rides the
6428
+ // resource chain ([&image:…][@caption:…], catalog D5).
6429
+ mappingKeys: {
6430
+ "xml-niso-iec": { "@el": "caption", "@children": { "@el": "title", "@text": "$" } }
6431
+ }
6240
6432
  },
6241
6433
  {
6242
6434
  key: ConfigKey.property_showInIndex,
@@ -6294,12 +6486,14 @@ var GROUPS = {
6294
6486
  {
6295
6487
  key: ConfigKey.property_width,
6296
6488
  description: "The width of the image",
6297
- format: TagFormat.number
6489
+ format: TagFormat.number,
6490
+ nullable: true
6298
6491
  },
6299
6492
  {
6300
6493
  key: ConfigKey.property_height,
6301
6494
  description: "The height of the image",
6302
- format: TagFormat.number
6495
+ format: TagFormat.number,
6496
+ nullable: true
6303
6497
  },
6304
6498
  {
6305
6499
  key: ConfigKey.property_alt,
@@ -6344,12 +6538,14 @@ var GROUPS = {
6344
6538
  {
6345
6539
  key: ConfigKey.property_width,
6346
6540
  description: "The width of the image",
6347
- format: TagFormat.number
6541
+ format: TagFormat.number,
6542
+ nullable: true
6348
6543
  },
6349
6544
  {
6350
6545
  key: ConfigKey.property_height,
6351
6546
  description: "The height of the image",
6352
- format: TagFormat.number
6547
+ format: TagFormat.number,
6548
+ nullable: true
6353
6549
  },
6354
6550
  {
6355
6551
  key: ConfigKey.property_alt,
@@ -6401,12 +6597,14 @@ var GROUPS = {
6401
6597
  {
6402
6598
  key: ConfigKey.property_width,
6403
6599
  description: "The width of the video",
6404
- format: TagFormat.number
6600
+ format: TagFormat.number,
6601
+ nullable: true
6405
6602
  },
6406
6603
  {
6407
6604
  key: ConfigKey.property_height,
6408
6605
  description: "The height of the video",
6409
- format: TagFormat.number
6606
+ format: TagFormat.number,
6607
+ nullable: true
6410
6608
  },
6411
6609
  {
6412
6610
  key: ConfigKey.property_duration,
@@ -6504,6 +6702,10 @@ var GROUPS = {
6504
6702
  {
6505
6703
  key: ConfigKey.resource_image,
6506
6704
  exportJsonKey: { resource: { type: "image", image: { src: "$" } } },
6705
+ // PLAN-141 F1 (NISO import): the image URL rides the `$`-in-attr
6706
+ // value slot — a <graphic xlink:href> child of the mapped bit
6707
+ // element roots the [&image:URL] chain.
6708
+ mappingKeys: { "xml-niso-iec": { "@el": "graphic", "@attr": { "xlink:href": "$" } } },
6507
6709
  description: "The image resource",
6508
6710
  chain: [
6509
6711
  {
@@ -7378,6 +7580,8 @@ var BITS = {
7378
7580
  maxCount: 2,
7379
7581
  jsonKey: "title|multi(count=2, key=subtitle)",
7380
7582
  exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }],
7583
+ // PLAN-140 W3 (NISO import): the title of a mapped source element.
7584
+ mappingKeys: { "xml-niso-iec": { "@el": "title", "@text": "$" } },
7381
7585
  key: ConfigKey.tag_title,
7382
7586
  description: "The title of the article"
7383
7587
  }
@@ -7419,12 +7623,56 @@ var BITS = {
7419
7623
  [BitType.smartStandardArticleNormative]: {
7420
7624
  since: "1.28.0",
7421
7625
  baseBitType: BitType.standardArticleNormative,
7422
- description: "Smart standard normative article bit"
7626
+ description: "Smart standard normative article bit",
7627
+ // PLAN-140 W3 (NISO import, tranche 1): one article bit per NISO
7628
+ // paragraph (catalog D1). CONTENT keys (@children): the subtree is the
7629
+ // bit's body; nothing inside it promotes. (Ancestor-context normativity
7630
+ // is the non-normative sibling's @ancestor key — plan Q4, resolved.)
7631
+ //
7632
+ // Second rule (catalog D1 push-down): a NUMBERED-PARAGRAPH sec is an
7633
+ // article, not a chapter — the sec-type literal outranks the chapter
7634
+ // key's plain sec|app rule (most-specific-wins). Content key: the sec's
7635
+ // label rides [%] via the label tag key, its inner <p> is the body, its
7636
+ // id is the bit's customerId, and the anchor slot marks it
7637
+ // anchor-bearing.
7638
+ mappingKeys: {
7639
+ "xml-niso-iec": [
7640
+ { "@el": "p", "@attr": { id: "$customerId" }, "@children": "$" },
7641
+ {
7642
+ "@el": "sec",
7643
+ "@attr": { "sec-type": "numbered-paragraph", id: "$customerId" },
7644
+ "@children": "$",
7645
+ "\u25BC": "$anchor"
7646
+ }
7647
+ ]
7648
+ }
7423
7649
  },
7424
7650
  [BitType.smartStandardArticleNonNormative]: {
7425
7651
  since: "1.28.0",
7426
7652
  baseBitType: BitType.standardArticleNonNormative,
7427
- description: "Smart standard non-normative article bit"
7653
+ description: "Smart standard non-normative article bit",
7654
+ // PLAN-140 Q4 (normativity inheritance): a <p> is non-normative because
7655
+ // of an ANCESTOR element — a foreword/intro sec or an informative annex.
7656
+ // @ancestor is a reverse-match-only constraint (forward emission ignores
7657
+ // it); the rules are alternatives, first-satisfied wins, and the
7658
+ // @ancestor literals give this key higher specificity than the plain
7659
+ // normative-article <p> key wherever the context applies.
7660
+ mappingKeys: {
7661
+ "xml-niso-iec": [
7662
+ {
7663
+ "@el": "p",
7664
+ "@attr": { id: "$customerId" },
7665
+ "@ancestor": { "@attr": { "sec-type": "foreword|intro" } },
7666
+ "@children": "$"
7667
+ },
7668
+ {
7669
+ "@el": "p",
7670
+ "@attr": { id: "$customerId" },
7671
+ "@ancestor": { "@attr": { "content-type": "informative" } },
7672
+ "@children": "$"
7673
+ }
7674
+ ]
7675
+ }
7428
7676
  },
7429
7677
  [BitType.smartStandardArticleNormativeCollapsible]: {
7430
7678
  since: "1.28.0",
@@ -7491,7 +7739,8 @@ var BITS = {
7491
7739
  {
7492
7740
  key: ConfigKey.property_coverImage,
7493
7741
  description: "Cover image of the catalog item",
7494
- format: TagFormat.plainText
7742
+ format: TagFormat.plainText,
7743
+ nullable: true
7495
7744
  },
7496
7745
  {
7497
7746
  key: ConfigKey.resource_coverImage,
@@ -7655,7 +7904,8 @@ var BITS = {
7655
7904
  {
7656
7905
  key: ConfigKey.property_coverImage,
7657
7906
  description: "Cover image of the catalog item",
7658
- format: TagFormat.plainText
7907
+ format: TagFormat.plainText,
7908
+ nullable: true
7659
7909
  },
7660
7910
  {
7661
7911
  key: ConfigKey.resource_coverImage,
@@ -7819,7 +8069,8 @@ var BITS = {
7819
8069
  {
7820
8070
  key: ConfigKey.property_coverImage,
7821
8071
  description: "Cover image of the catalog item",
7822
- format: TagFormat.plainText
8072
+ format: TagFormat.plainText,
8073
+ nullable: true
7823
8074
  },
7824
8075
  {
7825
8076
  key: ConfigKey.property_content2Buy,
@@ -8052,7 +8303,8 @@ var BITS = {
8052
8303
  {
8053
8304
  key: ConfigKey.property_maxCreatedBits,
8054
8305
  description: "The maximum number of bits that can be created from this bit",
8055
- format: TagFormat.number
8306
+ format: TagFormat.number,
8307
+ nullable: true
8056
8308
  }
8057
8309
  ],
8058
8310
  textFormatDefault: TextFormat.plainText
@@ -8182,6 +8434,13 @@ var BITS = {
8182
8434
  since: "1.3.0",
8183
8435
  baseBitType: BitType._standard,
8184
8436
  description: "Book bit, used to represent a book",
8437
+ // PLAN-141 F5 (NISO import): the <std-meta> front-matter container is
8438
+ // the [.book] bit (STRUCTURAL, first in document order): primary
8439
+ // title-wrap → [#], primary content-language → [@language], dated
8440
+ // std-ref → [@externalId] (tag keys with maxEmits caps — the NISO
8441
+ // convention puts the document language first). std-meta has no id, so
8442
+ // no anchor/customerId. Remaining leaves drop as recorded loss (R-4).
8443
+ mappingKeys: { "xml-niso-iec": { "@el": "std-meta" } },
8185
8444
  tags: [
8186
8445
  {
8187
8446
  key: ConfigKey.group_bookCommon,
@@ -8468,12 +8727,14 @@ var BITS = {
8468
8727
  {
8469
8728
  key: ConfigKey.property_focusX,
8470
8729
  description: "The X coordinate for focusing the image in the browser",
8471
- format: TagFormat.number
8730
+ format: TagFormat.number,
8731
+ nullable: true
8472
8732
  },
8473
8733
  {
8474
8734
  key: ConfigKey.property_focusY,
8475
8735
  description: "The Y coordinate for focusing the image in the browser",
8476
- format: TagFormat.number
8736
+ format: TagFormat.number,
8737
+ nullable: true
8477
8738
  }
8478
8739
  ]
8479
8740
  },
@@ -8504,6 +8765,15 @@ var BITS = {
8504
8765
  since: "1.3.0",
8505
8766
  baseBitType: BitType._standard,
8506
8767
  description: "Chapter bit, used to define chapters in books or articles",
8768
+ // PLAN-140 W3 (NISO import, tranche 1): recover a chapter from a NISO
8769
+ // section or annex. STRUCTURAL key (no @children content slot): the
8770
+ // element carries no body of its own — tag children (label/title) map
8771
+ // via tag keys, every mapped descendant promotes to a following sibling
8772
+ // bit, and the chapter level derives from nesting depth (catalog D1).
8773
+ // The source id lands as [@customerId] (two-id model, D2).
8774
+ mappingKeys: {
8775
+ "xml-niso-iec": { "@el": "sec|app", "@attr": { id: "$customerId" }, "\u25BC": "$anchor" }
8776
+ },
8507
8777
  tags: [
8508
8778
  {
8509
8779
  exportJsonKey: { anchor: "$" },
@@ -8515,7 +8785,10 @@ var BITS = {
8515
8785
  key: ConfigKey.tag_title,
8516
8786
  description: "The title of the chapter",
8517
8787
  jsonKey: "title|setMulti(level)",
8518
- exportJsonKey: { title: "$", level: "$level" }
8788
+ exportJsonKey: { title: "$", level: "$level" },
8789
+ // PLAN-140 W3 (NISO import): the section/annex title; the heading
8790
+ // level rides the normalizer-derived nesting depth (plan Q2).
8791
+ mappingKeys: { "xml-niso-iec": { "@el": "title", "@text": "$" } }
8519
8792
  },
8520
8793
  {
8521
8794
  key: ConfigKey.property_toc,
@@ -8605,12 +8878,14 @@ var BITS = {
8605
8878
  {
8606
8879
  key: ConfigKey.property_quizCountItems,
8607
8880
  description: "The number of items in the cloze quiz",
8608
- format: TagFormat.boolean
8881
+ format: TagFormat.boolean,
8882
+ nullable: true
8609
8883
  },
8610
8884
  {
8611
8885
  key: ConfigKey.property_quizStrikethroughSolutions,
8612
8886
  description: "If the cloze solutions should be strikethrough",
8613
- format: TagFormat.boolean
8887
+ format: TagFormat.boolean,
8888
+ nullable: true
8614
8889
  },
8615
8890
  {
8616
8891
  key: ConfigKey.group_gap,
@@ -8719,11 +8994,28 @@ var BITS = {
8719
8994
  since: "1.3.0",
8720
8995
  baseBitType: BitType._standard,
8721
8996
  description: "Code bit, used for code snippets in articles or documents",
8997
+ // PLAN-141 F4 (NISO import): a <code> block is a CONTENT bit with a
8998
+ // literal text body; @language recovers as [@computerLanguage] (absent
8999
+ // attr → no tag). Anchor = the source id (D2 revised).
9000
+ mappingKeys: {
9001
+ "xml-niso-iec": {
9002
+ "@el": "code",
9003
+ "@attr": { id: "$customerId", language: "$computerLanguage" },
9004
+ "\u25BC": "$anchor",
9005
+ "@text": "$"
9006
+ }
9007
+ },
8722
9008
  tags: [
8723
9009
  {
8724
9010
  key: ConfigKey.property_computerLanguage,
8725
9011
  description: "The programming language of the code snippet",
8726
- format: TagFormat.plainText
9012
+ format: TagFormat.plainText,
9013
+ // PLAN-141 F4 (NISO import): the bit key's `language` sigil recovers
9014
+ // a present attr; this `@absent` rule supplies the AUTHORED default
9015
+ // when the source carries none (catalog code row — an untyped block
9016
+ // is `[@computerLanguage:text]`). Fires only on foreign imports,
9017
+ // never the carrier round-trip.
9018
+ mappingKeys: { "xml-niso-iec": [{ "@absent": "text" }] }
8727
9019
  },
8728
9020
  {
8729
9021
  key: ConfigKey.property_codeLineNumbers,
@@ -8762,7 +9054,20 @@ var BITS = {
8762
9054
  [BitType.smartStandardFormulaNormative]: {
8763
9055
  since: "3.11.0",
8764
9056
  baseBitType: BitType.formula,
8765
- description: "Smart standard normative formula bit, used for mathematical formulas in smart standards that are normative"
9057
+ description: "Smart standard normative formula bit, used for mathematical formulas in smart standards that are normative",
9058
+ // PLAN-141 F4 (NISO import): a <disp-formula> is a CONTENT bit whose
9059
+ // latex-format body carries the <mml:math> subtree VERBATIM (G1 — no
9060
+ // MathML↔LaTeX transform; ids stripped); <label> → [%]; a contained
9061
+ // <legend> PROMOTES as a sibling legend bit (cards cannot nest in a
9062
+ // body). Anchor = the source id (D2 revised).
9063
+ mappingKeys: {
9064
+ "xml-niso-iec": {
9065
+ "@el": "disp-formula",
9066
+ "@attr": { id: "$customerId" },
9067
+ "\u25BC": "$anchor",
9068
+ "@children": "$"
9069
+ }
9070
+ }
8766
9071
  },
8767
9072
  [BitType.smartStandardRemarkFormula]: {
8768
9073
  since: "3.11.0",
@@ -9289,7 +9594,8 @@ var BITS = {
9289
9594
  {
9290
9595
  key: ConfigKey.property_reasonableNumOfChars,
9291
9596
  description: "The reasonable number of characters for the essay",
9292
- format: TagFormat.number
9597
+ format: TagFormat.number,
9598
+ nullable: true
9293
9599
  },
9294
9600
  {
9295
9601
  key: ConfigKey.property_sampleSolution,
@@ -9722,7 +10028,14 @@ var BITS = {
9722
10028
  [BitType.smartStandardList]: {
9723
10029
  since: "1.28.0",
9724
10030
  baseBitType: BitType.standardList,
9725
- description: "Smart standard list bit, used to create smart standard lists in articles or books"
10031
+ description: "Smart standard list bit, used to create smart standard lists in articles or books",
10032
+ // PLAN-140 refs family (NISO import): a reference list is a STRUCTURAL
10033
+ // bit (no @children — it takes a path ordinal anchor and its <ref>
10034
+ // children promote to sibling list-item bits); its <title> rides [#]
10035
+ // via the title tag key.
10036
+ mappingKeys: {
10037
+ "xml-niso-iec": { "@el": "ref-list", "@attr": { id: "$customerId" }, "\u25BC": "$anchor" }
10038
+ }
9726
10039
  },
9727
10040
  [BitType.smartStandardListCollapsible]: {
9728
10041
  since: "1.28.0",
@@ -9767,7 +10080,17 @@ var BITS = {
9767
10080
  [BitType.smartStandardNoteNonNormative]: {
9768
10081
  since: "1.28.0",
9769
10082
  baseBitType: BitType.standardNoteNonNormative,
9770
- description: "Smart standard non-normative note bit, used to provide non-normative notes in smart standards"
10083
+ description: "Smart standard non-normative note bit, used to provide non-normative notes in smart standards",
10084
+ // PLAN-140 W3 (NISO import, tranche 1). CONTENT key (@children): a
10085
+ // note's inner paragraphs are note body, never separate bits.
10086
+ mappingKeys: {
10087
+ "xml-niso-iec": {
10088
+ "@el": "non-normative-note",
10089
+ "@attr": { id: "$customerId" },
10090
+ "@children": "$",
10091
+ "\u25BC": "$anchor"
10092
+ }
10093
+ }
9771
10094
  },
9772
10095
  [BitType.smartStandardNoteNormativeCollapsible]: {
9773
10096
  since: "1.28.0",
@@ -9874,7 +10197,19 @@ var BITS = {
9874
10197
  [BitType.smartStandardRemarkNonNormative]: {
9875
10198
  since: "1.28.0",
9876
10199
  baseBitType: BitType.standardRemarkNonNormative,
9877
- description: "Smart standard non-normative remark bit, used to provide non-normative remarks in smart standards"
10200
+ description: "Smart standard non-normative remark bit, used to provide non-normative remarks in smart standards",
10201
+ // PLAN-140 Q4 rider: a warning/caution note routes to the remark bit —
10202
+ // the same element as the note key, distinguished by the content-type
10203
+ // attr literal (alias value: forward emits the first alternative,
10204
+ // reverse accepts any). Most-specific-wins beats the plain note key.
10205
+ mappingKeys: {
10206
+ "xml-niso-iec": {
10207
+ "@el": "non-normative-note",
10208
+ "@attr": { "content-type": "warning|caution", id: "$customerId" },
10209
+ "@children": "$",
10210
+ "\u25BC": "$anchor"
10211
+ }
10212
+ }
9878
10213
  },
9879
10214
  [BitType.smartStandardRemarkNormativeCollapsible]: {
9880
10215
  since: "1.28.0",
@@ -10306,6 +10641,12 @@ var BITS = {
10306
10641
  description: "Extractor theme bit, used to store design/theme JSON extracted from documents",
10307
10642
  textFormatDefault: TextFormat.json
10308
10643
  },
10644
+ [BitType.extractorReconcile]: {
10645
+ since: "5.35.0",
10646
+ baseBitType: BitType._standard,
10647
+ description: "Extractor reconcile bit, used to store PDF-compare reconciliation decisions (config and issues) in JSON",
10648
+ textFormatDefault: TextFormat.json
10649
+ },
10309
10650
  [BitType.extractorAiChat]: {
10310
10651
  since: "3.19.0",
10311
10652
  baseBitType: BitType._standard,
@@ -10324,32 +10665,38 @@ var BITS = {
10324
10665
  {
10325
10666
  key: ConfigKey.property_pageNo,
10326
10667
  description: "Page number for the block, used to indicate the page on which the block appears",
10327
- format: TagFormat.number
10668
+ format: TagFormat.number,
10669
+ nullable: true
10328
10670
  },
10329
10671
  {
10330
10672
  key: ConfigKey.property_x,
10331
10673
  description: "X-coordinate for the block, used to position the block on the page",
10332
- format: TagFormat.number
10674
+ format: TagFormat.number,
10675
+ nullable: true
10333
10676
  },
10334
10677
  {
10335
10678
  key: ConfigKey.property_y,
10336
10679
  description: "Y-coordinate for the block, used to position the block on the page",
10337
- format: TagFormat.number
10680
+ format: TagFormat.number,
10681
+ nullable: true
10338
10682
  },
10339
10683
  {
10340
10684
  key: ConfigKey.property_width,
10341
10685
  description: "Width of the block, used to define the size of the block on the page",
10342
- format: TagFormat.number
10686
+ format: TagFormat.number,
10687
+ nullable: true
10343
10688
  },
10344
10689
  {
10345
10690
  key: ConfigKey.property_height,
10346
10691
  description: "Height of the block, used to define the size of the block on the page",
10347
- format: TagFormat.number
10692
+ format: TagFormat.number,
10693
+ nullable: true
10348
10694
  },
10349
10695
  {
10350
10696
  key: ConfigKey.property_index,
10351
10697
  description: "Index of the block, used to order blocks within the extractor page",
10352
- format: TagFormat.number
10698
+ format: TagFormat.number,
10699
+ nullable: true
10353
10700
  },
10354
10701
  {
10355
10702
  key: ConfigKey.property_classification,
@@ -10659,7 +11006,20 @@ var BITS = {
10659
11006
  [BitType.smartStandardLegendNormative]: {
10660
11007
  since: "3.12.0",
10661
11008
  baseBitType: BitType.legend,
10662
- description: "Smart standard normative legend bit, used to provide normative smart standard legends in articles or books"
11009
+ description: "Smart standard normative legend bit, used to provide normative smart standard legends in articles or books",
11010
+ // PLAN-141 F2 (NISO import): a free-standing <legend> (a formula's) or
11011
+ // bare <def-list> (a table footer's — no <legend> wrapper there) that is
11012
+ // NOT the claimed card content of its enclosing bit is a legend bit:
11013
+ // STRUCTURAL-shaped, its <title> and <def-item>s build the
11014
+ // definition-list cards via the card set's authored keys. A <legend>
11015
+ // inside a figure/table bit stays that bit's claimed card content and
11016
+ // never reaches this key. Anchor = the source id (D2 revised).
11017
+ mappingKeys: {
11018
+ "xml-niso-iec": [
11019
+ { "@el": "legend", "@attr": { id: "$customerId" }, "\u25BC": "$anchor" },
11020
+ { "@el": "def-list", "@attr": { id: "$customerId" }, "\u25BC": "$anchor" }
11021
+ ]
11022
+ }
10663
11023
  },
10664
11024
  [BitType.smartStandardRemarkLegend]: {
10665
11025
  since: "3.12.0",
@@ -10714,7 +11074,16 @@ var BITS = {
10714
11074
  [BitType.smartStandardDefinitionListNormative]: {
10715
11075
  since: "5.24.0",
10716
11076
  baseBitType: BitType.standardDefinitionListNormative,
10717
- description: "Smart standard normative definition list bit, used to create normative smart standard definition lists in articles or books"
11077
+ description: "Smart standard normative definition list bit, used to create normative smart standard definition lists in articles or books",
11078
+ // PLAN-141 F3 (NISO import): a terms-and-definitions clause. STRUCTURAL-
11079
+ // shaped: <label> → [%], the tbx:termEntry/langSet subtree builds the
11080
+ // definition-list card via the card set's authored keys (all tig terms
11081
+ // stacked on the term side; definition/example/notes/source composed on
11082
+ // the definition side with authored locale affixes), langSet @xml:lang →
11083
+ // [@lang] (nested attr slot on the tag key). Anchor = the source id.
11084
+ mappingKeys: {
11085
+ "xml-niso-iec": { "@el": "term-sec", "@attr": { id: "$customerId" }, "\u25BC": "$anchor" }
11086
+ }
10718
11087
  },
10719
11088
  [BitType.smartStandardDefinitionListNonNormative]: {
10720
11089
  since: "5.24.0",
@@ -10783,12 +11152,14 @@ var BITS = {
10783
11152
  {
10784
11153
  key: ConfigKey.property_focusX,
10785
11154
  description: "X-coordinate for the focus point, used to define the focus area in the image",
10786
- format: TagFormat.number
11155
+ format: TagFormat.number,
11156
+ nullable: true
10787
11157
  },
10788
11158
  {
10789
11159
  key: ConfigKey.property_focusY,
10790
11160
  description: "Y-coordinate for the focus point, used to define the focus area in the image",
10791
- format: TagFormat.number
11161
+ format: TagFormat.number,
11162
+ nullable: true
10792
11163
  }
10793
11164
  ]
10794
11165
  },
@@ -10895,7 +11266,15 @@ var BITS = {
10895
11266
  [BitType.smartStandardImageFigureNormative]: {
10896
11267
  since: "1.28.0",
10897
11268
  baseBitType: BitType.standardImageFigureNormative,
10898
- description: "Smart standard normative image figure bit, used to create smart standard normative image figures in articles or books"
11269
+ description: "Smart standard normative image figure bit, used to create smart standard normative image figures in articles or books",
11270
+ // PLAN-141 F1 (NISO import): a figure is STRUCTURAL-shaped (no
11271
+ // @children — no body): <label> → [%], <caption>/<graphic> ride the
11272
+ // [&image] resource chain, the <legend> def-list becomes the bit's
11273
+ // definition-list cards, and an inner note PROMOTES as a sibling bit.
11274
+ // Anchor = the source id (D2 revised).
11275
+ mappingKeys: {
11276
+ "xml-niso-iec": { "@el": "fig", "@attr": { id: "$customerId" }, "\u25BC": "$anchor" }
11277
+ }
10899
11278
  },
10900
11279
  [BitType.smartStandardImageFigureNonNormative]: {
10901
11280
  since: "1.28.0",
@@ -11623,7 +12002,19 @@ var BITS = {
11623
12002
  [BitType.smartStandardListItem]: {
11624
12003
  since: "1.28.0",
11625
12004
  baseBitType: BitType.standardListItem,
11626
- description: "Smart standard list item bit, used to create smart standard list items in articles or books"
12005
+ description: "Smart standard list item bit, used to create smart standard list items in articles or books",
12006
+ // PLAN-140 refs family (NISO import): one list-item bit per <ref> —
12007
+ // CONTENT key (its citation subtree is the body), counter anchor scoped
12008
+ // to the containing list, <label> → [%], nested <std-id> → [@externalId]
12009
+ // (the externalId tag key's nested content slot).
12010
+ mappingKeys: {
12011
+ "xml-niso-iec": {
12012
+ "@el": "ref",
12013
+ "@attr": { id: "$customerId" },
12014
+ "@children": "$",
12015
+ "\u25BC": "$anchor"
12016
+ }
12017
+ }
11627
12018
  },
11628
12019
  [BitType.smartStandardListItemCollapsible]: {
11629
12020
  since: "1.28.0",
@@ -12092,7 +12483,8 @@ var BITS = {
12092
12483
  {
12093
12484
  key: ConfigKey.property_product,
12094
12485
  description: "Product reference for the product page, used to link to the product",
12095
- format: TagFormat.plainText
12486
+ format: TagFormat.plainText,
12487
+ nullable: true
12096
12488
  }
12097
12489
  ]
12098
12490
  },
@@ -12111,6 +12503,7 @@ var BITS = {
12111
12503
  key: ConfigKey.property_product,
12112
12504
  description: "Product reference for the product list, used to link to the product",
12113
12505
  format: TagFormat.plainText,
12506
+ nullable: true,
12114
12507
  maxCount: Count.infinity
12115
12508
  }
12116
12509
  // {
@@ -12672,7 +13065,8 @@ var BITS = {
12672
13065
  {
12673
13066
  key: ConfigKey.property_ratingLevelSelected,
12674
13067
  description: "Selected level for the rating survey, used to define the default rating",
12675
- format: TagFormat.number
13068
+ format: TagFormat.number,
13069
+ nullable: true
12676
13070
  },
12677
13071
  {
12678
13072
  key: ConfigKey.property_buttonCaption,
@@ -12727,7 +13121,13 @@ var BITS = {
12727
13121
  // `<caption>` — placed inside the idiomatic `<table>` container as
12728
13122
  // its first child. Outside a table context it falls back to the
12729
13123
  // residual carrier.
12730
- htmlKey: { "@el": "caption", "@children": "$" }
13124
+ htmlKey: { "@el": "caption", "@children": "$" },
13125
+ // PLAN-141 F2 (NISO import): a table-wrap's <caption><title> — the
13126
+ // nested content slot reads the title text (catalog D5: the caption
13127
+ // is a TOP-LEVEL bit property on table bits).
13128
+ mappingKeys: {
13129
+ "xml-niso-iec": { "@el": "caption", "@children": { "@el": "title", "@text": "$" } }
13130
+ }
12731
13131
  },
12732
13132
  {
12733
13133
  key: ConfigKey.property_tableFixedHeader,
@@ -12900,7 +13300,16 @@ var BITS = {
12900
13300
  [BitType.smartStandardTableExtendedNormative]: {
12901
13301
  since: "1.28.0",
12902
13302
  baseBitType: BitType.standardTableExtendedNormative,
12903
- description: "Smart standard normative extended table bit, used to create smart standard normative extended tables in articles or books"
13303
+ description: "Smart standard normative extended table bit, used to create smart standard normative extended tables in articles or books",
13304
+ // PLAN-141 F2 (NISO import): a table-wrap is STRUCTURAL-shaped (no
13305
+ // @children — no body): <label> → [%], <caption><title> → the bit-level
13306
+ // [@caption] (D5), the inner <table>/<table-wrap-foot> build the
13307
+ // table-extended card grid via the card set's authored keys, and a
13308
+ // footer <def-list> PROMOTES as a sibling legend bit. Anchor = the
13309
+ // source id (D2 revised).
13310
+ mappingKeys: {
13311
+ "xml-niso-iec": { "@el": "table-wrap", "@attr": { id: "$customerId" }, "\u25BC": "$anchor" }
13312
+ }
12904
13313
  },
12905
13314
  [BitType.smartStandardTableExtendedNonNormative]: {
12906
13315
  since: "1.28.0",
@@ -12975,7 +13384,8 @@ var BITS = {
12975
13384
  {
12976
13385
  key: ConfigKey.property_maxDisplayLevel,
12977
13386
  description: "Maximum display level for the chapter in the table of contents",
12978
- format: TagFormat.number
13387
+ format: TagFormat.number,
13388
+ nullable: true
12979
13389
  }
12980
13390
  ]
12981
13391
  },
@@ -12987,7 +13397,8 @@ var BITS = {
12987
13397
  {
12988
13398
  key: ConfigKey.property_maxTocChapterLevel,
12989
13399
  description: "Maximum chapter level for the inline table of contents",
12990
- format: TagFormat.number
13400
+ format: TagFormat.number,
13401
+ nullable: true
12991
13402
  }
12992
13403
  ]
12993
13404
  },
@@ -13410,13 +13821,15 @@ var BITS = {
13410
13821
  key: ConfigKey.property_width,
13411
13822
  // Same as image
13412
13823
  description: "Width for the embedded content, used to define the width in pixels",
13413
- format: TagFormat.number
13824
+ format: TagFormat.number,
13825
+ nullable: true
13414
13826
  },
13415
13827
  {
13416
13828
  key: ConfigKey.property_height,
13417
13829
  // Same as image
13418
13830
  description: "Height for the embedded content, used to define the height in pixels",
13419
- format: TagFormat.number
13831
+ format: TagFormat.number,
13832
+ nullable: true
13420
13833
  },
13421
13834
  {
13422
13835
  key: ConfigKey.property_vendorUrl,
@@ -13454,7 +13867,8 @@ var BITS = {
13454
13867
  {
13455
13868
  key: ConfigKey.property_jupyterExecutionCount,
13456
13869
  description: "Execution count for the Jupyter output, used to define the execution order",
13457
- format: TagFormat.number
13870
+ format: TagFormat.number,
13871
+ nullable: true
13458
13872
  }
13459
13873
  ],
13460
13874
  textFormatDefault: TextFormat.plainText
@@ -14004,7 +14418,7 @@ var instance2 = new Config();
14004
14418
  // src/generated/package_info.ts
14005
14419
  var PACKAGE_INFO = {
14006
14420
  "name": "@gmb/bitmark-parser-generator",
14007
- "version": "5.34.0",
14421
+ "version": "5.36.0",
14008
14422
  "author": "Get More Brain Ltd",
14009
14423
  "license": "ISC",
14010
14424
  "description": "A bitmark parser and generator using Peggy.js"
@@ -14533,6 +14947,8 @@ var NodeType = {
14533
14947
  definition: "definition",
14534
14948
  definitions: "definitions",
14535
14949
  definitionsValue: "definitionsValue",
14950
+ displayName: "displayName",
14951
+ displayNameValue: "displayNameValue",
14536
14952
  diffContext: "diffContext",
14537
14953
  diffContextValue: "diffContextValue",
14538
14954
  diffOp: "diffOp",
@@ -14929,6 +15345,8 @@ var NodeType = {
14929
15345
  reviewTagValue: "reviewTagValue",
14930
15346
  reviewerTag: "reviewerTag",
14931
15347
  reviewerTagValue: "reviewerTagValue",
15348
+ rightsPolicy: "rightsPolicy",
15349
+ rightsPolicyValue: "rightsPolicyValue",
14932
15350
  root: "root",
14933
15351
  // bit type (root)
14934
15352
  rows: "rows",
@@ -28298,6 +28716,14 @@ var Builder = class extends BaseBuilder {
28298
28716
  data.jupyterExecutionCount,
28299
28717
  options
28300
28718
  ),
28719
+ copyright: this.toAstProperty(bitType, ConfigKey.property_copyright, data.copyright, options),
28720
+ license: this.toAstProperty(bitType, ConfigKey.property_license, data.license, options),
28721
+ rightsPolicy: this.toAstProperty(
28722
+ bitType,
28723
+ ConfigKey.property_rightsPolicy,
28724
+ data.rightsPolicy,
28725
+ options
28726
+ ),
28301
28727
  sourceRL: this.toAstProperty(bitType, ConfigKey.property_sourceRL, data.sourceRL, options),
28302
28728
  isPublic: this.toAstProperty(bitType, ConfigKey.property_isPublic, data.isPublic, options),
28303
28729
  isTemplate: this.toAstProperty(
@@ -28445,6 +28871,12 @@ var Builder = class extends BaseBuilder {
28445
28871
  data.publisherName,
28446
28872
  options
28447
28873
  ),
28874
+ displayName: this.toAstProperty(
28875
+ bitType,
28876
+ ConfigKey.property_displayName,
28877
+ data.displayName,
28878
+ options
28879
+ ),
28448
28880
  theme: this.toAstProperty(bitType, ConfigKey.property_theme, data.theme, options),
28449
28881
  rtl: this.toAstProperty(bitType, ConfigKey.property_rtl, data.rtl, options),
28450
28882
  computerLanguage: this.toAstProperty(
@@ -44607,7 +45039,7 @@ var ConfigBuilder = class {
44607
45039
  }
44608
45040
  const outputFolder = opts.outputDir ?? "assets/config";
44609
45041
  const outputFolderBits = import_node_path3.default.join(outputFolder, "bits");
44610
- const outputFolderGroups = import_node_path3.default.join(outputFolder, "partials");
45042
+ const outputFolderGroups = import_node_path3.default.join(outputFolder, "groups");
44611
45043
  const outputFolderCards = import_node_path3.default.join(outputFolder, "cards");
44612
45044
  import_fs_extra3.default.ensureDirSync(outputFolderBits);
44613
45045
  import_fs_extra3.default.ensureDirSync(outputFolderGroups);
@@ -44642,6 +45074,15 @@ var ConfigBuilder = class {
44642
45074
  }
44643
45075
  return [{ key: groupKey }];
44644
45076
  };
45077
+ const mappingKeysField = (base, json, html) => {
45078
+ const record = {};
45079
+ for (const [id, value] of Object.entries(base ?? {})) {
45080
+ if (value != null) record[id] = value;
45081
+ }
45082
+ if (json.present && json.value != null) record.json = json.value;
45083
+ if (html.present && html.value != null) record.html = html.value;
45084
+ return Object.keys(record).length > 0 ? { mappingKeys: record } : {};
45085
+ };
44645
45086
  const bareKeyForProperty = (key) => {
44646
45087
  if (key.startsWith("@") || key.startsWith("&")) return key.substring(1);
44647
45088
  return void 0;
@@ -44662,22 +45103,20 @@ var ConfigBuilder = class {
44662
45103
  if (tag.format === TagFormat.plainText) {
44663
45104
  format = "string";
44664
45105
  } else if (tag.format === TagFormat.boolean) {
44665
- format = "bool";
44666
- } else if (tag.format === TagFormat.bitmarkText) {
44667
- format = "bitmark";
45106
+ format = "boolean";
44668
45107
  } else if (tag.format === TagFormat.number) {
44669
45108
  format = "number";
44670
45109
  } else {
44671
- format = "bitmark--";
45110
+ format = "bitmark+";
44672
45111
  }
44673
45112
  } else if (tagType === BitTagConfigKeyType.property) {
44674
45113
  tagName = tag.key;
44675
45114
  if (tag.format === TagFormat.plainText) {
44676
45115
  format = "string";
44677
45116
  } else if (tag.format === TagFormat.boolean) {
44678
- format = "bool";
45117
+ format = "boolean";
44679
45118
  } else if (tag.format === TagFormat.bitmarkText) {
44680
- format = "bitmark";
45119
+ format = "bitmark+";
44681
45120
  } else if (tag.format === TagFormat.number) {
44682
45121
  format = "number";
44683
45122
  } else if (tag.format === TagFormat.coordinates) {
@@ -44709,8 +45148,11 @@ var ConfigBuilder = class {
44709
45148
  tags2.push({
44710
45149
  type: "group",
44711
45150
  key: ref.key,
44712
- ...hasExportChosen ? { jsonKey: exportJsonKeyChosen } : {},
44713
- ...hasHtmlChosen ? { htmlKey: htmlKeyChosen } : {},
45151
+ ...mappingKeysField(
45152
+ { ...ref.extraKeys ?? {}, ...tag.mappingKeys ?? {} },
45153
+ { value: exportJsonKeyChosen, present: hasExportChosen },
45154
+ { value: htmlKeyChosen, present: hasHtmlChosen }
45155
+ ),
44714
45156
  ...min != null ? { min } : {},
44715
45157
  ...max != null ? { max } : {},
44716
45158
  ...description ? { description } : {}
@@ -44727,53 +45169,48 @@ var ConfigBuilder = class {
44727
45169
  chain = chainTags;
44728
45170
  }
44729
45171
  const hasExport = Object.prototype.hasOwnProperty.call(tag, "exportJsonKey");
44730
- let exportJsonKeyField;
44731
- if (hasExport) {
44732
- exportJsonKeyField = { jsonKey: tag.exportJsonKey };
44733
- } else if (legacyIsTrivialDefault(tag)) {
44734
- exportJsonKeyField = {};
44735
- } else {
45172
+ if (!hasExport && !legacyIsTrivialDefault(tag)) {
44736
45173
  const headingPath = [...pathStack, `tags.${tag.key}`].join(" / ");
44737
45174
  exportJsonKeyErrors.push(
44738
45175
  `Missing exportJsonKey for non-default jsonKey at ${headingPath}` + (tag.jsonKey ? ` (legacy: \`${tag.jsonKey}\`)` : ` (symbol-mapped tag \`${tag.key}\`)`)
44739
45176
  );
44740
- exportJsonKeyField = {};
44741
45177
  }
44742
45178
  const hasHtml = Object.prototype.hasOwnProperty.call(tag, "htmlKey");
44743
- const htmlKeyField = hasHtml ? { htmlKey: tag.htmlKey } : {};
44744
45179
  const t = {
44745
45180
  type: "tag",
44746
45181
  key: tagName,
44747
- ...exportJsonKeyField,
44748
- ...htmlKeyField,
44749
- format,
44750
- default: tag.defaultValue ?? null,
45182
+ ...mappingKeysField(
45183
+ tag.mappingKeys,
45184
+ { value: tag.exportJsonKey, present: hasExport },
45185
+ { value: tag.htmlKey, present: hasHtml }
45186
+ ),
45187
+ ...format && format !== "string" ? { format } : {},
45188
+ ...tag.defaultValue != null ? { default: tag.defaultValue } : {},
44751
45189
  ...tag.nullable ? { nullable: true } : {},
44752
- min: tag.minCount == null ? 0 : tag.minCount,
44753
- max: tag.maxCount == null ? 1 : tag.maxCount,
45190
+ ...tag.minCount != null && tag.minCount !== 0 ? { min: tag.minCount } : {},
45191
+ ...tag.maxCount != null && tag.maxCount !== 1 ? { max: tag.maxCount } : {},
44754
45192
  description: tag.description ?? "",
44755
45193
  tags: chain
44756
45194
  };
44757
45195
  tags2.push(t);
44758
45196
  return tags2;
44759
45197
  };
44760
- const cardJsonKeyField = (container, legacyKey, exportKey, pathHeading) => {
45198
+ const cardMappingKeysField = (container, base, legacyKey, exportKey, htmlExportKey, pathHeading) => {
44761
45199
  const c = container;
44762
45200
  const hasExport = Object.prototype.hasOwnProperty.call(c, exportKey);
44763
- if (hasExport) return { jsonKey: c[exportKey] };
44764
- const legacy = c[legacyKey];
44765
- if (legacy == null) return {};
44766
- exportJsonKeyErrors.push(
44767
- `Missing exportJsonKey for non-default jsonKey at ${pathHeading} (legacy: \`${legacy}\`)`
44768
- );
44769
- return {};
44770
- };
44771
- const cardHtmlKeyField = (container, htmlExportKey) => {
44772
- const c = container;
44773
- if (Object.prototype.hasOwnProperty.call(c, htmlExportKey)) {
44774
- return { htmlKey: c[htmlExportKey] };
45201
+ if (!hasExport && c[legacyKey] != null) {
45202
+ exportJsonKeyErrors.push(
45203
+ `Missing exportJsonKey for non-default jsonKey at ${pathHeading} (legacy: \`${c[legacyKey]}\`)`
45204
+ );
44775
45205
  }
44776
- return {};
45206
+ return mappingKeysField(
45207
+ base,
45208
+ { value: c[exportKey], present: hasExport },
45209
+ {
45210
+ value: c[htmlExportKey],
45211
+ present: Object.prototype.hasOwnProperty.call(c, htmlExportKey)
45212
+ }
45213
+ );
44777
45214
  };
44778
45215
  const serializeCardSet = (cardSetKey) => {
44779
45216
  const variantBodyFormat = (variant) => variant.format ?? TextFormat.bitmarkText;
@@ -44804,11 +45241,17 @@ var ConfigBuilder = class {
44804
45241
  variantTags.push(...processTagEntries(variantTag, [variantPath]));
44805
45242
  }
44806
45243
  return {
44807
- ...cardJsonKeyField(variant, "jsonKey", "exportJsonKey", variantPath),
44808
- ...cardHtmlKeyField(variant, "htmlKey"),
44809
- format: variantBodyFormat(variant),
45244
+ ...cardMappingKeysField(
45245
+ variant,
45246
+ void 0,
45247
+ "jsonKey",
45248
+ "exportJsonKey",
45249
+ "htmlKey",
45250
+ variantPath
45251
+ ),
45252
+ bodyFormat: variantBodyFormat(variant),
44810
45253
  tags: variantTags,
44811
- repeatCount: variant.repeatCount ?? 1,
45254
+ ...variant.repeatCount != null && variant.repeatCount !== 1 ? { repeatCount: variant.repeatCount } : {},
44812
45255
  ...variant.bodyRequired ? { bodyRequired: true } : {},
44813
45256
  ...variant.bodyAllowed === false ? { bodyForbidden: true } : {}
44814
45257
  };
@@ -44816,8 +45259,14 @@ var ConfigBuilder = class {
44816
45259
  return {
44817
45260
  name: side.name,
44818
45261
  ...side.repeat ? { repeat: side.repeat } : {},
44819
- ...cardJsonKeyField(side, "jsonKey", "exportJsonKey", sidePath),
44820
- ...cardHtmlKeyField(side, "htmlKey"),
45262
+ ...cardMappingKeysField(
45263
+ side,
45264
+ side.mappingKeys,
45265
+ "jsonKey",
45266
+ "exportJsonKey",
45267
+ "htmlKey",
45268
+ sidePath
45269
+ ),
44821
45270
  variants
44822
45271
  };
44823
45272
  });
@@ -44828,20 +45277,40 @@ var ConfigBuilder = class {
44828
45277
  const hasSideHtml = Object.prototype.hasOwnProperty.call(section, "sideHtmlKey");
44829
45278
  let cardSides = sides;
44830
45279
  if (hasSideExport || section.sideJsonKey != null || hasSideHtml) {
44831
- const sideOverride = cardJsonKeyField(
44832
- section,
44833
- "sideJsonKey",
44834
- "sideExportJsonKey",
44835
- `${sectionPath} / sides.*`
44836
- );
44837
- const sideHtmlOverride = cardHtmlKeyField(section, "sideHtmlKey");
44838
- cardSides = sides.map((s) => ({ ...s, ...sideOverride, ...sideHtmlOverride }));
45280
+ if (!hasSideExport && section.sideJsonKey != null) {
45281
+ exportJsonKeyErrors.push(
45282
+ `Missing exportJsonKey for non-default jsonKey at ${sectionPath} / sides.* (legacy: \`${section.sideJsonKey}\`)`
45283
+ );
45284
+ }
45285
+ cardSides = sides.map((s) => {
45286
+ const record = { ...s.mappingKeys ?? {} };
45287
+ if (hasSideExport) {
45288
+ if (section.sideExportJsonKey != null) record.json = section.sideExportJsonKey;
45289
+ else delete record.json;
45290
+ }
45291
+ if (hasSideHtml) {
45292
+ if (section.sideHtmlKey != null) record.html = section.sideHtmlKey;
45293
+ else delete record.html;
45294
+ }
45295
+ return {
45296
+ name: s.name,
45297
+ ...s.repeat ? { repeat: s.repeat } : {},
45298
+ ...Object.keys(record).length > 0 ? { mappingKeys: record } : {},
45299
+ variants: s.variants
45300
+ };
45301
+ });
44839
45302
  }
44840
45303
  return {
44841
45304
  name: sectionName,
44842
45305
  ...section.isDefault ? { isDefault: true } : {},
44843
- ...cardJsonKeyField(section, "jsonKey", "exportJsonKey", sectionPath),
44844
- ...cardHtmlKeyField(section, "htmlKey"),
45306
+ ...cardMappingKeysField(
45307
+ section,
45308
+ section.mappingKeys,
45309
+ "jsonKey",
45310
+ "exportJsonKey",
45311
+ "htmlKey",
45312
+ sectionPath
45313
+ ),
44845
45314
  // PLAN-085: per-section cardinality. Emit only when non-default
44846
45315
  // (treat `0` / undefined as "unbounded — omit").
44847
45316
  ...section.minCount != null && section.minCount !== 0 ? { min: section.minCount } : {},
@@ -44849,7 +45318,18 @@ var ConfigBuilder = class {
44849
45318
  sides: cardSides
44850
45319
  };
44851
45320
  });
44852
- return { name: normalizedKey, ...cardHtmlKeyField(cardSetConfig, "htmlKey"), cards };
45321
+ return {
45322
+ name: normalizedKey,
45323
+ ...mappingKeysField(
45324
+ void 0,
45325
+ { present: false },
45326
+ {
45327
+ value: cardSetConfig.htmlKey,
45328
+ present: Object.prototype.hasOwnProperty.call(cardSetConfig, "htmlKey")
45329
+ }
45330
+ ),
45331
+ cards
45332
+ };
44853
45333
  }
44854
45334
  const cardSetPath = `cardSets.${normalizedKey} / cards.default`;
44855
45335
  return {
@@ -44858,8 +45338,14 @@ var ConfigBuilder = class {
44858
45338
  {
44859
45339
  name: "default",
44860
45340
  isDefault: true,
44861
- ...cardJsonKeyField(cardSetConfig, "jsonKey", "exportJsonKey", cardSetPath),
44862
- ...cardHtmlKeyField(cardSetConfig, "htmlKey"),
45341
+ ...cardMappingKeysField(
45342
+ cardSetConfig,
45343
+ cardSetConfig.mappingKeys,
45344
+ "jsonKey",
45345
+ "exportJsonKey",
45346
+ "htmlKey",
45347
+ cardSetPath
45348
+ ),
44863
45349
  sides
44864
45350
  }
44865
45351
  ]
@@ -44895,14 +45381,19 @@ var ConfigBuilder = class {
44895
45381
  ...t.max != null ? { max: t.max } : {},
44896
45382
  ...t.description ? { description: t.description } : {}
44897
45383
  };
44898
- if (Object.prototype.hasOwnProperty.call(t, "jsonKey")) {
44899
- ref.exportJsonKey = t.jsonKey;
45384
+ const record = t.mappingKeys ?? {};
45385
+ if (Object.prototype.hasOwnProperty.call(record, "json")) {
45386
+ ref.exportJsonKey = record.json;
44900
45387
  ref.hasExportJsonKey = true;
44901
45388
  }
44902
- if (Object.prototype.hasOwnProperty.call(t, "htmlKey")) {
44903
- ref.htmlKey = t.htmlKey;
45389
+ if (Object.prototype.hasOwnProperty.call(record, "html")) {
45390
+ ref.htmlKey = record.html;
44904
45391
  ref.hasHtmlKey = true;
44905
45392
  }
45393
+ const extras = Object.fromEntries(
45394
+ Object.entries(record).filter(([id]) => id !== "json" && id !== "html")
45395
+ );
45396
+ if (Object.keys(extras).length > 0) ref.extraKeys = extras;
44906
45397
  replacements.push(ref);
44907
45398
  }
44908
45399
  squashedGroups.set(groupKey, replacements);
@@ -44936,8 +45427,11 @@ var ConfigBuilder = class {
44936
45427
  pushOrReplace({
44937
45428
  type: "group",
44938
45429
  key: ref.key,
44939
- ...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
44940
- ...ref.hasHtmlKey ? { htmlKey: ref.htmlKey } : {},
45430
+ ...mappingKeysField(
45431
+ ref.extraKeys,
45432
+ { value: ref.exportJsonKey, present: !!ref.hasExportJsonKey },
45433
+ { value: ref.htmlKey, present: !!ref.hasHtmlKey }
45434
+ ),
44941
45435
  ...ref.min != null ? { min: ref.min } : {},
44942
45436
  ...ref.max != null ? { max: ref.max } : {},
44943
45437
  ...ref.description ? { description: ref.description } : {}
@@ -44950,8 +45444,11 @@ var ConfigBuilder = class {
44950
45444
  pushOrReplace({
44951
45445
  type: "group",
44952
45446
  key: ref.key,
44953
- ...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
44954
- ...ref.hasHtmlKey ? { htmlKey: ref.htmlKey } : {},
45447
+ ...mappingKeysField(
45448
+ ref.extraKeys,
45449
+ { value: ref.exportJsonKey, present: !!ref.hasExportJsonKey },
45450
+ { value: ref.htmlKey, present: !!ref.hasHtmlKey }
45451
+ ),
44955
45452
  ...ref.min != null ? { min: ref.min } : {},
44956
45453
  ...ref.max != null ? { max: ref.max } : {},
44957
45454
  ...ref.description ? { description: ref.description } : {}
@@ -44978,20 +45475,17 @@ var ConfigBuilder = class {
44978
45475
  description: b.description ?? "",
44979
45476
  since: resolvedBitConfig.since,
44980
45477
  deprecated: resolvedBitConfig.deprecated,
44981
- history: [
44982
- {
44983
- version: resolvedBitConfig.since,
44984
- changes: ["Initial version"]
44985
- }
44986
- ],
44987
- format: resolvedBitConfig.textFormatDefault ?? "bitmark--",
44988
- bodyRequired: resolvedBitConfig.bodyRequired ?? false,
44989
- bodyForbidden: !(resolvedBitConfig.bodyAllowed ?? true),
44990
- footerRequired: resolvedBitConfig.footerRequired ?? false,
44991
- footerForbidden: !(resolvedBitConfig.footerAllowed ?? true),
44992
- resourceAttachmentAllowed: resolvedBitConfig.resourceAttachmentAllowed ?? true,
45478
+ bodyFormat: resolvedBitConfig.textFormatDefault ?? "bitmark--",
45479
+ ...resolvedBitConfig.bodyRequired ? { bodyRequired: true } : {},
45480
+ ...resolvedBitConfig.bodyAllowed === false ? { bodyForbidden: true } : {},
45481
+ ...resolvedBitConfig.footerRequired ? { footerRequired: true } : {},
45482
+ ...resolvedBitConfig.footerAllowed === false ? { footerForbidden: true } : {},
45483
+ ...resolvedBitConfig.resourceAttachmentAllowed === false ? { resourceAttachmentAllowed: false } : {},
45484
+ // Bit-level named key mappings (element keys for markup import),
45485
+ // carried verbatim from the raw config.
45486
+ ...mappingKeysField(b.mappingKeys, { present: false }, { present: false }),
44993
45487
  tags: tags2,
44994
- ...cardRef ? { card: cardRef } : {}
45488
+ ...cardRef ? { cardSet: cardRef } : {}
44995
45489
  };
44996
45490
  const output = import_node_path3.default.join(outputFolderBits, `${b.bitType}.jsonc`);
44997
45491
  const str = JSON.stringify(bitJson, null, 2);
@@ -45019,14 +45513,7 @@ var ConfigBuilder = class {
45019
45513
  const bitJson = {
45020
45514
  name: groupKey,
45021
45515
  description: g.description ?? "",
45022
- since: "UNKNOWN",
45023
45516
  deprecated: g.deprecated,
45024
- history: [
45025
- {
45026
- version: "UNKNOWN",
45027
- changes: ["Initial version"]
45028
- }
45029
- ],
45030
45517
  tags: tags2
45031
45518
  // cards: [
45032
45519
  // {
@@ -45080,8 +45567,11 @@ var ConfigBuilder = class {
45080
45567
  tags2.push({
45081
45568
  type: "group",
45082
45569
  key: ref.key,
45083
- ...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
45084
- ...ref.hasHtmlKey ? { htmlKey: ref.htmlKey } : {},
45570
+ ...mappingKeysField(
45571
+ ref.extraKeys,
45572
+ { value: ref.exportJsonKey, present: !!ref.hasExportJsonKey },
45573
+ { value: ref.htmlKey, present: !!ref.hasHtmlKey }
45574
+ ),
45085
45575
  ...ref.min != null ? { min: ref.min } : {},
45086
45576
  ...ref.max != null ? { max: ref.max } : {},
45087
45577
  ...ref.description ? { description: ref.description } : {}
@@ -45102,14 +45592,7 @@ var ConfigBuilder = class {
45102
45592
  const bitJson = {
45103
45593
  name: groupKey,
45104
45594
  description: b.description ?? "",
45105
- since: "UNKNOWN",
45106
45595
  deprecated: b.deprecated,
45107
- history: [
45108
- {
45109
- version: "UNKNOWN",
45110
- changes: ["Initial version"]
45111
- }
45112
- ],
45113
45596
  tags: tags2
45114
45597
  };
45115
45598
  const output = import_node_path3.default.join(outputFolderGroups, `${groupKey}.jsonc`);
@@ -45150,7 +45633,7 @@ var ConfigBuilder = class {
45150
45633
  validateConfigTree(outputFolder) {
45151
45634
  const errors = [];
45152
45635
  const outputFolderBits = import_node_path3.default.join(outputFolder, "bits");
45153
- const outputFolderGroups = import_node_path3.default.join(outputFolder, "partials");
45636
+ const outputFolderGroups = import_node_path3.default.join(outputFolder, "groups");
45154
45637
  const outputFolderCards = import_node_path3.default.join(outputFolder, "cards");
45155
45638
  const availableGroups = /* @__PURE__ */ new Set();
45156
45639
  if (import_fs_extra3.default.existsSync(outputFolderGroups)) {
@@ -45224,7 +45707,7 @@ var ConfigBuilder = class {
45224
45707
  const content = import_fs_extra3.default.readFileSync(filePath, "utf-8");
45225
45708
  const config = JSON.parse(content);
45226
45709
  if (config.tags && Array.isArray(config.tags)) {
45227
- checkTags(config.tags, `partials/${file}`, 15);
45710
+ checkTags(config.tags, `groups/${file}`, 15);
45228
45711
  }
45229
45712
  } catch (err) {
45230
45713
  errors.push(`Failed to parse ${file}: ${err}`);