@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/cli/main.js CHANGED
@@ -267,6 +267,7 @@ var BitType = {
267
267
  extractorPageNumberCollapsible: "extractor-page-number-collapsible",
268
268
  extractorPageWithBlocks: "extractor-page-with-blocks",
269
269
  extractorPageWithBlocksCollapsible: "extractor-page-with-blocks-collapsible",
270
+ extractorReconcile: "extractor-reconcile",
270
271
  extractorRepeatedText: "extractor-repeated-text",
271
272
  extractorRule: "extractor-rule",
272
273
  extractorTheme: "extractor-theme",
@@ -1315,6 +1316,7 @@ var propertyKeys = {
1315
1316
  property_dateEnd: "@dateEnd",
1316
1317
  property_decimalPlaces: "@decimalPlaces",
1317
1318
  property_deeplink: "@deeplink",
1319
+ property_displayName: "@displayName",
1318
1320
  property_diffContext: "@diffContext",
1319
1321
  property_diffOp: "@diffOp",
1320
1322
  property_diffRef: "@diffRef",
@@ -1470,6 +1472,7 @@ var propertyKeys = {
1470
1472
  property_revealSolutions: "@revealSolutions",
1471
1473
  property_reviewTag: "@reviewTag",
1472
1474
  property_reviewerTag: "@reviewerTag",
1475
+ property_rightsPolicy: "@rightsPolicy",
1473
1476
  property_sampleSolution: "@sampleSolution",
1474
1477
  property_scormSource: "@scormSource",
1475
1478
  property_search: "@search",
@@ -2454,9 +2457,30 @@ var CARDSETS = {
2454
2457
  [CardSetConfigKey.definitionList]: {
2455
2458
  jsonKey: "definitions",
2456
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
+ },
2457
2472
  sides: [
2458
2473
  {
2459
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
+ },
2460
2484
  variants: [
2461
2485
  {
2462
2486
  jsonKey: "term.text",
@@ -2470,8 +2494,10 @@ var CARDSETS = {
2470
2494
  key: ConfigKey.tag_title,
2471
2495
  description: "Title of the definition.",
2472
2496
  format: TagFormat.plainText,
2497
+ nullable: true,
2473
2498
  jsonKey: "^heading.forKeys",
2474
- exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2499
+ exportJsonKey: { "@bit": { heading: { forKeys: "$" } } },
2500
+ mappingKeys: { "xml-niso-iec": { "@el": "title", "@text": "$" } }
2475
2501
  },
2476
2502
  {
2477
2503
  key: ConfigKey.group_resourceIcon,
@@ -2497,6 +2523,24 @@ var CARDSETS = {
2497
2523
  },
2498
2524
  {
2499
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
+ },
2500
2544
  variants: [
2501
2545
  {
2502
2546
  jsonKey: "definition.text",
@@ -2510,6 +2554,7 @@ var CARDSETS = {
2510
2554
  key: ConfigKey.tag_title,
2511
2555
  description: "Title of the definition.",
2512
2556
  format: TagFormat.plainText,
2557
+ nullable: true,
2513
2558
  jsonKey: "^heading.forValues",
2514
2559
  exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2515
2560
  },
@@ -2588,6 +2633,7 @@ var CARDSETS = {
2588
2633
  key: ConfigKey.tag_title,
2589
2634
  description: "Title of the definition.",
2590
2635
  format: TagFormat.plainText,
2636
+ nullable: true,
2591
2637
  jsonKey: "^heading.forKeys",
2592
2638
  exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2593
2639
  },
@@ -2629,6 +2675,7 @@ var CARDSETS = {
2629
2675
  key: ConfigKey.tag_title,
2630
2676
  description: "Title of the definition.",
2631
2677
  format: TagFormat.plainText,
2678
+ nullable: true,
2632
2679
  jsonKey: "^heading.forValues",
2633
2680
  exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2634
2681
  },
@@ -2742,6 +2789,7 @@ var CARDSETS = {
2742
2789
  key: ConfigKey.tag_title,
2743
2790
  description: "Title of the match pair.",
2744
2791
  format: TagFormat.plainText,
2792
+ nullable: true,
2745
2793
  jsonKey: "^heading.forKeys",
2746
2794
  exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2747
2795
  },
@@ -2871,6 +2919,7 @@ var CARDSETS = {
2871
2919
  key: ConfigKey.tag_title,
2872
2920
  description: "Title of the match pair.",
2873
2921
  format: TagFormat.plainText,
2922
+ nullable: true,
2874
2923
  jsonKey: "^heading.forValues",
2875
2924
  exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2876
2925
  },
@@ -2917,6 +2966,7 @@ var CARDSETS = {
2917
2966
  key: ConfigKey.tag_title,
2918
2967
  description: "Title of the audio match pair.",
2919
2968
  format: TagFormat.plainText,
2969
+ nullable: true,
2920
2970
  jsonKey: "^heading.forKeys",
2921
2971
  exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2922
2972
  },
@@ -2948,6 +2998,7 @@ var CARDSETS = {
2948
2998
  key: ConfigKey.tag_title,
2949
2999
  description: "Title of the audio match pair.",
2950
3000
  format: TagFormat.plainText,
3001
+ nullable: true,
2951
3002
  jsonKey: "^heading.forValues",
2952
3003
  exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2953
3004
  },
@@ -2985,6 +3036,7 @@ var CARDSETS = {
2985
3036
  key: ConfigKey.tag_title,
2986
3037
  description: "Title of the image match pair.",
2987
3038
  format: TagFormat.plainText,
3039
+ nullable: true,
2988
3040
  jsonKey: "^heading.forKeys",
2989
3041
  exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2990
3042
  },
@@ -3016,6 +3068,7 @@ var CARDSETS = {
3016
3068
  key: ConfigKey.tag_title,
3017
3069
  description: "Title of the image match pair.",
3018
3070
  format: TagFormat.plainText,
3071
+ nullable: true,
3019
3072
  jsonKey: "^heading.forValues",
3020
3073
  exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
3021
3074
  },
@@ -3091,6 +3144,7 @@ var CARDSETS = {
3091
3144
  key: ConfigKey.tag_title,
3092
3145
  description: "Title of the match matrix.",
3093
3146
  format: TagFormat.plainText,
3147
+ nullable: true,
3094
3148
  jsonKey: "^heading.forKeys",
3095
3149
  exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
3096
3150
  },
@@ -3203,6 +3257,7 @@ var CARDSETS = {
3203
3257
  key: ConfigKey.tag_title,
3204
3258
  description: "Title of the match matrix.",
3205
3259
  format: TagFormat.plainText,
3260
+ nullable: true,
3206
3261
  jsonKey: "^heading.forValues",
3207
3262
  exportJsonKey: [
3208
3263
  { "@keyonly": { "@bit": { heading: { forValues: [""] } } } },
@@ -3485,6 +3540,7 @@ var CARDSETS = {
3485
3540
  key: ConfigKey.tag_title,
3486
3541
  description: "Title of the feedback.",
3487
3542
  format: TagFormat.plainText,
3543
+ nullable: true,
3488
3544
  jsonKey: "^heading.forKeys",
3489
3545
  exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
3490
3546
  }
@@ -3567,6 +3623,7 @@ var CARDSETS = {
3567
3623
  key: ConfigKey.tag_title,
3568
3624
  description: "Title of the feedback.",
3569
3625
  format: TagFormat.plainText,
3626
+ nullable: true,
3570
3627
  jsonKey: "^heading.forValues",
3571
3628
  exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
3572
3629
  }
@@ -3874,6 +3931,11 @@ var CARDSETS = {
3874
3931
  { table: { header: { rows: ["$"] } } }
3875
3932
  ],
3876
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
+ },
3877
3939
  sideJsonKey: "cells[{s}]|set(title=true)",
3878
3940
  sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } },
3879
3941
  // Header cells are `<th>`. The `width` attribute is contributed by the
@@ -3885,12 +3947,21 @@ var CARDSETS = {
3885
3947
  jsonKey: "table.body.rows",
3886
3948
  exportJsonKey: { table: { body: { rows: "$" } } },
3887
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
+ },
3888
3954
  isDefault: true
3889
3955
  },
3890
3956
  "table-footer": {
3891
3957
  jsonKey: "table.footer.rows",
3892
3958
  exportJsonKey: { table: { footer: { rows: "$" } } },
3893
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": "$" } },
3894
3965
  sideJsonKey: "cells[{s}]|set(title=true)",
3895
3966
  sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } },
3896
3967
  // Footer cells render as `<th>` (mirrors the header `title: true`
@@ -3907,6 +3978,8 @@ var CARDSETS = {
3907
3978
  // Default (body) cell → `<td>`; the header/footer sections override the
3908
3979
  // side to `<th>` via their sideHtmlKey (HTML.md §8).
3909
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": "$" } },
3910
3983
  variants: [
3911
3984
  {
3912
3985
  jsonKey: "content",
@@ -3924,7 +3997,11 @@ var CARDSETS = {
3924
3997
  // cell with `title: true` automatically.
3925
3998
  jsonKey: "content",
3926
3999
  exportJsonKey: { content: "$" },
3927
- 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": "$" } }
3928
4005
  },
3929
4006
  {
3930
4007
  key: ConfigKey.property_tableCellType,
@@ -3943,6 +4020,9 @@ var CARDSETS = {
3943
4020
  // HTML-C2: contribute a `rowspan` attribute onto the enclosing
3944
4021
  // cell element (`<th>`/`<td>`).
3945
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: "$" } } } },
3946
4026
  description: "Number of rows the cell spans.",
3947
4027
  format: TagFormat.number
3948
4028
  },
@@ -3953,6 +4033,9 @@ var CARDSETS = {
3953
4033
  // HTML-C2: contribute a `colspan` attribute onto the enclosing
3954
4034
  // cell element (`<th>`/`<td>`).
3955
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: "$" } } } },
3956
4039
  description: "Number of columns the cell spans.",
3957
4040
  format: TagFormat.number
3958
4041
  },
@@ -3974,6 +4057,13 @@ var CARDSETS = {
3974
4057
  // HTML.md §8 + HTML-C2: contribute a `width` attribute onto the
3975
4058
  // enclosing cell element (`<th>`/`<td>`).
3976
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: "$" } } },
3977
4067
  description: "Width for the column.",
3978
4068
  format: TagFormat.number
3979
4069
  }
@@ -4347,13 +4437,44 @@ var GROUPS = {
4347
4437
  key: ConfigKey.property_externalId,
4348
4438
  description: "The external identifier for the bit",
4349
4439
  format: TagFormat.plainText,
4350
- 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
+ }
4351
4456
  },
4352
4457
  {
4353
4458
  key: ConfigKey.property_sourceRL,
4354
4459
  description: "The original location of the information in the original source material",
4355
4460
  format: TagFormat.plainText
4356
4461
  },
4462
+ {
4463
+ key: ConfigKey.property_copyright,
4464
+ description: "The copyright information for the bit",
4465
+ format: TagFormat.plainText
4466
+ },
4467
+ {
4468
+ key: ConfigKey.property_license,
4469
+ description: "The license for the bit",
4470
+ format: TagFormat.plainText
4471
+ },
4472
+ {
4473
+ key: ConfigKey.property_rightsPolicy,
4474
+ description: "The rights policy or policies for the bit",
4475
+ format: TagFormat.plainText,
4476
+ maxCount: Count.infinity
4477
+ },
4357
4478
  {
4358
4479
  key: ConfigKey.property_isTemplate,
4359
4480
  description: "If true, the bit is a template",
@@ -4380,7 +4501,8 @@ var GROUPS = {
4380
4501
  {
4381
4502
  key: ConfigKey.property_aiGenerated,
4382
4503
  description: "If true, the bit is AI-generated",
4383
- format: TagFormat.boolean
4504
+ format: TagFormat.boolean,
4505
+ nullable: true
4384
4506
  },
4385
4507
  {
4386
4508
  key: ConfigKey.property_machineTranslated,
@@ -4395,7 +4517,8 @@ var GROUPS = {
4395
4517
  {
4396
4518
  key: ConfigKey.property_spansPageBreak,
4397
4519
  description: "If true, the bit spans a page break",
4398
- format: TagFormat.boolean
4520
+ format: TagFormat.boolean,
4521
+ nullable: true
4399
4522
  },
4400
4523
  {
4401
4524
  key: ConfigKey.property_searchIndex,
@@ -4470,7 +4593,8 @@ var GROUPS = {
4470
4593
  {
4471
4594
  key: ConfigKey.property_diffTime,
4472
4595
  description: "The diff time for the bit",
4473
- format: TagFormat.number
4596
+ format: TagFormat.number,
4597
+ nullable: true
4474
4598
  },
4475
4599
  {
4476
4600
  key: ConfigKey.property_ageRange,
@@ -4481,7 +4605,18 @@ var GROUPS = {
4481
4605
  {
4482
4606
  key: ConfigKey.property_lang,
4483
4607
  description: "The language for the bit",
4484
- 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
+ }
4485
4620
  },
4486
4621
  {
4487
4622
  key: ConfigKey.property_publisher,
@@ -4498,6 +4633,7 @@ var GROUPS = {
4498
4633
  key: ConfigKey.property_theme,
4499
4634
  description: "The theme(s) for the bit",
4500
4635
  format: TagFormat.plainText,
4636
+ nullable: true,
4501
4637
  maxCount: Count.infinity
4502
4638
  },
4503
4639
  {
@@ -4516,6 +4652,7 @@ var GROUPS = {
4516
4652
  key: ConfigKey.property_tag,
4517
4653
  description: "The tag(s) for the bit",
4518
4654
  format: TagFormat.plainText,
4655
+ nullable: true,
4519
4656
  maxCount: Count.infinity
4520
4657
  },
4521
4658
  {
@@ -4535,6 +4672,7 @@ var GROUPS = {
4535
4672
  exportJsonKey: { tags: ["$"] },
4536
4673
  description: "The tag(s) for the group",
4537
4674
  format: TagFormat.plainText,
4675
+ nullable: true,
4538
4676
  maxCount: Count.infinity
4539
4677
  }
4540
4678
  ]
@@ -4652,6 +4790,20 @@ var GROUPS = {
4652
4790
  description: "The layer role(s) for the bit",
4653
4791
  format: TagFormat.plainText,
4654
4792
  maxCount: Count.infinity
4793
+ },
4794
+ {
4795
+ // Universal @internalComment — declares in config what Config.ts also
4796
+ // injects programmatically into every bit (its push runs last and wins
4797
+ // the keyed merge, so runtime behaviour is unchanged). Declared here so
4798
+ // the config export (ConfigBuilder → assets/config → configurator →
4799
+ // bitmark.json) carries the tag for downstream parsers. Empty
4800
+ // exportJsonKey: consumed but never emitted to the bit JSON (the value
4801
+ // is routed to parser.internalComments).
4802
+ key: ConfigKey.property_internalComment,
4803
+ description: "Internal comment for the bit.",
4804
+ format: TagFormat.plainText,
4805
+ maxCount: Count.infinity,
4806
+ exportJsonKey: {}
4655
4807
  }
4656
4808
  ]
4657
4809
  },
@@ -4663,6 +4815,9 @@ var GROUPS = {
4663
4815
  key: ConfigKey.tag_item,
4664
4816
  jsonKey: "item",
4665
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": "$" } },
4666
4821
  description: "The item for the bit",
4667
4822
  chain: [
4668
4823
  {
@@ -4808,7 +4963,8 @@ var GROUPS = {
4808
4963
  {
4809
4964
  key: ConfigKey.property_size,
4810
4965
  description: "The size of the image",
4811
- format: TagFormat.number
4966
+ format: TagFormat.number,
4967
+ nullable: true
4812
4968
  },
4813
4969
  {
4814
4970
  key: ConfigKey.property_format,
@@ -5624,7 +5780,20 @@ var GROUPS = {
5624
5780
  key: ConfigKey.property_language,
5625
5781
  description: "The language of the book",
5626
5782
  format: TagFormat.plainText,
5627
- 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
5628
5797
  },
5629
5798
  {
5630
5799
  key: ConfigKey.property_customerExternalId,
@@ -5700,7 +5869,18 @@ var GROUPS = {
5700
5869
  description: "The title of the book",
5701
5870
  maxCount: 2,
5702
5871
  jsonKey: "title|multi(count=2, key=subtitle)",
5703
- 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
+ }
5704
5884
  },
5705
5885
  {
5706
5886
  key: ConfigKey.property_subtype,
@@ -5711,6 +5891,7 @@ var GROUPS = {
5711
5891
  key: ConfigKey.property_coverImage,
5712
5892
  description: "The cover image(s) of the book",
5713
5893
  format: TagFormat.plainText,
5894
+ nullable: true,
5714
5895
  maxCount: Count.infinity
5715
5896
  },
5716
5897
  {
@@ -6012,22 +6193,26 @@ var GROUPS = {
6012
6193
  {
6013
6194
  key: ConfigKey.property_platformMargin,
6014
6195
  description: "The platform margin",
6015
- format: TagFormat.number
6196
+ format: TagFormat.number,
6197
+ nullable: true
6016
6198
  },
6017
6199
  {
6018
6200
  key: ConfigKey.property_platformBorderRadius,
6019
6201
  description: "The platform border radius",
6020
- format: TagFormat.number
6202
+ format: TagFormat.number,
6203
+ nullable: true
6021
6204
  },
6022
6205
  {
6023
6206
  key: ConfigKey.property_platformSelectionBorderRadius,
6024
6207
  description: "The platform selection border radius",
6025
- format: TagFormat.number
6208
+ format: TagFormat.number,
6209
+ nullable: true
6026
6210
  },
6027
6211
  {
6028
6212
  key: ConfigKey.property_platformNeedsShadow,
6029
6213
  description: "If true, the platform needs shadow",
6030
- format: TagFormat.boolean
6214
+ format: TagFormat.boolean,
6215
+ nullable: true
6031
6216
  }
6032
6217
  ]
6033
6218
  },
@@ -6038,7 +6223,8 @@ var GROUPS = {
6038
6223
  {
6039
6224
  key: ConfigKey.property_revealSolutions,
6040
6225
  description: "If true, the quiz solutions are revealed",
6041
- format: TagFormat.boolean
6226
+ format: TagFormat.boolean,
6227
+ nullable: true
6042
6228
  // defaultValue: 'false',
6043
6229
  },
6044
6230
  {
@@ -6127,7 +6313,13 @@ var GROUPS = {
6127
6313
  {
6128
6314
  key: ConfigKey.property_caption,
6129
6315
  description: "The caption for the resource",
6130
- 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
+ }
6131
6323
  },
6132
6324
  {
6133
6325
  key: ConfigKey.property_showInIndex,
@@ -6185,12 +6377,14 @@ var GROUPS = {
6185
6377
  {
6186
6378
  key: ConfigKey.property_width,
6187
6379
  description: "The width of the image",
6188
- format: TagFormat.number
6380
+ format: TagFormat.number,
6381
+ nullable: true
6189
6382
  },
6190
6383
  {
6191
6384
  key: ConfigKey.property_height,
6192
6385
  description: "The height of the image",
6193
- format: TagFormat.number
6386
+ format: TagFormat.number,
6387
+ nullable: true
6194
6388
  },
6195
6389
  {
6196
6390
  key: ConfigKey.property_alt,
@@ -6235,12 +6429,14 @@ var GROUPS = {
6235
6429
  {
6236
6430
  key: ConfigKey.property_width,
6237
6431
  description: "The width of the image",
6238
- format: TagFormat.number
6432
+ format: TagFormat.number,
6433
+ nullable: true
6239
6434
  },
6240
6435
  {
6241
6436
  key: ConfigKey.property_height,
6242
6437
  description: "The height of the image",
6243
- format: TagFormat.number
6438
+ format: TagFormat.number,
6439
+ nullable: true
6244
6440
  },
6245
6441
  {
6246
6442
  key: ConfigKey.property_alt,
@@ -6292,12 +6488,14 @@ var GROUPS = {
6292
6488
  {
6293
6489
  key: ConfigKey.property_width,
6294
6490
  description: "The width of the video",
6295
- format: TagFormat.number
6491
+ format: TagFormat.number,
6492
+ nullable: true
6296
6493
  },
6297
6494
  {
6298
6495
  key: ConfigKey.property_height,
6299
6496
  description: "The height of the video",
6300
- format: TagFormat.number
6497
+ format: TagFormat.number,
6498
+ nullable: true
6301
6499
  },
6302
6500
  {
6303
6501
  key: ConfigKey.property_duration,
@@ -6395,6 +6593,10 @@ var GROUPS = {
6395
6593
  {
6396
6594
  key: ConfigKey.resource_image,
6397
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": "$" } } },
6398
6600
  description: "The image resource",
6399
6601
  chain: [
6400
6602
  {
@@ -7269,6 +7471,8 @@ var BITS = {
7269
7471
  maxCount: 2,
7270
7472
  jsonKey: "title|multi(count=2, key=subtitle)",
7271
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": "$" } },
7272
7476
  key: ConfigKey.tag_title,
7273
7477
  description: "The title of the article"
7274
7478
  }
@@ -7310,12 +7514,56 @@ var BITS = {
7310
7514
  [BitType.smartStandardArticleNormative]: {
7311
7515
  since: "1.28.0",
7312
7516
  baseBitType: BitType.standardArticleNormative,
7313
- 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
+ }
7314
7540
  },
7315
7541
  [BitType.smartStandardArticleNonNormative]: {
7316
7542
  since: "1.28.0",
7317
7543
  baseBitType: BitType.standardArticleNonNormative,
7318
- 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
+ }
7319
7567
  },
7320
7568
  [BitType.smartStandardArticleNormativeCollapsible]: {
7321
7569
  since: "1.28.0",
@@ -7382,7 +7630,8 @@ var BITS = {
7382
7630
  {
7383
7631
  key: ConfigKey.property_coverImage,
7384
7632
  description: "Cover image of the catalog item",
7385
- format: TagFormat.plainText
7633
+ format: TagFormat.plainText,
7634
+ nullable: true
7386
7635
  },
7387
7636
  {
7388
7637
  key: ConfigKey.resource_coverImage,
@@ -7546,7 +7795,8 @@ var BITS = {
7546
7795
  {
7547
7796
  key: ConfigKey.property_coverImage,
7548
7797
  description: "Cover image of the catalog item",
7549
- format: TagFormat.plainText
7798
+ format: TagFormat.plainText,
7799
+ nullable: true
7550
7800
  },
7551
7801
  {
7552
7802
  key: ConfigKey.resource_coverImage,
@@ -7710,7 +7960,8 @@ var BITS = {
7710
7960
  {
7711
7961
  key: ConfigKey.property_coverImage,
7712
7962
  description: "Cover image of the catalog item",
7713
- format: TagFormat.plainText
7963
+ format: TagFormat.plainText,
7964
+ nullable: true
7714
7965
  },
7715
7966
  {
7716
7967
  key: ConfigKey.property_content2Buy,
@@ -7943,7 +8194,8 @@ var BITS = {
7943
8194
  {
7944
8195
  key: ConfigKey.property_maxCreatedBits,
7945
8196
  description: "The maximum number of bits that can be created from this bit",
7946
- format: TagFormat.number
8197
+ format: TagFormat.number,
8198
+ nullable: true
7947
8199
  }
7948
8200
  ],
7949
8201
  textFormatDefault: TextFormat.plainText
@@ -8073,6 +8325,13 @@ var BITS = {
8073
8325
  since: "1.3.0",
8074
8326
  baseBitType: BitType._standard,
8075
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" } },
8076
8335
  tags: [
8077
8336
  {
8078
8337
  key: ConfigKey.group_bookCommon,
@@ -8359,12 +8618,14 @@ var BITS = {
8359
8618
  {
8360
8619
  key: ConfigKey.property_focusX,
8361
8620
  description: "The X coordinate for focusing the image in the browser",
8362
- format: TagFormat.number
8621
+ format: TagFormat.number,
8622
+ nullable: true
8363
8623
  },
8364
8624
  {
8365
8625
  key: ConfigKey.property_focusY,
8366
8626
  description: "The Y coordinate for focusing the image in the browser",
8367
- format: TagFormat.number
8627
+ format: TagFormat.number,
8628
+ nullable: true
8368
8629
  }
8369
8630
  ]
8370
8631
  },
@@ -8395,6 +8656,15 @@ var BITS = {
8395
8656
  since: "1.3.0",
8396
8657
  baseBitType: BitType._standard,
8397
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
+ },
8398
8668
  tags: [
8399
8669
  {
8400
8670
  exportJsonKey: { anchor: "$" },
@@ -8406,7 +8676,10 @@ var BITS = {
8406
8676
  key: ConfigKey.tag_title,
8407
8677
  description: "The title of the chapter",
8408
8678
  jsonKey: "title|setMulti(level)",
8409
- 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": "$" } }
8410
8683
  },
8411
8684
  {
8412
8685
  key: ConfigKey.property_toc,
@@ -8496,12 +8769,14 @@ var BITS = {
8496
8769
  {
8497
8770
  key: ConfigKey.property_quizCountItems,
8498
8771
  description: "The number of items in the cloze quiz",
8499
- format: TagFormat.boolean
8772
+ format: TagFormat.boolean,
8773
+ nullable: true
8500
8774
  },
8501
8775
  {
8502
8776
  key: ConfigKey.property_quizStrikethroughSolutions,
8503
8777
  description: "If the cloze solutions should be strikethrough",
8504
- format: TagFormat.boolean
8778
+ format: TagFormat.boolean,
8779
+ nullable: true
8505
8780
  },
8506
8781
  {
8507
8782
  key: ConfigKey.group_gap,
@@ -8610,11 +8885,28 @@ var BITS = {
8610
8885
  since: "1.3.0",
8611
8886
  baseBitType: BitType._standard,
8612
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
+ },
8613
8899
  tags: [
8614
8900
  {
8615
8901
  key: ConfigKey.property_computerLanguage,
8616
8902
  description: "The programming language of the code snippet",
8617
- 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" }] }
8618
8910
  },
8619
8911
  {
8620
8912
  key: ConfigKey.property_codeLineNumbers,
@@ -8653,7 +8945,20 @@ var BITS = {
8653
8945
  [BitType.smartStandardFormulaNormative]: {
8654
8946
  since: "3.11.0",
8655
8947
  baseBitType: BitType.formula,
8656
- 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
+ }
8657
8962
  },
8658
8963
  [BitType.smartStandardRemarkFormula]: {
8659
8964
  since: "3.11.0",
@@ -9180,7 +9485,8 @@ var BITS = {
9180
9485
  {
9181
9486
  key: ConfigKey.property_reasonableNumOfChars,
9182
9487
  description: "The reasonable number of characters for the essay",
9183
- format: TagFormat.number
9488
+ format: TagFormat.number,
9489
+ nullable: true
9184
9490
  },
9185
9491
  {
9186
9492
  key: ConfigKey.property_sampleSolution,
@@ -9613,7 +9919,14 @@ var BITS = {
9613
9919
  [BitType.smartStandardList]: {
9614
9920
  since: "1.28.0",
9615
9921
  baseBitType: BitType.standardList,
9616
- 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
+ }
9617
9930
  },
9618
9931
  [BitType.smartStandardListCollapsible]: {
9619
9932
  since: "1.28.0",
@@ -9658,7 +9971,17 @@ var BITS = {
9658
9971
  [BitType.smartStandardNoteNonNormative]: {
9659
9972
  since: "1.28.0",
9660
9973
  baseBitType: BitType.standardNoteNonNormative,
9661
- 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
+ }
9662
9985
  },
9663
9986
  [BitType.smartStandardNoteNormativeCollapsible]: {
9664
9987
  since: "1.28.0",
@@ -9765,7 +10088,19 @@ var BITS = {
9765
10088
  [BitType.smartStandardRemarkNonNormative]: {
9766
10089
  since: "1.28.0",
9767
10090
  baseBitType: BitType.standardRemarkNonNormative,
9768
- 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
+ }
9769
10104
  },
9770
10105
  [BitType.smartStandardRemarkNormativeCollapsible]: {
9771
10106
  since: "1.28.0",
@@ -10197,6 +10532,12 @@ var BITS = {
10197
10532
  description: "Extractor theme bit, used to store design/theme JSON extracted from documents",
10198
10533
  textFormatDefault: TextFormat.json
10199
10534
  },
10535
+ [BitType.extractorReconcile]: {
10536
+ since: "5.35.0",
10537
+ baseBitType: BitType._standard,
10538
+ description: "Extractor reconcile bit, used to store PDF-compare reconciliation decisions (config and issues) in JSON",
10539
+ textFormatDefault: TextFormat.json
10540
+ },
10200
10541
  [BitType.extractorAiChat]: {
10201
10542
  since: "3.19.0",
10202
10543
  baseBitType: BitType._standard,
@@ -10215,32 +10556,38 @@ var BITS = {
10215
10556
  {
10216
10557
  key: ConfigKey.property_pageNo,
10217
10558
  description: "Page number for the block, used to indicate the page on which the block appears",
10218
- format: TagFormat.number
10559
+ format: TagFormat.number,
10560
+ nullable: true
10219
10561
  },
10220
10562
  {
10221
10563
  key: ConfigKey.property_x,
10222
10564
  description: "X-coordinate for the block, used to position the block on the page",
10223
- format: TagFormat.number
10565
+ format: TagFormat.number,
10566
+ nullable: true
10224
10567
  },
10225
10568
  {
10226
10569
  key: ConfigKey.property_y,
10227
10570
  description: "Y-coordinate for the block, used to position the block on the page",
10228
- format: TagFormat.number
10571
+ format: TagFormat.number,
10572
+ nullable: true
10229
10573
  },
10230
10574
  {
10231
10575
  key: ConfigKey.property_width,
10232
10576
  description: "Width of the block, used to define the size of the block on the page",
10233
- format: TagFormat.number
10577
+ format: TagFormat.number,
10578
+ nullable: true
10234
10579
  },
10235
10580
  {
10236
10581
  key: ConfigKey.property_height,
10237
10582
  description: "Height of the block, used to define the size of the block on the page",
10238
- format: TagFormat.number
10583
+ format: TagFormat.number,
10584
+ nullable: true
10239
10585
  },
10240
10586
  {
10241
10587
  key: ConfigKey.property_index,
10242
10588
  description: "Index of the block, used to order blocks within the extractor page",
10243
- format: TagFormat.number
10589
+ format: TagFormat.number,
10590
+ nullable: true
10244
10591
  },
10245
10592
  {
10246
10593
  key: ConfigKey.property_classification,
@@ -10550,7 +10897,20 @@ var BITS = {
10550
10897
  [BitType.smartStandardLegendNormative]: {
10551
10898
  since: "3.12.0",
10552
10899
  baseBitType: BitType.legend,
10553
- 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
+ }
10554
10914
  },
10555
10915
  [BitType.smartStandardRemarkLegend]: {
10556
10916
  since: "3.12.0",
@@ -10605,7 +10965,16 @@ var BITS = {
10605
10965
  [BitType.smartStandardDefinitionListNormative]: {
10606
10966
  since: "5.24.0",
10607
10967
  baseBitType: BitType.standardDefinitionListNormative,
10608
- 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
+ }
10609
10978
  },
10610
10979
  [BitType.smartStandardDefinitionListNonNormative]: {
10611
10980
  since: "5.24.0",
@@ -10674,12 +11043,14 @@ var BITS = {
10674
11043
  {
10675
11044
  key: ConfigKey.property_focusX,
10676
11045
  description: "X-coordinate for the focus point, used to define the focus area in the image",
10677
- format: TagFormat.number
11046
+ format: TagFormat.number,
11047
+ nullable: true
10678
11048
  },
10679
11049
  {
10680
11050
  key: ConfigKey.property_focusY,
10681
11051
  description: "Y-coordinate for the focus point, used to define the focus area in the image",
10682
- format: TagFormat.number
11052
+ format: TagFormat.number,
11053
+ nullable: true
10683
11054
  }
10684
11055
  ]
10685
11056
  },
@@ -10786,7 +11157,15 @@ var BITS = {
10786
11157
  [BitType.smartStandardImageFigureNormative]: {
10787
11158
  since: "1.28.0",
10788
11159
  baseBitType: BitType.standardImageFigureNormative,
10789
- 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
+ }
10790
11169
  },
10791
11170
  [BitType.smartStandardImageFigureNonNormative]: {
10792
11171
  since: "1.28.0",
@@ -11514,7 +11893,19 @@ var BITS = {
11514
11893
  [BitType.smartStandardListItem]: {
11515
11894
  since: "1.28.0",
11516
11895
  baseBitType: BitType.standardListItem,
11517
- 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
+ }
11518
11909
  },
11519
11910
  [BitType.smartStandardListItemCollapsible]: {
11520
11911
  since: "1.28.0",
@@ -11983,7 +12374,8 @@ var BITS = {
11983
12374
  {
11984
12375
  key: ConfigKey.property_product,
11985
12376
  description: "Product reference for the product page, used to link to the product",
11986
- format: TagFormat.plainText
12377
+ format: TagFormat.plainText,
12378
+ nullable: true
11987
12379
  }
11988
12380
  ]
11989
12381
  },
@@ -12002,6 +12394,7 @@ var BITS = {
12002
12394
  key: ConfigKey.property_product,
12003
12395
  description: "Product reference for the product list, used to link to the product",
12004
12396
  format: TagFormat.plainText,
12397
+ nullable: true,
12005
12398
  maxCount: Count.infinity
12006
12399
  }
12007
12400
  // {
@@ -12563,7 +12956,8 @@ var BITS = {
12563
12956
  {
12564
12957
  key: ConfigKey.property_ratingLevelSelected,
12565
12958
  description: "Selected level for the rating survey, used to define the default rating",
12566
- format: TagFormat.number
12959
+ format: TagFormat.number,
12960
+ nullable: true
12567
12961
  },
12568
12962
  {
12569
12963
  key: ConfigKey.property_buttonCaption,
@@ -12618,7 +13012,13 @@ var BITS = {
12618
13012
  // `<caption>` — placed inside the idiomatic `<table>` container as
12619
13013
  // its first child. Outside a table context it falls back to the
12620
13014
  // residual carrier.
12621
- 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
+ }
12622
13022
  },
12623
13023
  {
12624
13024
  key: ConfigKey.property_tableFixedHeader,
@@ -12791,7 +13191,16 @@ var BITS = {
12791
13191
  [BitType.smartStandardTableExtendedNormative]: {
12792
13192
  since: "1.28.0",
12793
13193
  baseBitType: BitType.standardTableExtendedNormative,
12794
- 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
+ }
12795
13204
  },
12796
13205
  [BitType.smartStandardTableExtendedNonNormative]: {
12797
13206
  since: "1.28.0",
@@ -12866,7 +13275,8 @@ var BITS = {
12866
13275
  {
12867
13276
  key: ConfigKey.property_maxDisplayLevel,
12868
13277
  description: "Maximum display level for the chapter in the table of contents",
12869
- format: TagFormat.number
13278
+ format: TagFormat.number,
13279
+ nullable: true
12870
13280
  }
12871
13281
  ]
12872
13282
  },
@@ -12878,7 +13288,8 @@ var BITS = {
12878
13288
  {
12879
13289
  key: ConfigKey.property_maxTocChapterLevel,
12880
13290
  description: "Maximum chapter level for the inline table of contents",
12881
- format: TagFormat.number
13291
+ format: TagFormat.number,
13292
+ nullable: true
12882
13293
  }
12883
13294
  ]
12884
13295
  },
@@ -13301,13 +13712,15 @@ var BITS = {
13301
13712
  key: ConfigKey.property_width,
13302
13713
  // Same as image
13303
13714
  description: "Width for the embedded content, used to define the width in pixels",
13304
- format: TagFormat.number
13715
+ format: TagFormat.number,
13716
+ nullable: true
13305
13717
  },
13306
13718
  {
13307
13719
  key: ConfigKey.property_height,
13308
13720
  // Same as image
13309
13721
  description: "Height for the embedded content, used to define the height in pixels",
13310
- format: TagFormat.number
13722
+ format: TagFormat.number,
13723
+ nullable: true
13311
13724
  },
13312
13725
  {
13313
13726
  key: ConfigKey.property_vendorUrl,
@@ -13345,7 +13758,8 @@ var BITS = {
13345
13758
  {
13346
13759
  key: ConfigKey.property_jupyterExecutionCount,
13347
13760
  description: "Execution count for the Jupyter output, used to define the execution order",
13348
- format: TagFormat.number
13761
+ format: TagFormat.number,
13762
+ nullable: true
13349
13763
  }
13350
13764
  ],
13351
13765
  textFormatDefault: TextFormat.plainText
@@ -13895,7 +14309,7 @@ var instance2 = new Config();
13895
14309
  // src/generated/package_info.ts
13896
14310
  var PACKAGE_INFO = {
13897
14311
  "name": "@gmb/bitmark-parser-generator",
13898
- "version": "5.34.0",
14312
+ "version": "5.36.0",
13899
14313
  "license": "ISC"};
13900
14314
  var Environment = {
13901
14315
  unknown: "",
@@ -14392,6 +14806,8 @@ var NodeType = {
14392
14806
  definition: "definition",
14393
14807
  definitions: "definitions",
14394
14808
  definitionsValue: "definitionsValue",
14809
+ displayName: "displayName",
14810
+ displayNameValue: "displayNameValue",
14395
14811
  diffContext: "diffContext",
14396
14812
  diffContextValue: "diffContextValue",
14397
14813
  diffOp: "diffOp",
@@ -14788,6 +15204,8 @@ var NodeType = {
14788
15204
  reviewTagValue: "reviewTagValue",
14789
15205
  reviewerTag: "reviewerTag",
14790
15206
  reviewerTagValue: "reviewerTagValue",
15207
+ rightsPolicy: "rightsPolicy",
15208
+ rightsPolicyValue: "rightsPolicyValue",
14791
15209
  root: "root",
14792
15210
  // bit type (root)
14793
15211
  rows: "rows",
@@ -27972,6 +28390,14 @@ var Builder = class extends BaseBuilder {
27972
28390
  data.jupyterExecutionCount,
27973
28391
  options
27974
28392
  ),
28393
+ copyright: this.toAstProperty(bitType, ConfigKey.property_copyright, data.copyright, options),
28394
+ license: this.toAstProperty(bitType, ConfigKey.property_license, data.license, options),
28395
+ rightsPolicy: this.toAstProperty(
28396
+ bitType,
28397
+ ConfigKey.property_rightsPolicy,
28398
+ data.rightsPolicy,
28399
+ options
28400
+ ),
27975
28401
  sourceRL: this.toAstProperty(bitType, ConfigKey.property_sourceRL, data.sourceRL, options),
27976
28402
  isPublic: this.toAstProperty(bitType, ConfigKey.property_isPublic, data.isPublic, options),
27977
28403
  isTemplate: this.toAstProperty(
@@ -28119,6 +28545,12 @@ var Builder = class extends BaseBuilder {
28119
28545
  data.publisherName,
28120
28546
  options
28121
28547
  ),
28548
+ displayName: this.toAstProperty(
28549
+ bitType,
28550
+ ConfigKey.property_displayName,
28551
+ data.displayName,
28552
+ options
28553
+ ),
28122
28554
  theme: this.toAstProperty(bitType, ConfigKey.property_theme, data.theme, options),
28123
28555
  rtl: this.toAstProperty(bitType, ConfigKey.property_rtl, data.rtl, options),
28124
28556
  computerLanguage: this.toAstProperty(
@@ -44084,7 +44516,7 @@ var ConfigBuilder = class {
44084
44516
  }
44085
44517
  const outputFolder = opts.outputDir ?? "assets/config";
44086
44518
  const outputFolderBits = path3.join(outputFolder, "bits");
44087
- const outputFolderGroups = path3.join(outputFolder, "partials");
44519
+ const outputFolderGroups = path3.join(outputFolder, "groups");
44088
44520
  const outputFolderCards = path3.join(outputFolder, "cards");
44089
44521
  fs4.ensureDirSync(outputFolderBits);
44090
44522
  fs4.ensureDirSync(outputFolderGroups);
@@ -44119,6 +44551,15 @@ var ConfigBuilder = class {
44119
44551
  }
44120
44552
  return [{ key: groupKey }];
44121
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
+ };
44122
44563
  const bareKeyForProperty = (key) => {
44123
44564
  if (key.startsWith("@") || key.startsWith("&")) return key.substring(1);
44124
44565
  return void 0;
@@ -44139,22 +44580,20 @@ var ConfigBuilder = class {
44139
44580
  if (tag.format === TagFormat.plainText) {
44140
44581
  format = "string";
44141
44582
  } else if (tag.format === TagFormat.boolean) {
44142
- format = "bool";
44143
- } else if (tag.format === TagFormat.bitmarkText) {
44144
- format = "bitmark";
44583
+ format = "boolean";
44145
44584
  } else if (tag.format === TagFormat.number) {
44146
44585
  format = "number";
44147
44586
  } else {
44148
- format = "bitmark--";
44587
+ format = "bitmark+";
44149
44588
  }
44150
44589
  } else if (tagType === BitTagConfigKeyType.property) {
44151
44590
  tagName = tag.key;
44152
44591
  if (tag.format === TagFormat.plainText) {
44153
44592
  format = "string";
44154
44593
  } else if (tag.format === TagFormat.boolean) {
44155
- format = "bool";
44594
+ format = "boolean";
44156
44595
  } else if (tag.format === TagFormat.bitmarkText) {
44157
- format = "bitmark";
44596
+ format = "bitmark+";
44158
44597
  } else if (tag.format === TagFormat.number) {
44159
44598
  format = "number";
44160
44599
  } else if (tag.format === TagFormat.coordinates) {
@@ -44186,8 +44625,11 @@ var ConfigBuilder = class {
44186
44625
  tags2.push({
44187
44626
  type: "group",
44188
44627
  key: ref.key,
44189
- ...hasExportChosen ? { jsonKey: exportJsonKeyChosen } : {},
44190
- ...hasHtmlChosen ? { htmlKey: htmlKeyChosen } : {},
44628
+ ...mappingKeysField(
44629
+ { ...ref.extraKeys ?? {}, ...tag.mappingKeys ?? {} },
44630
+ { value: exportJsonKeyChosen, present: hasExportChosen },
44631
+ { value: htmlKeyChosen, present: hasHtmlChosen }
44632
+ ),
44191
44633
  ...min != null ? { min } : {},
44192
44634
  ...max != null ? { max } : {},
44193
44635
  ...description ? { description } : {}
@@ -44204,53 +44646,48 @@ var ConfigBuilder = class {
44204
44646
  chain = chainTags;
44205
44647
  }
44206
44648
  const hasExport = Object.prototype.hasOwnProperty.call(tag, "exportJsonKey");
44207
- let exportJsonKeyField;
44208
- if (hasExport) {
44209
- exportJsonKeyField = { jsonKey: tag.exportJsonKey };
44210
- } else if (legacyIsTrivialDefault(tag)) {
44211
- exportJsonKeyField = {};
44212
- } else {
44649
+ if (!hasExport && !legacyIsTrivialDefault(tag)) {
44213
44650
  const headingPath = [...pathStack, `tags.${tag.key}`].join(" / ");
44214
44651
  exportJsonKeyErrors.push(
44215
44652
  `Missing exportJsonKey for non-default jsonKey at ${headingPath}` + (tag.jsonKey ? ` (legacy: \`${tag.jsonKey}\`)` : ` (symbol-mapped tag \`${tag.key}\`)`)
44216
44653
  );
44217
- exportJsonKeyField = {};
44218
44654
  }
44219
44655
  const hasHtml = Object.prototype.hasOwnProperty.call(tag, "htmlKey");
44220
- const htmlKeyField = hasHtml ? { htmlKey: tag.htmlKey } : {};
44221
44656
  const t = {
44222
44657
  type: "tag",
44223
44658
  key: tagName,
44224
- ...exportJsonKeyField,
44225
- ...htmlKeyField,
44226
- format,
44227
- 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 } : {},
44228
44666
  ...tag.nullable ? { nullable: true } : {},
44229
- min: tag.minCount == null ? 0 : tag.minCount,
44230
- 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 } : {},
44231
44669
  description: tag.description ?? "",
44232
44670
  tags: chain
44233
44671
  };
44234
44672
  tags2.push(t);
44235
44673
  return tags2;
44236
44674
  };
44237
- const cardJsonKeyField = (container, legacyKey, exportKey, pathHeading) => {
44675
+ const cardMappingKeysField = (container, base, legacyKey, exportKey, htmlExportKey, pathHeading) => {
44238
44676
  const c = container;
44239
44677
  const hasExport = Object.prototype.hasOwnProperty.call(c, exportKey);
44240
- if (hasExport) return { jsonKey: c[exportKey] };
44241
- const legacy = c[legacyKey];
44242
- if (legacy == null) return {};
44243
- exportJsonKeyErrors.push(
44244
- `Missing exportJsonKey for non-default jsonKey at ${pathHeading} (legacy: \`${legacy}\`)`
44245
- );
44246
- return {};
44247
- };
44248
- const cardHtmlKeyField = (container, htmlExportKey) => {
44249
- const c = container;
44250
- if (Object.prototype.hasOwnProperty.call(c, htmlExportKey)) {
44251
- 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
+ );
44252
44682
  }
44253
- 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
+ );
44254
44691
  };
44255
44692
  const serializeCardSet = (cardSetKey) => {
44256
44693
  const variantBodyFormat = (variant) => variant.format ?? TextFormat.bitmarkText;
@@ -44281,11 +44718,17 @@ var ConfigBuilder = class {
44281
44718
  variantTags.push(...processTagEntries(variantTag, [variantPath]));
44282
44719
  }
44283
44720
  return {
44284
- ...cardJsonKeyField(variant, "jsonKey", "exportJsonKey", variantPath),
44285
- ...cardHtmlKeyField(variant, "htmlKey"),
44286
- format: variantBodyFormat(variant),
44721
+ ...cardMappingKeysField(
44722
+ variant,
44723
+ void 0,
44724
+ "jsonKey",
44725
+ "exportJsonKey",
44726
+ "htmlKey",
44727
+ variantPath
44728
+ ),
44729
+ bodyFormat: variantBodyFormat(variant),
44287
44730
  tags: variantTags,
44288
- repeatCount: variant.repeatCount ?? 1,
44731
+ ...variant.repeatCount != null && variant.repeatCount !== 1 ? { repeatCount: variant.repeatCount } : {},
44289
44732
  ...variant.bodyRequired ? { bodyRequired: true } : {},
44290
44733
  ...variant.bodyAllowed === false ? { bodyForbidden: true } : {}
44291
44734
  };
@@ -44293,8 +44736,14 @@ var ConfigBuilder = class {
44293
44736
  return {
44294
44737
  name: side.name,
44295
44738
  ...side.repeat ? { repeat: side.repeat } : {},
44296
- ...cardJsonKeyField(side, "jsonKey", "exportJsonKey", sidePath),
44297
- ...cardHtmlKeyField(side, "htmlKey"),
44739
+ ...cardMappingKeysField(
44740
+ side,
44741
+ side.mappingKeys,
44742
+ "jsonKey",
44743
+ "exportJsonKey",
44744
+ "htmlKey",
44745
+ sidePath
44746
+ ),
44298
44747
  variants
44299
44748
  };
44300
44749
  });
@@ -44305,20 +44754,40 @@ var ConfigBuilder = class {
44305
44754
  const hasSideHtml = Object.prototype.hasOwnProperty.call(section, "sideHtmlKey");
44306
44755
  let cardSides = sides;
44307
44756
  if (hasSideExport || section.sideJsonKey != null || hasSideHtml) {
44308
- const sideOverride = cardJsonKeyField(
44309
- section,
44310
- "sideJsonKey",
44311
- "sideExportJsonKey",
44312
- `${sectionPath} / sides.*`
44313
- );
44314
- const sideHtmlOverride = cardHtmlKeyField(section, "sideHtmlKey");
44315
- 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
+ });
44316
44779
  }
44317
44780
  return {
44318
44781
  name: sectionName,
44319
44782
  ...section.isDefault ? { isDefault: true } : {},
44320
- ...cardJsonKeyField(section, "jsonKey", "exportJsonKey", sectionPath),
44321
- ...cardHtmlKeyField(section, "htmlKey"),
44783
+ ...cardMappingKeysField(
44784
+ section,
44785
+ section.mappingKeys,
44786
+ "jsonKey",
44787
+ "exportJsonKey",
44788
+ "htmlKey",
44789
+ sectionPath
44790
+ ),
44322
44791
  // PLAN-085: per-section cardinality. Emit only when non-default
44323
44792
  // (treat `0` / undefined as "unbounded — omit").
44324
44793
  ...section.minCount != null && section.minCount !== 0 ? { min: section.minCount } : {},
@@ -44326,7 +44795,18 @@ var ConfigBuilder = class {
44326
44795
  sides: cardSides
44327
44796
  };
44328
44797
  });
44329
- 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
+ };
44330
44810
  }
44331
44811
  const cardSetPath = `cardSets.${normalizedKey} / cards.default`;
44332
44812
  return {
@@ -44335,8 +44815,14 @@ var ConfigBuilder = class {
44335
44815
  {
44336
44816
  name: "default",
44337
44817
  isDefault: true,
44338
- ...cardJsonKeyField(cardSetConfig, "jsonKey", "exportJsonKey", cardSetPath),
44339
- ...cardHtmlKeyField(cardSetConfig, "htmlKey"),
44818
+ ...cardMappingKeysField(
44819
+ cardSetConfig,
44820
+ cardSetConfig.mappingKeys,
44821
+ "jsonKey",
44822
+ "exportJsonKey",
44823
+ "htmlKey",
44824
+ cardSetPath
44825
+ ),
44340
44826
  sides
44341
44827
  }
44342
44828
  ]
@@ -44372,14 +44858,19 @@ var ConfigBuilder = class {
44372
44858
  ...t.max != null ? { max: t.max } : {},
44373
44859
  ...t.description ? { description: t.description } : {}
44374
44860
  };
44375
- if (Object.prototype.hasOwnProperty.call(t, "jsonKey")) {
44376
- ref.exportJsonKey = t.jsonKey;
44861
+ const record = t.mappingKeys ?? {};
44862
+ if (Object.prototype.hasOwnProperty.call(record, "json")) {
44863
+ ref.exportJsonKey = record.json;
44377
44864
  ref.hasExportJsonKey = true;
44378
44865
  }
44379
- if (Object.prototype.hasOwnProperty.call(t, "htmlKey")) {
44380
- ref.htmlKey = t.htmlKey;
44866
+ if (Object.prototype.hasOwnProperty.call(record, "html")) {
44867
+ ref.htmlKey = record.html;
44381
44868
  ref.hasHtmlKey = true;
44382
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;
44383
44874
  replacements.push(ref);
44384
44875
  }
44385
44876
  squashedGroups.set(groupKey, replacements);
@@ -44413,8 +44904,11 @@ var ConfigBuilder = class {
44413
44904
  pushOrReplace({
44414
44905
  type: "group",
44415
44906
  key: ref.key,
44416
- ...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
44417
- ...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
+ ),
44418
44912
  ...ref.min != null ? { min: ref.min } : {},
44419
44913
  ...ref.max != null ? { max: ref.max } : {},
44420
44914
  ...ref.description ? { description: ref.description } : {}
@@ -44427,8 +44921,11 @@ var ConfigBuilder = class {
44427
44921
  pushOrReplace({
44428
44922
  type: "group",
44429
44923
  key: ref.key,
44430
- ...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
44431
- ...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
+ ),
44432
44929
  ...ref.min != null ? { min: ref.min } : {},
44433
44930
  ...ref.max != null ? { max: ref.max } : {},
44434
44931
  ...ref.description ? { description: ref.description } : {}
@@ -44455,20 +44952,17 @@ var ConfigBuilder = class {
44455
44952
  description: b.description ?? "",
44456
44953
  since: resolvedBitConfig.since,
44457
44954
  deprecated: resolvedBitConfig.deprecated,
44458
- history: [
44459
- {
44460
- version: resolvedBitConfig.since,
44461
- changes: ["Initial version"]
44462
- }
44463
- ],
44464
- format: resolvedBitConfig.textFormatDefault ?? "bitmark--",
44465
- bodyRequired: resolvedBitConfig.bodyRequired ?? false,
44466
- bodyForbidden: !(resolvedBitConfig.bodyAllowed ?? true),
44467
- footerRequired: resolvedBitConfig.footerRequired ?? false,
44468
- footerForbidden: !(resolvedBitConfig.footerAllowed ?? true),
44469
- 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 }),
44470
44964
  tags: tags2,
44471
- ...cardRef ? { card: cardRef } : {}
44965
+ ...cardRef ? { cardSet: cardRef } : {}
44472
44966
  };
44473
44967
  const output = path3.join(outputFolderBits, `${b.bitType}.jsonc`);
44474
44968
  const str = JSON.stringify(bitJson, null, 2);
@@ -44496,14 +44990,7 @@ var ConfigBuilder = class {
44496
44990
  const bitJson = {
44497
44991
  name: groupKey,
44498
44992
  description: g.description ?? "",
44499
- since: "UNKNOWN",
44500
44993
  deprecated: g.deprecated,
44501
- history: [
44502
- {
44503
- version: "UNKNOWN",
44504
- changes: ["Initial version"]
44505
- }
44506
- ],
44507
44994
  tags: tags2
44508
44995
  // cards: [
44509
44996
  // {
@@ -44557,8 +45044,11 @@ var ConfigBuilder = class {
44557
45044
  tags2.push({
44558
45045
  type: "group",
44559
45046
  key: ref.key,
44560
- ...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
44561
- ...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
+ ),
44562
45052
  ...ref.min != null ? { min: ref.min } : {},
44563
45053
  ...ref.max != null ? { max: ref.max } : {},
44564
45054
  ...ref.description ? { description: ref.description } : {}
@@ -44579,14 +45069,7 @@ var ConfigBuilder = class {
44579
45069
  const bitJson = {
44580
45070
  name: groupKey,
44581
45071
  description: b.description ?? "",
44582
- since: "UNKNOWN",
44583
45072
  deprecated: b.deprecated,
44584
- history: [
44585
- {
44586
- version: "UNKNOWN",
44587
- changes: ["Initial version"]
44588
- }
44589
- ],
44590
45073
  tags: tags2
44591
45074
  };
44592
45075
  const output = path3.join(outputFolderGroups, `${groupKey}.jsonc`);
@@ -44627,7 +45110,7 @@ var ConfigBuilder = class {
44627
45110
  validateConfigTree(outputFolder) {
44628
45111
  const errors = [];
44629
45112
  const outputFolderBits = path3.join(outputFolder, "bits");
44630
- const outputFolderGroups = path3.join(outputFolder, "partials");
45113
+ const outputFolderGroups = path3.join(outputFolder, "groups");
44631
45114
  const outputFolderCards = path3.join(outputFolder, "cards");
44632
45115
  const availableGroups = /* @__PURE__ */ new Set();
44633
45116
  if (fs4.existsSync(outputFolderGroups)) {
@@ -44701,7 +45184,7 @@ var ConfigBuilder = class {
44701
45184
  const content = fs4.readFileSync(filePath, "utf-8");
44702
45185
  const config = JSON.parse(content);
44703
45186
  if (config.tags && Array.isArray(config.tags)) {
44704
- checkTags(config.tags, `partials/${file}`, 15);
45187
+ checkTags(config.tags, `groups/${file}`, 15);
44705
45188
  }
44706
45189
  } catch (err) {
44707
45190
  errors.push(`Failed to parse ${file}: ${err}`);