@gmb/bitmark-parser-generator 5.22.0 → 5.23.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
@@ -42,6 +42,7 @@ __export(index_exports, {
42
42
  BitmarkStringGenerator: () => BitmarkStringGenerator,
43
43
  BitmarkVersion: () => BitmarkVersion,
44
44
  BodyTextFormat: () => BodyTextFormat,
45
+ BoundingBoxIndex: () => BoundingBoxIndex,
45
46
  Builder: () => Builder,
46
47
  CardSetVersion: () => CardSetVersion,
47
48
  FileWriter: () => FileWriter,
@@ -340,6 +341,7 @@ var BitType = {
340
341
  footNote: "foot-note",
341
342
  formFreeText: "form-free-text",
342
343
  formula: "formula",
344
+ formulaImage: "formula-image",
343
345
  gapText: "gap-text",
344
346
  gapTextInstructionGrouped: "gap-text-instruction-grouped",
345
347
  glossaryTerm: "glossary-term",
@@ -764,8 +766,10 @@ var TagFormat = {
764
766
  // If the value is treated as a boolean
765
767
  invertedBoolean: "invertedBoolean",
766
768
  // If the value is treated as a boolean with the value inverted (e.g. isLongAnswer ==> isShortAnswer = false)
767
- enumeration: "enumeration"
769
+ enumeration: "enumeration",
768
770
  // If the value is treated as an enumeration (the value is a string that must be one of a predefined set of values)
771
+ coordinates: "coordinates"
772
+ // Comma-separated list of 4 numbers (e.g. bounding-box x, y, x1, y1)
769
773
  };
770
774
 
771
775
  // src/model/enum/TextFormat.ts
@@ -850,7 +854,11 @@ var AbstractTagConfig = class {
850
854
  // Default: 0
851
855
  __publicField(this, "chain");
852
856
  __publicField(this, "jsonKey");
853
- // If the json key is different from the tag
857
+ // Legacy string-form jsonKey
858
+ __publicField(this, "exportJsonKey");
859
+ // New JSON-pattern jsonKey (export-only)
860
+ __publicField(this, "hasExportJsonKey");
861
+ // True iff exportJsonKey was explicitly set
854
862
  __publicField(this, "deprecated");
855
863
  this.type = params.type;
856
864
  this.configKey = params.configKey;
@@ -859,6 +867,8 @@ var AbstractTagConfig = class {
859
867
  this.minCount = params.minCount;
860
868
  this.chain = params.chain;
861
869
  this.jsonKey = params.jsonKey;
870
+ this.exportJsonKey = params.exportJsonKey;
871
+ this.hasExportJsonKey = params.hasExportJsonKey;
862
872
  this.deprecated = params.deprecated;
863
873
  }
864
874
  };
@@ -868,7 +878,6 @@ var MarkupTagConfig = class extends AbstractTagConfig {
868
878
  constructor(params) {
869
879
  super({
870
880
  type: BitTagConfigKeyType.tag,
871
- jsonKey: void 0,
872
881
  ...params
873
882
  });
874
883
  __publicField(this, "type", BitTagConfigKeyType.tag);
@@ -980,8 +989,8 @@ var ResourceTagConfig = class extends AbstractTagConfig {
980
989
 
981
990
  // src/model/config/CardVariantConfig.ts
982
991
  var CardVariantConfig = class {
983
- // JSON path for body text
984
- constructor(tags2, bodyAllowed, bodyRequired, repeatCount, jsonKey) {
992
+ // Body text format. Default: bitmark++
993
+ constructor(tags2, bodyAllowed, bodyRequired, repeatCount, jsonKey, exportJsonKey, hasExportJsonKey = false, format) {
985
994
  __publicField(this, "tags");
986
995
  __publicField(this, "bodyAllowed");
987
996
  // Default: true
@@ -991,11 +1000,19 @@ var CardVariantConfig = class {
991
1000
  // Default: 1
992
1001
  // JSON mapping fields
993
1002
  __publicField(this, "jsonKey");
1003
+ // JSON path for body text (legacy)
1004
+ __publicField(this, "exportJsonKey");
1005
+ // New JSON-pattern jsonKey
1006
+ __publicField(this, "hasExportJsonKey");
1007
+ __publicField(this, "format");
994
1008
  this.tags = tags2;
995
1009
  this.bodyAllowed = bodyAllowed == null ? true : bodyAllowed;
996
1010
  this.bodyRequired = bodyRequired;
997
1011
  this.repeatCount = repeatCount;
998
1012
  this.jsonKey = jsonKey;
1013
+ this.exportJsonKey = exportJsonKey;
1014
+ this.hasExportJsonKey = hasExportJsonKey;
1015
+ this.format = format;
999
1016
  }
1000
1017
  toString(options) {
1001
1018
  const opts = Object.assign({}, options);
@@ -1019,14 +1036,18 @@ ${tag.toString(opts)}`;
1019
1036
 
1020
1037
  // src/model/config/CardSideConfig.ts
1021
1038
  var CardSideConfig = class {
1022
- constructor(name, repeat, variants, jsonKey) {
1039
+ constructor(name, repeat, variants, jsonKey, exportJsonKey, hasExportJsonKey = false) {
1023
1040
  __publicField(this, "name");
1024
1041
  __publicField(this, "repeat");
1025
1042
  __publicField(this, "jsonKey");
1043
+ __publicField(this, "exportJsonKey");
1044
+ __publicField(this, "hasExportJsonKey");
1026
1045
  __publicField(this, "variants");
1027
1046
  this.name = name;
1028
1047
  this.repeat = repeat;
1029
1048
  this.jsonKey = jsonKey;
1049
+ this.exportJsonKey = exportJsonKey;
1050
+ this.hasExportJsonKey = hasExportJsonKey;
1030
1051
  this.variants = variants;
1031
1052
  }
1032
1053
  toString(options) {
@@ -1048,13 +1069,17 @@ var CardSideConfig = class {
1048
1069
 
1049
1070
  // src/model/config/CardSetConfig.ts
1050
1071
  var CardSetConfig = class {
1051
- constructor(configKey, jsonKey, sections, sides) {
1072
+ constructor(configKey, jsonKey, exportJsonKey, hasExportJsonKey, sections, sides) {
1052
1073
  __publicField(this, "configKey");
1053
1074
  __publicField(this, "jsonKey");
1075
+ __publicField(this, "exportJsonKey");
1076
+ __publicField(this, "hasExportJsonKey");
1054
1077
  __publicField(this, "sections");
1055
1078
  __publicField(this, "sides");
1056
1079
  this.configKey = configKey;
1057
1080
  this.jsonKey = jsonKey;
1081
+ this.exportJsonKey = exportJsonKey;
1082
+ this.hasExportJsonKey = hasExportJsonKey;
1058
1083
  this.sections = sections;
1059
1084
  this.sides = sides;
1060
1085
  }
@@ -1349,6 +1374,7 @@ var propertyKeys = {
1349
1374
  property_formula: "@formula",
1350
1375
  property_fullName: "@fullName",
1351
1376
  property_groupTag: "@groupTag",
1377
+ property_gUri: "@gUri",
1352
1378
  property_handInAcceptFileType: "@handInAcceptFileType",
1353
1379
  property_handInInstruction: "@handInInstruction",
1354
1380
  property_handInRequirement: "@handInRequirement",
@@ -1484,6 +1510,7 @@ var propertyKeys = {
1484
1510
  property_siteName: "@siteName",
1485
1511
  property_size: "@size",
1486
1512
  property_slug: "@slug",
1513
+ property_sourceBB: "@sourceBB",
1487
1514
  property_sourceDocument: "@sourceDocument",
1488
1515
  property_sourceRL: "@sourceRL",
1489
1516
  property_spaceId: "@spaceId",
@@ -2237,25 +2264,29 @@ var CARDSETS = {
2237
2264
  //
2238
2265
  [CardSetConfigKey.flashcard]: {
2239
2266
  jsonKey: "cards",
2267
+ exportJsonKey: { cards: "$" },
2240
2268
  sides: [
2241
2269
  {
2242
2270
  name: "question",
2243
2271
  variants: [
2244
2272
  {
2245
2273
  jsonKey: "question.text",
2274
+ exportJsonKey: { question: { text: "$" } },
2246
2275
  tags: [
2247
2276
  {
2248
2277
  key: ConfigKey.group_standardTags,
2249
2278
  description: "Standard tags for the flashcard."
2250
2279
  },
2251
2280
  {
2281
+ exportJsonKey: { title: "$" },
2252
2282
  key: ConfigKey.tag_title,
2253
2283
  description: "Title of the flashcard."
2254
2284
  },
2255
2285
  {
2256
2286
  key: ConfigKey.group_resourceIcon,
2257
2287
  description: "Icon resource for the flashcard.",
2258
- jsonKey: "question.icon|resource(type=image, key=image)"
2288
+ jsonKey: "question.icon|resource(type=image, key=image)",
2289
+ exportJsonKey: { question: { icon: { type: "image", image: { src: "$" } } } }
2259
2290
  }
2260
2291
  ]
2261
2292
  }
@@ -2266,37 +2297,45 @@ var CARDSETS = {
2266
2297
  variants: [
2267
2298
  {
2268
2299
  jsonKey: "answer.text",
2300
+ exportJsonKey: { answer: { text: "$" } },
2269
2301
  tags: [
2270
2302
  {
2271
2303
  key: ConfigKey.group_standardTags,
2272
2304
  description: "Standard tags for the flashcard."
2273
2305
  },
2274
2306
  {
2307
+ exportJsonKey: { title: "$" },
2275
2308
  key: ConfigKey.tag_title,
2276
2309
  description: "Title of the flashcard."
2277
2310
  },
2278
2311
  {
2279
2312
  key: ConfigKey.group_resourceIcon,
2280
2313
  description: "Icon resource for the flashcard.",
2281
- jsonKey: "answer.icon|resource(type=image, key=image)"
2314
+ jsonKey: "answer.icon|resource(type=image, key=image)",
2315
+ exportJsonKey: { answer: { icon: { type: "image", image: { src: "$" } } } }
2282
2316
  }
2283
2317
  ]
2284
2318
  },
2285
2319
  {
2286
2320
  jsonKey: "alternativeAnswers[].text",
2321
+ exportJsonKey: { alternativeAnswers: [{ text: "$" }] },
2287
2322
  tags: [
2288
2323
  {
2289
2324
  key: ConfigKey.group_standardTags,
2290
2325
  description: "Standard tags for the flashcard."
2291
2326
  },
2292
2327
  {
2328
+ exportJsonKey: { title: "$" },
2293
2329
  key: ConfigKey.tag_title,
2294
2330
  description: "Title of the flashcard."
2295
2331
  },
2296
2332
  {
2297
2333
  key: ConfigKey.group_resourceIcon,
2298
2334
  description: "Icon resource for the flashcard.",
2299
- jsonKey: "alternativeAnswers[].icon|resource(type=image, key=image)"
2335
+ jsonKey: "alternativeAnswers[].icon|resource(type=image, key=image)",
2336
+ exportJsonKey: {
2337
+ alternativeAnswers: [{ icon: { type: "image", image: { src: "$" } } }]
2338
+ }
2300
2339
  }
2301
2340
  ],
2302
2341
  repeatCount: Count.infinity
@@ -2310,12 +2349,14 @@ var CARDSETS = {
2310
2349
  //
2311
2350
  [CardSetConfigKey.definitionList]: {
2312
2351
  jsonKey: "definitions",
2352
+ exportJsonKey: { definitions: "$" },
2313
2353
  sides: [
2314
2354
  {
2315
2355
  name: "term",
2316
2356
  variants: [
2317
2357
  {
2318
2358
  jsonKey: "term.text",
2359
+ exportJsonKey: { term: { text: "$" } },
2319
2360
  tags: [
2320
2361
  {
2321
2362
  key: ConfigKey.group_standardTags,
@@ -2325,13 +2366,15 @@ var CARDSETS = {
2325
2366
  key: ConfigKey.tag_title,
2326
2367
  description: "Title of the definition.",
2327
2368
  format: TagFormat.plainText,
2328
- jsonKey: "^heading.forKeys"
2369
+ jsonKey: "^heading.forKeys",
2370
+ exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2329
2371
  },
2330
2372
  {
2331
2373
  key: ConfigKey.group_resourceIcon,
2332
2374
  description: "Icon resource for the definition.",
2333
2375
  format: TagFormat.plainText,
2334
- jsonKey: "term.icon|resource(type=image, key=image)"
2376
+ jsonKey: "term.icon|resource(type=image, key=image)",
2377
+ exportJsonKey: { term: { icon: { type: "image", image: { src: "$" } } } }
2335
2378
  }
2336
2379
  ]
2337
2380
  }
@@ -2342,6 +2385,7 @@ var CARDSETS = {
2342
2385
  variants: [
2343
2386
  {
2344
2387
  jsonKey: "definition.text",
2388
+ exportJsonKey: { definition: { text: "$" } },
2345
2389
  tags: [
2346
2390
  {
2347
2391
  key: ConfigKey.group_standardTags,
@@ -2351,30 +2395,37 @@ var CARDSETS = {
2351
2395
  key: ConfigKey.tag_title,
2352
2396
  description: "Title of the definition.",
2353
2397
  format: TagFormat.plainText,
2354
- jsonKey: "^heading.forValues"
2398
+ jsonKey: "^heading.forValues",
2399
+ exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2355
2400
  },
2356
2401
  {
2357
2402
  key: ConfigKey.group_resourceIcon,
2358
2403
  description: "Icon resource for the definition.",
2359
- jsonKey: "definition.icon|resource(type=image, key=image)"
2404
+ jsonKey: "definition.icon|resource(type=image, key=image)",
2405
+ exportJsonKey: { definition: { icon: { type: "image", image: { src: "$" } } } }
2360
2406
  }
2361
2407
  ]
2362
2408
  },
2363
2409
  {
2364
2410
  jsonKey: "alternativeDefinitions[].text",
2411
+ exportJsonKey: { alternativeDefinitions: [{ text: "$" }] },
2365
2412
  tags: [
2366
2413
  {
2367
2414
  key: ConfigKey.group_standardTags,
2368
2415
  description: "Standard tags for the definition."
2369
2416
  },
2370
2417
  {
2418
+ exportJsonKey: { title: "$" },
2371
2419
  key: ConfigKey.tag_title,
2372
2420
  description: "Title of the definition."
2373
2421
  },
2374
2422
  {
2375
2423
  key: ConfigKey.group_resourceIcon,
2376
2424
  description: "Icon resource for the definition.",
2377
- jsonKey: "alternativeDefinitions[].icon|resource(type=image, key=image)"
2425
+ jsonKey: "alternativeDefinitions[].icon|resource(type=image, key=image)",
2426
+ exportJsonKey: {
2427
+ alternativeDefinitions: [{ icon: { type: "image", image: { src: "$" } } }]
2428
+ }
2378
2429
  }
2379
2430
  ],
2380
2431
  repeatCount: Count.infinity
@@ -2388,12 +2439,14 @@ var CARDSETS = {
2388
2439
  //
2389
2440
  [CardSetConfigKey.matchPairs]: {
2390
2441
  jsonKey: "pairs",
2442
+ exportJsonKey: { pairs: "$" },
2391
2443
  sides: [
2392
2444
  {
2393
2445
  name: "key",
2394
2446
  variants: [
2395
2447
  {
2396
2448
  jsonKey: "key",
2449
+ exportJsonKey: { key: "$" },
2397
2450
  tags: [
2398
2451
  {
2399
2452
  key: ConfigKey.group_standardTags,
@@ -2403,22 +2456,29 @@ var CARDSETS = {
2403
2456
  key: ConfigKey.tag_title,
2404
2457
  description: "Title of the match pair.",
2405
2458
  format: TagFormat.plainText,
2406
- jsonKey: "^heading.forKeys"
2459
+ jsonKey: "^heading.forKeys",
2460
+ exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2407
2461
  },
2408
2462
  {
2409
2463
  key: ConfigKey.property_isCaseSensitive,
2464
+ exportJsonKey: [
2465
+ { "@absent": { isCaseSensitive: "$ancestor" } },
2466
+ { isCaseSensitive: "$" }
2467
+ ],
2410
2468
  description: "Property to indicate if the match is case sensitive.",
2411
2469
  format: TagFormat.boolean
2412
2470
  },
2413
2471
  {
2414
2472
  key: ConfigKey.resource_audio,
2415
2473
  description: "Audio resource for the match pair.",
2416
- jsonKey: "keyAudio"
2474
+ jsonKey: "keyAudio",
2475
+ exportJsonKey: { keyAudio: "$" }
2417
2476
  },
2418
2477
  {
2419
2478
  key: ConfigKey.resource_image,
2420
2479
  description: "Image resource for the match pair.",
2421
- jsonKey: "keyImage"
2480
+ jsonKey: "keyImage",
2481
+ exportJsonKey: { keyImage: "$" }
2422
2482
  }
2423
2483
  ]
2424
2484
  }
@@ -2430,6 +2490,7 @@ var CARDSETS = {
2430
2490
  variants: [
2431
2491
  {
2432
2492
  jsonKey: "values[]",
2493
+ exportJsonKey: { values: ["$"] },
2433
2494
  tags: [
2434
2495
  {
2435
2496
  key: ConfigKey.group_standardTags,
@@ -2439,10 +2500,15 @@ var CARDSETS = {
2439
2500
  key: ConfigKey.tag_title,
2440
2501
  description: "Title of the match pair.",
2441
2502
  format: TagFormat.plainText,
2442
- jsonKey: "^heading.forValues"
2503
+ jsonKey: "^heading.forValues",
2504
+ exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2443
2505
  },
2444
2506
  {
2445
2507
  key: ConfigKey.property_isCaseSensitive,
2508
+ exportJsonKey: [
2509
+ { "@absent": { isCaseSensitive: "$ancestor" } },
2510
+ { isCaseSensitive: "$" }
2511
+ ],
2446
2512
  description: "Property to indicate if the match is case sensitive.",
2447
2513
  format: TagFormat.boolean
2448
2514
  }
@@ -2458,12 +2524,14 @@ var CARDSETS = {
2458
2524
  //
2459
2525
  [CardSetConfigKey.matchAudioPairs]: {
2460
2526
  jsonKey: "pairs",
2527
+ exportJsonKey: { pairs: "$" },
2461
2528
  sides: [
2462
2529
  {
2463
2530
  name: "key",
2464
2531
  variants: [
2465
2532
  {
2466
2533
  jsonKey: "key",
2534
+ exportJsonKey: { key: "$" },
2467
2535
  tags: [
2468
2536
  {
2469
2537
  key: ConfigKey.group_standardTags,
@@ -2473,12 +2541,14 @@ var CARDSETS = {
2473
2541
  key: ConfigKey.tag_title,
2474
2542
  description: "Title of the audio match pair.",
2475
2543
  format: TagFormat.plainText,
2476
- jsonKey: "^heading.forKeys"
2544
+ jsonKey: "^heading.forKeys",
2545
+ exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2477
2546
  },
2478
2547
  {
2479
2548
  key: ConfigKey.resource_audio,
2480
2549
  description: "Audio resource for the match pair.",
2481
- jsonKey: "keyAudio"
2550
+ jsonKey: "keyAudio",
2551
+ exportJsonKey: { keyAudio: "$" }
2482
2552
  }
2483
2553
  ]
2484
2554
  }
@@ -2490,6 +2560,7 @@ var CARDSETS = {
2490
2560
  variants: [
2491
2561
  {
2492
2562
  jsonKey: "values[]",
2563
+ exportJsonKey: { values: ["$"] },
2493
2564
  tags: [
2494
2565
  {
2495
2566
  key: ConfigKey.group_standardTags,
@@ -2499,7 +2570,8 @@ var CARDSETS = {
2499
2570
  key: ConfigKey.tag_title,
2500
2571
  description: "Title of the audio match pair.",
2501
2572
  format: TagFormat.plainText,
2502
- jsonKey: "^heading.forValues"
2573
+ jsonKey: "^heading.forValues",
2574
+ exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2503
2575
  },
2504
2576
  {
2505
2577
  key: ConfigKey.resource_audio,
@@ -2517,12 +2589,14 @@ var CARDSETS = {
2517
2589
  //
2518
2590
  [CardSetConfigKey.matchImagePairs]: {
2519
2591
  jsonKey: "pairs",
2592
+ exportJsonKey: { pairs: "$" },
2520
2593
  sides: [
2521
2594
  {
2522
2595
  name: "key",
2523
2596
  variants: [
2524
2597
  {
2525
2598
  jsonKey: "key",
2599
+ exportJsonKey: { key: "$" },
2526
2600
  tags: [
2527
2601
  {
2528
2602
  key: ConfigKey.group_standardTags,
@@ -2532,12 +2606,14 @@ var CARDSETS = {
2532
2606
  key: ConfigKey.tag_title,
2533
2607
  description: "Title of the image match pair.",
2534
2608
  format: TagFormat.plainText,
2535
- jsonKey: "^heading.forKeys"
2609
+ jsonKey: "^heading.forKeys",
2610
+ exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2536
2611
  },
2537
2612
  {
2538
2613
  key: ConfigKey.resource_image,
2539
2614
  description: "Image resource for the match pair.",
2540
- jsonKey: "keyImage"
2615
+ jsonKey: "keyImage",
2616
+ exportJsonKey: { keyImage: "$" }
2541
2617
  }
2542
2618
  ]
2543
2619
  }
@@ -2549,6 +2625,7 @@ var CARDSETS = {
2549
2625
  variants: [
2550
2626
  {
2551
2627
  jsonKey: "values[]",
2628
+ exportJsonKey: { values: ["$"] },
2552
2629
  tags: [
2553
2630
  {
2554
2631
  key: ConfigKey.group_standardTags,
@@ -2558,7 +2635,8 @@ var CARDSETS = {
2558
2635
  key: ConfigKey.tag_title,
2559
2636
  description: "Title of the image match pair.",
2560
2637
  format: TagFormat.plainText,
2561
- jsonKey: "^heading.forValues"
2638
+ jsonKey: "^heading.forValues",
2639
+ exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2562
2640
  },
2563
2641
  {
2564
2642
  key: ConfigKey.resource_image,
@@ -2576,12 +2654,14 @@ var CARDSETS = {
2576
2654
  //
2577
2655
  [CardSetConfigKey.matchMatrix]: {
2578
2656
  jsonKey: "matrix",
2657
+ exportJsonKey: { matrix: "$" },
2579
2658
  sides: [
2580
2659
  {
2581
2660
  name: "key",
2582
2661
  variants: [
2583
2662
  {
2584
2663
  jsonKey: "key",
2664
+ exportJsonKey: { key: "$" },
2585
2665
  tags: [
2586
2666
  {
2587
2667
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -2589,6 +2669,11 @@ var CARDSETS = {
2589
2669
  },
2590
2670
  {
2591
2671
  key: ConfigKey.property_example,
2672
+ exportJsonKey: [
2673
+ { "@keyonly": { isExample: true, "@bit": { isExample: true } } },
2674
+ { "@absent": { isExample: true, "@bit": { isExample: true } } },
2675
+ { isExample: true, example: "$", "@bit": { isExample: true } }
2676
+ ],
2592
2677
  description: "Example text for the match matrix.",
2593
2678
  format: TagFormat.plainText
2594
2679
  },
@@ -2596,10 +2681,15 @@ var CARDSETS = {
2596
2681
  key: ConfigKey.tag_title,
2597
2682
  description: "Title of the match matrix.",
2598
2683
  format: TagFormat.plainText,
2599
- jsonKey: "^heading.forKeys"
2684
+ jsonKey: "^heading.forKeys",
2685
+ exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2600
2686
  },
2601
2687
  {
2602
2688
  key: ConfigKey.property_isCaseSensitive,
2689
+ exportJsonKey: [
2690
+ { "@absent": { isCaseSensitive: "$ancestor" } },
2691
+ { isCaseSensitive: "$" }
2692
+ ],
2603
2693
  description: "Property to indicate if the match is case sensitive.",
2604
2694
  format: TagFormat.boolean
2605
2695
  }
@@ -2613,6 +2703,7 @@ var CARDSETS = {
2613
2703
  variants: [
2614
2704
  {
2615
2705
  jsonKey: "cells[{s}].values[]",
2706
+ exportJsonKey: { cells: { $s: { values: ["$"] } } },
2616
2707
  tags: [
2617
2708
  {
2618
2709
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -2620,6 +2711,18 @@ var CARDSETS = {
2620
2711
  },
2621
2712
  {
2622
2713
  key: ConfigKey.property_example,
2714
+ exportJsonKey: [
2715
+ {
2716
+ "@keyonly": {
2717
+ cells: { $s: { isExample: true, example: "$parent.values[0]" } },
2718
+ "@bit": { isExample: true }
2719
+ }
2720
+ },
2721
+ {
2722
+ "@absent": { cells: { $s: { isExample: true, example: "$parent.values[0]" } } }
2723
+ },
2724
+ { cells: { $s: { isExample: true, example: "$" } }, "@bit": { isExample: true } }
2725
+ ],
2623
2726
  description: "Example text for the match matrix.",
2624
2727
  format: TagFormat.plainText
2625
2728
  },
@@ -2627,10 +2730,15 @@ var CARDSETS = {
2627
2730
  key: ConfigKey.tag_title,
2628
2731
  description: "Title of the match matrix.",
2629
2732
  format: TagFormat.plainText,
2630
- jsonKey: "^heading.forValues"
2733
+ jsonKey: "^heading.forValues",
2734
+ exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2631
2735
  },
2632
2736
  {
2633
2737
  key: ConfigKey.property_isCaseSensitive,
2738
+ exportJsonKey: [
2739
+ { "@absent": { isCaseSensitive: "$ancestor" } },
2740
+ { isCaseSensitive: "$" }
2741
+ ],
2634
2742
  description: "Property to indicate if the match is case sensitive.",
2635
2743
  format: TagFormat.boolean
2636
2744
  }
@@ -2646,23 +2754,27 @@ var CARDSETS = {
2646
2754
  //
2647
2755
  [CardSetConfigKey.statements]: {
2648
2756
  jsonKey: "statements",
2757
+ exportJsonKey: { statements: "$" },
2649
2758
  sides: [
2650
2759
  {
2651
2760
  name: "statement",
2652
2761
  variants: [
2653
2762
  {
2654
2763
  jsonKey: "statement",
2764
+ exportJsonKey: { statement: "$" },
2655
2765
  tags: [
2656
2766
  {
2657
2767
  key: ConfigKey.tag_true,
2658
2768
  description: "Tag for true statements.",
2659
2769
  jsonKey: "statement|set(isCorrect=true)",
2770
+ exportJsonKey: { statement: "$", isCorrect: true },
2660
2771
  maxCount: 1
2661
2772
  },
2662
2773
  {
2663
2774
  key: ConfigKey.tag_false,
2664
2775
  description: "Tag for false statements.",
2665
2776
  jsonKey: "statement|set(isCorrect=false)",
2777
+ exportJsonKey: { statement: "$", isCorrect: false },
2666
2778
  maxCount: 1
2667
2779
  },
2668
2780
  {
@@ -2681,6 +2793,7 @@ var CARDSETS = {
2681
2793
  //
2682
2794
  [CardSetConfigKey.quiz]: {
2683
2795
  jsonKey: "quizzes",
2796
+ exportJsonKey: { quizzes: "$" },
2684
2797
  sides: [
2685
2798
  {
2686
2799
  name: "choices",
@@ -2708,6 +2821,7 @@ var CARDSETS = {
2708
2821
  //
2709
2822
  [CardSetConfigKey.feedback]: {
2710
2823
  jsonKey: "feedbacks",
2824
+ exportJsonKey: { feedbacks: "$" },
2711
2825
  sides: [
2712
2826
  {
2713
2827
  name: "choices",
@@ -2727,7 +2841,8 @@ var CARDSETS = {
2727
2841
  key: ConfigKey.tag_title,
2728
2842
  description: "Title of the feedback.",
2729
2843
  format: TagFormat.plainText,
2730
- jsonKey: "^heading.forKeys"
2844
+ jsonKey: "^heading.forKeys",
2845
+ exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2731
2846
  }
2732
2847
  ],
2733
2848
  bodyAllowed: false
@@ -2739,6 +2854,7 @@ var CARDSETS = {
2739
2854
  variants: [
2740
2855
  {
2741
2856
  jsonKey: "reason.text",
2857
+ exportJsonKey: { reason: { text: "$" } },
2742
2858
  tags: [
2743
2859
  {
2744
2860
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -2746,11 +2862,20 @@ var CARDSETS = {
2746
2862
  },
2747
2863
  {
2748
2864
  key: ConfigKey.property_reasonableNumOfChars,
2865
+ exportJsonKey: [
2866
+ { "@absent": { reasonableNumOfChars: "$ancestor" } },
2867
+ { reasonableNumOfChars: "$" }
2868
+ ],
2749
2869
  description: "Property for reasonable number of characters.",
2750
2870
  format: TagFormat.number
2751
2871
  },
2752
2872
  {
2753
2873
  key: ConfigKey.property_example,
2874
+ exportJsonKey: [
2875
+ { "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
2876
+ { "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
2877
+ { isExample: true, example: "$", "@bit": { isExample: true } }
2878
+ ],
2754
2879
  description: "Example text for the feedback.",
2755
2880
  format: TagFormat.plainText
2756
2881
  },
@@ -2758,7 +2883,8 @@ var CARDSETS = {
2758
2883
  key: ConfigKey.tag_title,
2759
2884
  description: "Title of the feedback.",
2760
2885
  format: TagFormat.plainText,
2761
- jsonKey: "^heading.forValues"
2886
+ jsonKey: "^heading.forValues",
2887
+ exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2762
2888
  }
2763
2889
  ],
2764
2890
  bodyAllowed: true
@@ -2772,21 +2898,29 @@ var CARDSETS = {
2772
2898
  //
2773
2899
  [CardSetConfigKey.questions]: {
2774
2900
  jsonKey: "questions",
2901
+ exportJsonKey: { questions: "$" },
2775
2902
  sides: [
2776
2903
  {
2777
2904
  name: "question",
2778
2905
  variants: [
2779
2906
  {
2780
2907
  jsonKey: "question",
2908
+ exportJsonKey: { question: "$" },
2781
2909
  tags: [
2782
2910
  {
2783
2911
  key: ConfigKey.property_reasonableNumOfChars,
2912
+ exportJsonKey: [
2913
+ { "@absent": { reasonableNumOfChars: "$ancestor" } },
2914
+ { reasonableNumOfChars: "$" }
2915
+ ],
2784
2916
  description: "Property for reasonable number of characters.",
2785
2917
  format: TagFormat.number
2786
2918
  },
2787
2919
  {
2920
+ exportJsonKey: { sampleSolution: "$" },
2788
2921
  key: ConfigKey.tag_sampleSolution,
2789
- description: "Sample solution for the question."
2922
+ description: "Sample solution for the question.",
2923
+ format: TagFormat.plainText
2790
2924
  },
2791
2925
  {
2792
2926
  key: ConfigKey.property_sampleSolution,
@@ -2826,6 +2960,7 @@ var CARDSETS = {
2826
2960
  variants: [
2827
2961
  {
2828
2962
  jsonKey: "elements[]",
2963
+ exportJsonKey: { elements: ["$"] },
2829
2964
  tags: [
2830
2965
  {
2831
2966
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -2833,6 +2968,11 @@ var CARDSETS = {
2833
2968
  },
2834
2969
  {
2835
2970
  key: ConfigKey.property_example,
2971
+ exportJsonKey: [
2972
+ { "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
2973
+ { "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
2974
+ { isExample: true, example: "$", "@bit": { isExample: true } }
2975
+ ],
2836
2976
  description: "Example text for the element.",
2837
2977
  format: TagFormat.plainText
2838
2978
  }
@@ -2848,6 +2988,7 @@ var CARDSETS = {
2848
2988
  //
2849
2989
  [CardSetConfigKey.table]: {
2850
2990
  jsonKey: "table.data",
2991
+ exportJsonKey: { table: { data: "$" } },
2851
2992
  sides: [
2852
2993
  {
2853
2994
  name: "cell",
@@ -2863,6 +3004,7 @@ var CARDSETS = {
2863
3004
  {
2864
3005
  key: ConfigKey.tag_title,
2865
3006
  jsonKey: "^table.columns[]",
3007
+ exportJsonKey: { "@bit": { table: { columns: ["$"] } } },
2866
3008
  description: "Title of the table."
2867
3009
  },
2868
3010
  {
@@ -2903,18 +3045,34 @@ var CARDSETS = {
2903
3045
  [CardSetConfigKey.tableExtended]: {
2904
3046
  jsonKey: null,
2905
3047
  sections: {
2906
- "table-header": { jsonKey: "table.header.rows", sideJsonKey: "cells[{s}]|set(title=true)" },
2907
- "table-body": { jsonKey: "table.body.rows", isDefault: true },
2908
- "table-footer": { jsonKey: "table.footer.rows", sideJsonKey: "cells[{s}]|set(title=true)" }
3048
+ "table-header": {
3049
+ jsonKey: "table.header.rows",
3050
+ exportJsonKey: { table: { header: { rows: "$" } } },
3051
+ sideJsonKey: "cells[{s}]|set(title=true)",
3052
+ sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } }
3053
+ },
3054
+ "table-body": {
3055
+ jsonKey: "table.body.rows",
3056
+ exportJsonKey: { table: { body: { rows: "$" } } },
3057
+ isDefault: true
3058
+ },
3059
+ "table-footer": {
3060
+ jsonKey: "table.footer.rows",
3061
+ exportJsonKey: { table: { footer: { rows: "$" } } },
3062
+ sideJsonKey: "cells[{s}]|set(title=true)",
3063
+ sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } }
3064
+ }
2909
3065
  },
2910
3066
  sides: [
2911
3067
  {
2912
3068
  name: "cell",
2913
3069
  repeat: true,
2914
3070
  jsonKey: "cells[{s}]",
3071
+ exportJsonKey: { cells: { $s: "$" } },
2915
3072
  variants: [
2916
3073
  {
2917
3074
  jsonKey: "content",
3075
+ exportJsonKey: { content: "$" },
2918
3076
  tags: [
2919
3077
  {
2920
3078
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -2923,29 +3081,38 @@ var CARDSETS = {
2923
3081
  {
2924
3082
  key: ConfigKey.tag_title,
2925
3083
  jsonKey: ".",
3084
+ exportJsonKey: {
3085
+ "@bit": {
3086
+ table: { header: { rows: { cells: { cells: { $s: { content: "$" } } } } } }
3087
+ }
3088
+ },
2926
3089
  description: "Title of the table cell."
2927
3090
  },
2928
3091
  {
2929
3092
  key: ConfigKey.property_tableCellType,
2930
3093
  jsonKey: "title|bool(th)",
3094
+ exportJsonKey: [{ "@value=th": { title: true } }],
2931
3095
  description: "Table cell type (th/td).",
2932
3096
  format: TagFormat.plainText
2933
3097
  },
2934
3098
  {
2935
3099
  key: ConfigKey.property_tableRowSpan,
2936
3100
  jsonKey: "rowspan",
3101
+ exportJsonKey: { rowspan: "$" },
2937
3102
  description: "Number of rows the cell spans.",
2938
3103
  format: TagFormat.number
2939
3104
  },
2940
3105
  {
2941
3106
  key: ConfigKey.property_tableColSpan,
2942
3107
  jsonKey: "colspan",
3108
+ exportJsonKey: { colspan: "$" },
2943
3109
  description: "Number of columns the cell spans.",
2944
3110
  format: TagFormat.number
2945
3111
  },
2946
3112
  {
2947
3113
  key: ConfigKey.property_tableScope,
2948
3114
  jsonKey: "scope",
3115
+ exportJsonKey: { scope: "$" },
2949
3116
  description: "Scope attribute for header cells.",
2950
3117
  format: TagFormat.plainText
2951
3118
  },
@@ -2966,6 +3133,7 @@ var CARDSETS = {
2966
3133
  //
2967
3134
  [CardSetConfigKey.pronunciationTable]: {
2968
3135
  jsonKey: "pronunciationTable.data",
3136
+ exportJsonKey: { pronunciationTable: { data: "$" } },
2969
3137
  sides: [
2970
3138
  {
2971
3139
  name: "cell",
@@ -2973,12 +3141,14 @@ var CARDSETS = {
2973
3141
  variants: [
2974
3142
  {
2975
3143
  jsonKey: "body",
3144
+ exportJsonKey: { body: "$" },
2976
3145
  tags: [
2977
3146
  {
2978
3147
  key: ConfigKey.group_standardItemLeadInstructionHint,
2979
3148
  description: "Standard tags for lead, instruction, and hint."
2980
3149
  },
2981
3150
  {
3151
+ exportJsonKey: { title: "$" },
2982
3152
  key: ConfigKey.tag_title,
2983
3153
  description: "Title of the pronunciation table."
2984
3154
  },
@@ -2999,12 +3169,15 @@ var CARDSETS = {
2999
3169
  //
3000
3170
  [CardSetConfigKey.botActionResponses]: {
3001
3171
  jsonKey: "responses",
3172
+ exportJsonKey: { responses: "$" },
3002
3173
  sides: [
3003
3174
  {
3004
3175
  name: "response",
3005
3176
  variants: [
3006
3177
  {
3007
3178
  jsonKey: "feedback",
3179
+ exportJsonKey: { feedback: "$" },
3180
+ format: TextFormat.plainText,
3008
3181
  tags: [
3009
3182
  {
3010
3183
  key: ConfigKey.property_reaction,
@@ -3012,16 +3185,53 @@ var CARDSETS = {
3012
3185
  format: TagFormat.plainText
3013
3186
  },
3014
3187
  {
3015
- key: ConfigKey.group_standardItemLead,
3016
- description: "Item, lead, page number, and margin number for the bot action response."
3188
+ key: ConfigKey.tag_item,
3189
+ jsonKey: "item",
3190
+ exportJsonKey: { item: "$" },
3191
+ format: TagFormat.plainText,
3192
+ description: "The item for the bit",
3193
+ chain: [
3194
+ {
3195
+ key: ConfigKey.tag_item,
3196
+ jsonKey: "lead",
3197
+ exportJsonKey: { lead: "$" },
3198
+ description: "The lead for the bit",
3199
+ maxCount: 1,
3200
+ chain: [
3201
+ {
3202
+ key: ConfigKey.tag_item,
3203
+ jsonKey: "pageNumber",
3204
+ exportJsonKey: { pageNumber: "$" },
3205
+ description: "The page number for the bit",
3206
+ maxCount: 1,
3207
+ chain: [
3208
+ {
3209
+ key: ConfigKey.tag_item,
3210
+ jsonKey: "marginNumber",
3211
+ exportJsonKey: { marginNumber: "$" },
3212
+ description: "The margin number for the bit",
3213
+ maxCount: 1
3214
+ }
3215
+ ]
3216
+ }
3217
+ ]
3218
+ }
3219
+ ]
3017
3220
  },
3018
3221
  {
3019
3222
  key: ConfigKey.tag_instruction,
3020
3223
  description: "The response label for the bot action.",
3021
- jsonKey: "response"
3224
+ jsonKey: "response",
3225
+ exportJsonKey: { response: "$" },
3226
+ format: TagFormat.plainText
3022
3227
  },
3023
3228
  {
3024
3229
  key: ConfigKey.property_example,
3230
+ exportJsonKey: [
3231
+ { "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
3232
+ { "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
3233
+ { isExample: true, example: "$", "@bit": { isExample: true } }
3234
+ ],
3025
3235
  description: "Example text for the bot action response.",
3026
3236
  format: TagFormat.plainText
3027
3237
  }
@@ -3036,12 +3246,14 @@ var CARDSETS = {
3036
3246
  //
3037
3247
  [CardSetConfigKey.clozeList]: {
3038
3248
  jsonKey: "listItems",
3249
+ exportJsonKey: { listItems: "$" },
3039
3250
  sides: [
3040
3251
  {
3041
3252
  name: "content",
3042
3253
  variants: [
3043
3254
  {
3044
3255
  jsonKey: "body",
3256
+ exportJsonKey: { body: "$" },
3045
3257
  tags: [
3046
3258
  {
3047
3259
  key: ConfigKey.group_standardTags,
@@ -3062,18 +3274,21 @@ var CARDSETS = {
3062
3274
  //
3063
3275
  [CardSetConfigKey.exampleBitList]: {
3064
3276
  jsonKey: "listItems",
3277
+ exportJsonKey: { listItems: "$" },
3065
3278
  sides: [
3066
3279
  {
3067
3280
  name: "item",
3068
3281
  variants: [
3069
3282
  {
3070
3283
  jsonKey: "body",
3284
+ exportJsonKey: { body: "$" },
3071
3285
  tags: [
3072
3286
  {
3073
3287
  key: ConfigKey.group_standardTags,
3074
3288
  description: "Standard tags for example bits."
3075
3289
  },
3076
3290
  {
3291
+ exportJsonKey: { title: "$" },
3077
3292
  key: ConfigKey.tag_title,
3078
3293
  description: "Title of the example bit."
3079
3294
  }
@@ -3088,14 +3303,17 @@ var CARDSETS = {
3088
3303
  //
3089
3304
  [CardSetConfigKey.ingredients]: {
3090
3305
  jsonKey: "ingredients",
3306
+ exportJsonKey: { ingredients: "$" },
3091
3307
  sides: [
3092
3308
  {
3093
3309
  name: "ingredient",
3094
3310
  variants: [
3095
3311
  {
3096
3312
  jsonKey: "ingredient",
3313
+ exportJsonKey: { ingredient: "$" },
3097
3314
  tags: [
3098
3315
  {
3316
+ exportJsonKey: { title: "$" },
3099
3317
  key: ConfigKey.tag_title,
3100
3318
  description: "Title of the ingredient."
3101
3319
  },
@@ -3103,6 +3321,7 @@ var CARDSETS = {
3103
3321
  key: ConfigKey.tag_true,
3104
3322
  description: "Checked state for the ingredient.",
3105
3323
  jsonKey: "|set(checked=true)",
3324
+ exportJsonKey: { checked: true, $: "$" },
3106
3325
  maxCount: 1
3107
3326
  // nullable: true,
3108
3327
  },
@@ -3110,6 +3329,7 @@ var CARDSETS = {
3110
3329
  key: ConfigKey.tag_false,
3111
3330
  description: "Unchecked state for the ingredient.",
3112
3331
  jsonKey: "|set(checked=false)",
3332
+ exportJsonKey: { checked: false, $: "$" },
3113
3333
  maxCount: 1
3114
3334
  // nullable: true,
3115
3335
  },
@@ -3121,9 +3341,11 @@ var CARDSETS = {
3121
3341
  key: ConfigKey.tag_instruction,
3122
3342
  description: "The quantity of the ingredient.",
3123
3343
  jsonKey: "quantity",
3344
+ exportJsonKey: { quantity: "$" },
3124
3345
  format: TagFormat.number
3125
3346
  },
3126
3347
  {
3348
+ exportJsonKey: { hint: "$" },
3127
3349
  key: ConfigKey.tag_hint,
3128
3350
  description: "The hint for the ingredient."
3129
3351
  },
@@ -3159,6 +3381,7 @@ var CARDSETS = {
3159
3381
  //
3160
3382
  [CardSetConfigKey.bookReferenceList]: {
3161
3383
  jsonKey: "bookReferences",
3384
+ exportJsonKey: { bookReferences: "$" },
3162
3385
  sides: [
3163
3386
  {
3164
3387
  name: "reference",
@@ -3218,6 +3441,11 @@ var GROUPS = {
3218
3441
  format: TagFormat.plainText,
3219
3442
  maxCount: Count.infinity
3220
3443
  },
3444
+ {
3445
+ key: ConfigKey.property_gUri,
3446
+ description: "Global URI for the bit",
3447
+ format: TagFormat.plainText
3448
+ },
3221
3449
  {
3222
3450
  key: ConfigKey.property_customerId,
3223
3451
  description: "The customer-specific identifier for the bit",
@@ -3401,12 +3629,14 @@ var GROUPS = {
3401
3629
  {
3402
3630
  key: ConfigKey.property_groupTag,
3403
3631
  jsonKey: "groupTag.name",
3632
+ exportJsonKey: { groupTag: { name: "$" } },
3404
3633
  description: "The group tag(s) for the bit",
3405
3634
  format: TagFormat.plainText,
3406
3635
  maxCount: Count.infinity,
3407
3636
  chain: [
3408
3637
  {
3409
3638
  key: ConfigKey.property_tag,
3639
+ exportJsonKey: { tags: ["$"] },
3410
3640
  description: "The tag(s) for the group",
3411
3641
  format: TagFormat.plainText,
3412
3642
  maxCount: Count.infinity
@@ -3437,6 +3667,12 @@ var GROUPS = {
3437
3667
  format: TagFormat.plainText,
3438
3668
  maxCount: Count.infinity
3439
3669
  },
3670
+ {
3671
+ key: ConfigKey.property_sourceBB,
3672
+ description: "The source bounding box(es) for the bit (x, y, x1, y1)",
3673
+ format: TagFormat.coordinates,
3674
+ maxCount: Count.infinity
3675
+ },
3440
3676
  {
3441
3677
  key: ConfigKey.property_levelCEFRp,
3442
3678
  description: "The CEFRp level for the bit",
@@ -3474,6 +3710,7 @@ var GROUPS = {
3474
3710
  maxCount: Count.infinity
3475
3711
  },
3476
3712
  {
3713
+ exportJsonKey: { anchor: "$" },
3477
3714
  key: ConfigKey.tag_anchor,
3478
3715
  name: "Anchor",
3479
3716
  format: TagFormat.plainText,
@@ -3511,23 +3748,27 @@ var GROUPS = {
3511
3748
  {
3512
3749
  key: ConfigKey.tag_item,
3513
3750
  jsonKey: "item",
3751
+ exportJsonKey: { item: "$" },
3514
3752
  description: "The item for the bit",
3515
3753
  chain: [
3516
3754
  {
3517
3755
  key: ConfigKey.tag_item,
3518
3756
  jsonKey: "lead",
3757
+ exportJsonKey: { lead: "$" },
3519
3758
  description: "The lead for the bit",
3520
3759
  maxCount: 1,
3521
3760
  chain: [
3522
3761
  {
3523
3762
  key: ConfigKey.tag_item,
3524
3763
  jsonKey: "pageNumber",
3764
+ exportJsonKey: { pageNumber: "$" },
3525
3765
  description: "The page number for the bit",
3526
3766
  maxCount: 1,
3527
3767
  chain: [
3528
3768
  {
3529
3769
  key: ConfigKey.tag_item,
3530
3770
  jsonKey: "marginNumber",
3771
+ exportJsonKey: { marginNumber: "$" },
3531
3772
  description: "The margin number for the bit",
3532
3773
  maxCount: 1
3533
3774
  }
@@ -3548,11 +3789,13 @@ var GROUPS = {
3548
3789
  description: "Item, lead, page number, and margin number tags"
3549
3790
  },
3550
3791
  {
3792
+ exportJsonKey: { instruction: "$" },
3551
3793
  key: ConfigKey.tag_instruction,
3552
3794
  name: "Instruction",
3553
3795
  description: "The instruction for the bit"
3554
3796
  },
3555
3797
  {
3798
+ exportJsonKey: { hint: "$" },
3556
3799
  key: ConfigKey.tag_hint,
3557
3800
  name: "Hint",
3558
3801
  description: "The hint for the bit"
@@ -3572,9 +3815,17 @@ var GROUPS = {
3572
3815
  description: "Item, lead, page number, margin number, instruction and hint tags"
3573
3816
  },
3574
3817
  {
3818
+ // Bit-level example tag: bare/synthesized records the marker only;
3819
+ // valued [@example:text] emits `isExample: true` and `example` as
3820
+ // PM-rendered rich text (bitmark+ format).
3575
3821
  key: ConfigKey.property_example,
3822
+ exportJsonKey: [
3823
+ { "@keyonly": { isExample: true } },
3824
+ { "@absent": { isExample: true } },
3825
+ { isExample: true, example: "$" }
3826
+ ],
3576
3827
  description: "The example(s) for the bit",
3577
- format: TagFormat.plainText
3828
+ format: TagFormat.bitmarkText
3578
3829
  }
3579
3830
  ]
3580
3831
  },
@@ -3585,6 +3836,7 @@ var GROUPS = {
3585
3836
  {
3586
3837
  key: ConfigKey.property_imageSource,
3587
3838
  jsonKey: "imageSource.url",
3839
+ exportJsonKey: { imageSource: { url: "$" } },
3588
3840
  description: "The source of an image",
3589
3841
  format: TagFormat.plainText,
3590
3842
  chain: [
@@ -3619,6 +3871,7 @@ var GROUPS = {
3619
3871
  {
3620
3872
  key: ConfigKey.property_technicalTerm,
3621
3873
  jsonKey: "technicalTerm.technicalTerm",
3874
+ exportJsonKey: { technicalTerm: { technicalTerm: "$" } },
3622
3875
  description: "The technical term",
3623
3876
  format: TagFormat.plainText,
3624
3877
  chain: [
@@ -3638,6 +3891,7 @@ var GROUPS = {
3638
3891
  {
3639
3892
  key: ConfigKey.property_person,
3640
3893
  jsonKey: "partner.name",
3894
+ exportJsonKey: { partner: { name: "$" } },
3641
3895
  description: "A person",
3642
3896
  format: TagFormat.plainText,
3643
3897
  chain: [
@@ -3649,6 +3903,7 @@ var GROUPS = {
3649
3903
  {
3650
3904
  key: ConfigKey.group_resourceImage,
3651
3905
  jsonKey: "avatarImage|resource(type=image, key=image)",
3906
+ exportJsonKey: { avatarImage: { type: "image", image: { src: "$" } } },
3652
3907
  description: "The image of the person"
3653
3908
  }
3654
3909
  ]
@@ -3657,6 +3912,7 @@ var GROUPS = {
3657
3912
  // Deprecated (parter renamed to person)
3658
3913
  key: ConfigKey.property_partner,
3659
3914
  jsonKey: "partner.name",
3915
+ exportJsonKey: { partner: { name: "$" } },
3660
3916
  description: "A partner",
3661
3917
  format: TagFormat.plainText,
3662
3918
  chain: [
@@ -3668,6 +3924,7 @@ var GROUPS = {
3668
3924
  {
3669
3925
  key: ConfigKey.group_resourceImage,
3670
3926
  jsonKey: "avatarImage|resource(type=image, key=image)",
3927
+ exportJsonKey: { avatarImage: { type: "image", image: { src: "$" } } },
3671
3928
  description: "The image of the partner"
3672
3929
  }
3673
3930
  ]
@@ -3679,15 +3936,19 @@ var GROUPS = {
3679
3936
  description: "Gap chain",
3680
3937
  tags: [
3681
3938
  {
3939
+ exportJsonKey: { solutions: [["$"]] },
3682
3940
  key: ConfigKey.tag_gap,
3683
3941
  description: "The value of a gap in the content",
3684
3942
  maxCount: Count.infinity,
3943
+ format: TagFormat.plainText,
3685
3944
  chain: [
3686
3945
  {
3687
3946
  key: ConfigKey.tag_gap,
3688
3947
  jsonKey: "solutions[]",
3948
+ exportJsonKey: { solutions: ["$"] },
3689
3949
  description: "Alternative values for the gaps in the content",
3690
- maxCount: Count.infinity
3950
+ maxCount: Count.infinity,
3951
+ format: TagFormat.plainText
3691
3952
  },
3692
3953
  {
3693
3954
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -3696,12 +3957,33 @@ var GROUPS = {
3696
3957
  {
3697
3958
  key: ConfigKey.property_example,
3698
3959
  jsonKey: "example",
3960
+ exportJsonKey: [
3961
+ {
3962
+ "@keyonly": {
3963
+ isExample: true,
3964
+ example: "$parent.solutions[0]",
3965
+ "@bit": { isExample: true }
3966
+ }
3967
+ },
3968
+ {
3969
+ "@absent": {
3970
+ isExample: true,
3971
+ example: "$parent.solutions[0]",
3972
+ "@bit": { isExample: true }
3973
+ }
3974
+ },
3975
+ { isExample: true, example: "$", "@bit": { isExample: true } }
3976
+ ],
3699
3977
  description: "An example for the gap",
3700
- format: TagFormat.plainText
3978
+ format: TagFormat.bitmarkText
3701
3979
  },
3702
3980
  {
3703
3981
  key: ConfigKey.property_isCaseSensitive,
3704
3982
  jsonKey: "isCaseSensitive",
3983
+ exportJsonKey: [
3984
+ { "@absent": { isCaseSensitive: "$ancestor" } },
3985
+ { isCaseSensitive: "$" }
3986
+ ],
3705
3987
  description: "If true, the gap text is case sensitive",
3706
3988
  format: TagFormat.boolean,
3707
3989
  defaultValue: "true"
@@ -3715,21 +3997,27 @@ var GROUPS = {
3715
3997
  description: "True/False chain",
3716
3998
  tags: [
3717
3999
  {
4000
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: true }] },
3718
4001
  key: ConfigKey.tag_true,
3719
4002
  description: "True value for a true/false statement/question",
3720
4003
  maxCount: Count.infinity,
4004
+ format: TagFormat.plainText,
3721
4005
  chain: [
3722
4006
  {
3723
4007
  key: ConfigKey.tag_true,
3724
4008
  jsonKey: "choices[]|set(isCorrect=true)",
4009
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: true }] },
3725
4010
  description: "True values for a true/false statement/question",
3726
- maxCount: Count.infinity
4011
+ maxCount: Count.infinity,
4012
+ format: TagFormat.plainText
3727
4013
  },
3728
4014
  {
3729
4015
  key: ConfigKey.tag_false,
3730
4016
  jsonKey: "choices[]|set(isCorrect=false)",
4017
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
3731
4018
  description: "False values for a true/false statement/question",
3732
- maxCount: Count.infinity
4019
+ maxCount: Count.infinity,
4020
+ format: TagFormat.plainText
3733
4021
  },
3734
4022
  {
3735
4023
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -3738,27 +4026,50 @@ var GROUPS = {
3738
4026
  {
3739
4027
  key: ConfigKey.property_example,
3740
4028
  jsonKey: "example",
4029
+ exportJsonKey: [
4030
+ {
4031
+ "@keyonly": {
4032
+ isExample: true,
4033
+ example: "$parent.isCorrect",
4034
+ "@bit": { isExample: true }
4035
+ }
4036
+ },
4037
+ {
4038
+ "@absent": {
4039
+ isExample: true,
4040
+ example: "$parent.isCorrect",
4041
+ "@bit": { isExample: true }
4042
+ }
4043
+ },
4044
+ { isExample: true, example: "$", "@bit": { isExample: true } }
4045
+ ],
3741
4046
  description: "An example for the true/false statement/question",
3742
- format: TagFormat.plainText
4047
+ format: TagFormat.bitmarkText
3743
4048
  }
3744
4049
  ]
3745
4050
  },
3746
4051
  {
4052
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
3747
4053
  key: ConfigKey.tag_false,
3748
4054
  description: "False value for a true/false statement/question",
3749
4055
  maxCount: Count.infinity,
4056
+ format: TagFormat.plainText,
3750
4057
  chain: [
3751
4058
  {
3752
4059
  key: ConfigKey.tag_true,
3753
4060
  jsonKey: "choices[]|set(isCorrect=true)",
4061
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: true }] },
3754
4062
  description: "True values for a true/false statement/question",
3755
- maxCount: Count.infinity
4063
+ maxCount: Count.infinity,
4064
+ format: TagFormat.plainText
3756
4065
  },
3757
4066
  {
3758
4067
  key: ConfigKey.tag_false,
3759
4068
  jsonKey: "choices[]|set(isCorrect=false)",
4069
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
3760
4070
  description: "False values for a true/false statement/question",
3761
- maxCount: Count.infinity
4071
+ maxCount: Count.infinity,
4072
+ format: TagFormat.plainText
3762
4073
  },
3763
4074
  {
3764
4075
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -3767,8 +4078,25 @@ var GROUPS = {
3767
4078
  {
3768
4079
  key: ConfigKey.property_example,
3769
4080
  jsonKey: "example",
4081
+ exportJsonKey: [
4082
+ {
4083
+ "@keyonly": {
4084
+ isExample: true,
4085
+ example: "$parent.isCorrect",
4086
+ "@bit": { isExample: true }
4087
+ }
4088
+ },
4089
+ {
4090
+ "@absent": {
4091
+ isExample: true,
4092
+ example: "$parent.isCorrect",
4093
+ "@bit": { isExample: true }
4094
+ }
4095
+ },
4096
+ { isExample: true, example: "$", "@bit": { isExample: true } }
4097
+ ],
3770
4098
  description: "An example for the true/false statement/question",
3771
- format: TagFormat.plainText
4099
+ format: TagFormat.bitmarkText
3772
4100
  }
3773
4101
  ]
3774
4102
  }
@@ -3781,6 +4109,7 @@ var GROUPS = {
3781
4109
  {
3782
4110
  key: ConfigKey.property_mark,
3783
4111
  jsonKey: "marks.mark",
4112
+ exportJsonKey: { marks: { mark: ["$"] } },
3784
4113
  description: "The mark configuration",
3785
4114
  format: TagFormat.plainText,
3786
4115
  maxCount: Count.infinity,
@@ -3804,9 +4133,11 @@ var GROUPS = {
3804
4133
  description: "Mark chain",
3805
4134
  tags: [
3806
4135
  {
4136
+ exportJsonKey: { solution: ["$"] },
3807
4137
  key: ConfigKey.tag_mark,
3808
4138
  description: "The marked content",
3809
4139
  maxCount: Count.infinity,
4140
+ format: TagFormat.plainText,
3810
4141
  chain: [
3811
4142
  {
3812
4143
  key: ConfigKey.property_mark,
@@ -3817,8 +4148,13 @@ var GROUPS = {
3817
4148
  {
3818
4149
  key: ConfigKey.property_example,
3819
4150
  jsonKey: "example",
4151
+ exportJsonKey: [
4152
+ { "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
4153
+ { "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
4154
+ { isExample: true, example: "$", "@bit": { isExample: true } }
4155
+ ],
3820
4156
  description: "An example for the marked content",
3821
- format: TagFormat.plainText
4157
+ format: TagFormat.bitmarkText
3822
4158
  }
3823
4159
  ]
3824
4160
  }
@@ -3907,7 +4243,8 @@ var GROUPS = {
3907
4243
  name: "Title",
3908
4244
  description: "The title of the book",
3909
4245
  maxCount: 2,
3910
- jsonKey: "title|multi(count=2, key=subtitle)"
4246
+ jsonKey: "title|multi(count=2, key=subtitle)",
4247
+ exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
3911
4248
  },
3912
4249
  {
3913
4250
  key: ConfigKey.property_subtype,
@@ -3923,6 +4260,7 @@ var GROUPS = {
3923
4260
  {
3924
4261
  key: ConfigKey.resource_coverImage,
3925
4262
  jsonKey: "coverImage|resource(type=image, key=image)",
4263
+ exportJsonKey: { coverImage: { type: "image", image: { src: "$" } } },
3926
4264
  description: "The cover image of the book",
3927
4265
  chain: [
3928
4266
  {
@@ -3940,6 +4278,7 @@ var GROUPS = {
3940
4278
  {
3941
4279
  key: ConfigKey.resource_backgroundImage,
3942
4280
  jsonKey: "backgroundImage|resource(type=image, key=image)",
4281
+ exportJsonKey: { backgroundImage: { type: "image", image: { src: "$" } } },
3943
4282
  description: "The background image of the book",
3944
4283
  chain: [
3945
4284
  {
@@ -4099,10 +4438,21 @@ var GROUPS = {
4099
4438
  format: TagFormat.plainText,
4100
4439
  chain: [
4101
4440
  {
4441
+ exportJsonKey: { reference: "$" },
4102
4442
  key: ConfigKey.tag_reference,
4103
4443
  format: TagFormat.plainText,
4104
- description: "The reference(s) for the book(s) in the learning path",
4105
- maxCount: 2
4444
+ description: "The reference for the book(s) in the learning path",
4445
+ maxCount: 1,
4446
+ chain: [
4447
+ {
4448
+ key: ConfigKey.tag_reference,
4449
+ jsonKey: "referenceEnd",
4450
+ exportJsonKey: { referenceEnd: "$" },
4451
+ format: TagFormat.plainText,
4452
+ description: "The referenceEnd for the book(s) in the learning path",
4453
+ maxCount: 1
4454
+ }
4455
+ ]
4106
4456
  }
4107
4457
  ]
4108
4458
  }
@@ -4242,6 +4592,8 @@ var GROUPS = {
4242
4592
  tags: [
4243
4593
  {
4244
4594
  key: ConfigKey.resource_imagePlaceholder,
4595
+ jsonKey: "imagePlaceholder|resource(type=image, key=image)",
4596
+ exportJsonKey: { imagePlaceholder: { type: "image", image: { src: "$" } } },
4245
4597
  description: "Placeholder image for the resource",
4246
4598
  chain: [
4247
4599
  {
@@ -4426,6 +4778,7 @@ var GROUPS = {
4426
4778
  {
4427
4779
  key: ConfigKey.property_posterImage,
4428
4780
  jsonKey: "posterImage.src",
4781
+ exportJsonKey: { posterImage: { src: "$" } },
4429
4782
  description: "The poster image for the video",
4430
4783
  format: TagFormat.plainText,
4431
4784
  chain: [
@@ -4482,6 +4835,7 @@ var GROUPS = {
4482
4835
  tags: [
4483
4836
  {
4484
4837
  key: ConfigKey.resource_image,
4838
+ exportJsonKey: { resource: { type: "image", image: { src: "$" } } },
4485
4839
  description: "The image resource",
4486
4840
  chain: [
4487
4841
  {
@@ -4546,6 +4900,7 @@ var GROUPS = {
4546
4900
  tags: [
4547
4901
  {
4548
4902
  key: ConfigKey.resource_imageLink,
4903
+ exportJsonKey: { resource: { type: "image-link", imageLink: { url: "$" } } },
4549
4904
  description: "The link to the image resource",
4550
4905
  chain: [
4551
4906
  {
@@ -4562,6 +4917,7 @@ var GROUPS = {
4562
4917
  tags: [
4563
4918
  {
4564
4919
  key: ConfigKey.resource_audio,
4920
+ exportJsonKey: { resource: { type: "audio", audio: { src: "$" } } },
4565
4921
  description: "The audio resource",
4566
4922
  chain: [
4567
4923
  {
@@ -4578,6 +4934,7 @@ var GROUPS = {
4578
4934
  tags: [
4579
4935
  {
4580
4936
  key: ConfigKey.resource_audioEmbed,
4937
+ exportJsonKey: { resource: { type: "audio-embed", audioEmbed: { src: "$" } } },
4581
4938
  description: "The embedded audio resource",
4582
4939
  chain: [
4583
4940
  {
@@ -4594,6 +4951,7 @@ var GROUPS = {
4594
4951
  tags: [
4595
4952
  {
4596
4953
  key: ConfigKey.resource_audioLink,
4954
+ exportJsonKey: { resource: { type: "audio-link", audioLink: { url: "$" } } },
4597
4955
  description: "The link to the audio resource",
4598
4956
  chain: [
4599
4957
  {
@@ -4610,6 +4968,7 @@ var GROUPS = {
4610
4968
  tags: [
4611
4969
  {
4612
4970
  key: ConfigKey.resource_video,
4971
+ exportJsonKey: { resource: { type: "video", video: { src: "$" } } },
4613
4972
  description: "The video resource",
4614
4973
  chain: [
4615
4974
  {
@@ -4626,6 +4985,7 @@ var GROUPS = {
4626
4985
  tags: [
4627
4986
  {
4628
4987
  key: ConfigKey.resource_videoEmbed,
4988
+ exportJsonKey: { resource: { type: "video-embed", videoEmbed: { url: "$" } } },
4629
4989
  description: "The embedded video resource",
4630
4990
  chain: [
4631
4991
  {
@@ -4642,6 +5002,7 @@ var GROUPS = {
4642
5002
  tags: [
4643
5003
  {
4644
5004
  key: ConfigKey.resource_videoLink,
5005
+ exportJsonKey: { resource: { type: "video-link", videoLink: { url: "$" } } },
4645
5006
  description: "The link to the video resource",
4646
5007
  chain: [
4647
5008
  {
@@ -4658,6 +5019,9 @@ var GROUPS = {
4658
5019
  tags: [
4659
5020
  {
4660
5021
  key: ConfigKey.resource_stillImageFilmEmbed,
5022
+ exportJsonKey: {
5023
+ resource: { type: "still-image-film-embed", stillImageFilmEmbed: { url: "$" } }
5024
+ },
4661
5025
  description: "The embedded still image film resource",
4662
5026
  chain: [
4663
5027
  {
@@ -4674,6 +5038,9 @@ var GROUPS = {
4674
5038
  tags: [
4675
5039
  {
4676
5040
  key: ConfigKey.resource_stillImageFilmLink,
5041
+ exportJsonKey: {
5042
+ resource: { type: "still-image-film-link", stillImageFilmLink: { url: "$" } }
5043
+ },
4677
5044
  description: "The link to the still image film resource",
4678
5045
  chain: [
4679
5046
  {
@@ -4738,6 +5105,7 @@ var GROUPS = {
4738
5105
  tags: [
4739
5106
  {
4740
5107
  key: ConfigKey.resource_document,
5108
+ exportJsonKey: { resource: { type: "document", document: { url: "$" } } },
4741
5109
  description: "The document resource",
4742
5110
  chain: [
4743
5111
  {
@@ -4754,6 +5122,7 @@ var GROUPS = {
4754
5122
  tags: [
4755
5123
  {
4756
5124
  key: ConfigKey.resource_documentEmbed,
5125
+ exportJsonKey: { resource: { type: "document-embed", documentEmbed: { url: "$" } } },
4757
5126
  description: "The embedded document resource",
4758
5127
  chain: [
4759
5128
  {
@@ -4770,6 +5139,7 @@ var GROUPS = {
4770
5139
  tags: [
4771
5140
  {
4772
5141
  key: ConfigKey.resource_documentLink,
5142
+ exportJsonKey: { resource: { type: "document-link", documentLink: { url: "$" } } },
4773
5143
  description: "The link to the document resource",
4774
5144
  chain: [
4775
5145
  {
@@ -4786,6 +5156,7 @@ var GROUPS = {
4786
5156
  tags: [
4787
5157
  {
4788
5158
  key: ConfigKey.resource_documentDownload,
5159
+ exportJsonKey: { resource: { type: "document-download", documentDownload: { url: "$" } } },
4789
5160
  description: "The downloadable document resource",
4790
5161
  chain: [
4791
5162
  {
@@ -4802,6 +5173,7 @@ var GROUPS = {
4802
5173
  tags: [
4803
5174
  {
4804
5175
  key: ConfigKey.resource_appLink,
5176
+ exportJsonKey: { resource: { type: "app-link", appLink: { url: "$" } } },
4805
5177
  description: "The link to the app resource",
4806
5178
  chain: [
4807
5179
  {
@@ -4818,6 +5190,7 @@ var GROUPS = {
4818
5190
  tags: [
4819
5191
  {
4820
5192
  key: ConfigKey.resource_websiteLink,
5193
+ exportJsonKey: { resource: { type: "website-link", websiteLink: { url: "$" } } },
4821
5194
  description: "The link to the website resource",
4822
5195
  chain: [
4823
5196
  {
@@ -4876,6 +5249,7 @@ var GROUPS = {
4876
5249
  {
4877
5250
  key: ConfigKey.resource_previewImage,
4878
5251
  jsonKey: "previewImage|resource(type=image, key=image)",
5252
+ exportJsonKey: { previewImage: { type: "image", image: { src: "$" } } },
4879
5253
  description: "The preview image resource",
4880
5254
  chain: [
4881
5255
  {
@@ -4893,6 +5267,7 @@ var GROUPS = {
4893
5267
  {
4894
5268
  key: ConfigKey.resource_previewVideo,
4895
5269
  jsonKey: "previewVideo|resource(type=video, key=video)",
5270
+ exportJsonKey: { previewVideo: { type: "video", video: { src: "$" } } },
4896
5271
  description: "The preview video resource",
4897
5272
  chain: [
4898
5273
  {
@@ -4957,20 +5332,48 @@ var ConfigHydrator = class {
4957
5332
  _side.name,
4958
5333
  _side.repeat ?? false,
4959
5334
  variantsOfSide,
4960
- _side.jsonKey
5335
+ _side.jsonKey,
5336
+ _side.exportJsonKey,
5337
+ Object.prototype.hasOwnProperty.call(_side, "exportJsonKey")
4961
5338
  );
4962
5339
  sides.push(sideConfig);
4963
5340
  }
4964
5341
  const cardSetConfig = new CardSetConfig(
4965
5342
  _cardSet,
4966
5343
  _cardSetConfig.jsonKey,
4967
- _cardSetConfig.sections,
5344
+ _cardSetConfig.exportJsonKey,
5345
+ Object.prototype.hasOwnProperty.call(_cardSetConfig, "exportJsonKey"),
5346
+ this.hydrateCardSections(_cardSetConfig.sections),
4968
5347
  sides
4969
5348
  );
4970
5349
  return cardSetConfig;
4971
5350
  }
5351
+ hydrateCardSections(sections) {
5352
+ if (!sections) return void 0;
5353
+ const out = {};
5354
+ for (const [k, v] of Object.entries(sections)) {
5355
+ out[k] = {
5356
+ jsonKey: v.jsonKey,
5357
+ exportJsonKey: v.exportJsonKey,
5358
+ hasExportJsonKey: Object.prototype.hasOwnProperty.call(v, "exportJsonKey"),
5359
+ isDefault: v.isDefault,
5360
+ sideJsonKey: v.sideJsonKey,
5361
+ sideExportJsonKey: v.sideExportJsonKey,
5362
+ hasSideExportJsonKey: Object.prototype.hasOwnProperty.call(v, "sideExportJsonKey")
5363
+ };
5364
+ }
5365
+ return out;
5366
+ }
4972
5367
  hydrateTagConfig(_tag) {
4973
- const { key: _configKey, maxCount, minCount, chain: _chain, deprecated } = _tag;
5368
+ const {
5369
+ key: _configKey,
5370
+ maxCount,
5371
+ minCount,
5372
+ chain: _chain,
5373
+ deprecated,
5374
+ jsonKey,
5375
+ exportJsonKey
5376
+ } = _tag;
4974
5377
  const configKey = (0, import_superenum15.Enum)(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
4975
5378
  if (!configKey) throw new Error(`No tag key found for config key '${configKey}'`);
4976
5379
  const tag = (0, import_superenum15.Enum)(Tag).fromValue(configKey);
@@ -4985,6 +5388,9 @@ var ConfigHydrator = class {
4985
5388
  maxCount: maxCount ?? MAX_COUNT_DEFAULT,
4986
5389
  minCount: minCount ?? MIN_COUNT_DEFAULT,
4987
5390
  chain,
5391
+ jsonKey,
5392
+ exportJsonKey,
5393
+ hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
4988
5394
  deprecated
4989
5395
  });
4990
5396
  return {
@@ -5003,7 +5409,8 @@ var ConfigHydrator = class {
5003
5409
  format,
5004
5410
  values,
5005
5411
  defaultValue,
5006
- jsonKey
5412
+ jsonKey,
5413
+ exportJsonKey
5007
5414
  } = _tag;
5008
5415
  const configKey = (0, import_superenum15.Enum)(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
5009
5416
  if (!configKey) throw new Error(`No property key found for config key '${configKey}'`);
@@ -5019,6 +5426,8 @@ var ConfigHydrator = class {
5019
5426
  minCount: minCount ?? MIN_COUNT_DEFAULT,
5020
5427
  chain,
5021
5428
  jsonKey,
5429
+ exportJsonKey,
5430
+ hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
5022
5431
  format,
5023
5432
  values,
5024
5433
  defaultValue,
@@ -5031,7 +5440,15 @@ var ConfigHydrator = class {
5031
5440
  };
5032
5441
  }
5033
5442
  hydrateResourceTagConfig(_tag) {
5034
- const { key: _configKey, maxCount, minCount, chain: _chain, deprecated, jsonKey } = _tag;
5443
+ const {
5444
+ key: _configKey,
5445
+ maxCount,
5446
+ minCount,
5447
+ chain: _chain,
5448
+ deprecated,
5449
+ jsonKey,
5450
+ exportJsonKey
5451
+ } = _tag;
5035
5452
  const configKey = (0, import_superenum15.Enum)(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
5036
5453
  if (!configKey) throw new Error(`No resource key found for config key '${configKey}'`);
5037
5454
  const tag = _configKey.substring(1);
@@ -5046,6 +5463,8 @@ var ConfigHydrator = class {
5046
5463
  minCount: minCount ?? MIN_COUNT_DEFAULT,
5047
5464
  chain,
5048
5465
  jsonKey,
5466
+ exportJsonKey,
5467
+ hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
5049
5468
  deprecated
5050
5469
  });
5051
5470
  return {
@@ -5077,14 +5496,25 @@ var ConfigHydrator = class {
5077
5496
  };
5078
5497
  }
5079
5498
  hydrateCardVariantConfig(_variant) {
5080
- const { tags: _tags, bodyAllowed, bodyRequired, repeatCount, jsonKey } = _variant;
5499
+ const {
5500
+ tags: _tags,
5501
+ bodyAllowed,
5502
+ bodyRequired,
5503
+ repeatCount,
5504
+ jsonKey,
5505
+ exportJsonKey,
5506
+ format
5507
+ } = _variant;
5081
5508
  const tags2 = this.hydrateTagsConfig(_tags);
5082
5509
  const cardSetConfig = new CardVariantConfig(
5083
5510
  tags2.tags,
5084
5511
  bodyAllowed,
5085
5512
  bodyRequired,
5086
5513
  repeatCount,
5087
- jsonKey
5514
+ jsonKey,
5515
+ exportJsonKey,
5516
+ Object.prototype.hasOwnProperty.call(_variant, "exportJsonKey"),
5517
+ format
5088
5518
  );
5089
5519
  return cardSetConfig;
5090
5520
  }
@@ -5122,6 +5552,7 @@ var BITS = {
5122
5552
  description: "Common tags for quiz bits"
5123
5553
  },
5124
5554
  {
5555
+ exportJsonKey: { title: "$" },
5125
5556
  key: ConfigKey.tag_title,
5126
5557
  description: "The title of the flashcard quiz"
5127
5558
  },
@@ -5130,6 +5561,20 @@ var BITS = {
5130
5561
  description: "The flashcard set to use for the app flashcards",
5131
5562
  format: TagFormat.plainText,
5132
5563
  maxCount: Count.infinity
5564
+ },
5565
+ {
5566
+ // Override inherited @example from group_standardTags: string root
5567
+ // example. Bare/synthesized emits `example: "true"` (a text literal
5568
+ // that field-coerces to a paragraph "true" in bitmark+ contexts);
5569
+ // valued [@example:text] emits the user's text via `$`.
5570
+ key: ConfigKey.property_example,
5571
+ exportJsonKey: [
5572
+ { "@keyonly": { isExample: true, example: "true" } },
5573
+ { "@absent": { isExample: true, example: "true" } },
5574
+ { isExample: true, example: "$" }
5575
+ ],
5576
+ description: "The example text for the bit",
5577
+ format: TagFormat.plainText
5133
5578
  }
5134
5579
  ],
5135
5580
  rootExampleType: ExampleType.string
@@ -5211,6 +5656,7 @@ var BITS = {
5211
5656
  description: "Article bit, used for articles / paragraphs",
5212
5657
  tags: [
5213
5658
  {
5659
+ exportJsonKey: { title: "$" },
5214
5660
  key: ConfigKey.tag_title,
5215
5661
  description: "The title of the article"
5216
5662
  }
@@ -5318,7 +5764,8 @@ var BITS = {
5318
5764
  key: ConfigKey.tag_title,
5319
5765
  description: "Title and subtitle of the catalog item",
5320
5766
  maxCount: 2,
5321
- jsonKey: "title|multi(count=2, key=subtitle)"
5767
+ jsonKey: "title|multi(count=2, key=subtitle)",
5768
+ exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
5322
5769
  },
5323
5770
  {
5324
5771
  key: ConfigKey.property_coverImage,
@@ -5328,6 +5775,7 @@ var BITS = {
5328
5775
  {
5329
5776
  key: ConfigKey.resource_coverImage,
5330
5777
  jsonKey: "coverImage|resource(type=image, key=image)",
5778
+ exportJsonKey: { coverImage: { type: "image", image: { src: "$" } } },
5331
5779
  description: "Cover image of the catalog item",
5332
5780
  chain: [
5333
5781
  {
@@ -5455,6 +5903,17 @@ var BITS = {
5455
5903
  key: ConfigKey.group_previewVideos,
5456
5904
  description: "Array of preview videos for the catalog item",
5457
5905
  maxCount: Count.infinity
5906
+ },
5907
+ {
5908
+ // Override inherited @example from group_standardTags: string root example.
5909
+ key: ConfigKey.property_example,
5910
+ exportJsonKey: [
5911
+ { "@keyonly": { isExample: true, example: "true" } },
5912
+ { "@absent": { isExample: true, example: "true" } },
5913
+ { isExample: true, example: "$" }
5914
+ ],
5915
+ description: "The example text for the bit",
5916
+ format: TagFormat.plainText
5458
5917
  }
5459
5918
  ],
5460
5919
  rootExampleType: ExampleType.string
@@ -5468,7 +5927,8 @@ var BITS = {
5468
5927
  key: ConfigKey.tag_title,
5469
5928
  description: "Title and subtitle of the catalog item",
5470
5929
  maxCount: 2,
5471
- jsonKey: "title|multi(count=2, key=subtitle)"
5930
+ jsonKey: "title|multi(count=2, key=subtitle)",
5931
+ exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
5472
5932
  },
5473
5933
  {
5474
5934
  key: ConfigKey.property_coverImage,
@@ -5478,6 +5938,7 @@ var BITS = {
5478
5938
  {
5479
5939
  key: ConfigKey.resource_coverImage,
5480
5940
  jsonKey: "coverImage|resource(type=image, key=image)",
5941
+ exportJsonKey: { coverImage: { type: "image", image: { src: "$" } } },
5481
5942
  description: "Cover image of the catalog item",
5482
5943
  chain: [
5483
5944
  {
@@ -5605,6 +6066,17 @@ var BITS = {
5605
6066
  key: ConfigKey.group_previewVideos,
5606
6067
  description: "Array of preview videos for the catalog item",
5607
6068
  maxCount: Count.infinity
6069
+ },
6070
+ {
6071
+ // Override inherited @example from group_standardTags: string root example.
6072
+ key: ConfigKey.property_example,
6073
+ exportJsonKey: [
6074
+ { "@keyonly": { isExample: true, example: "true" } },
6075
+ { "@absent": { isExample: true, example: "true" } },
6076
+ { isExample: true, example: "$" }
6077
+ ],
6078
+ description: "The example text for the bit",
6079
+ format: TagFormat.plainText
5608
6080
  }
5609
6081
  ],
5610
6082
  rootExampleType: ExampleType.string
@@ -5618,7 +6090,8 @@ var BITS = {
5618
6090
  key: ConfigKey.tag_title,
5619
6091
  description: "Title and subtitle of the catalog item",
5620
6092
  maxCount: 2,
5621
- jsonKey: "title|multi(count=2, key=subtitle)"
6093
+ jsonKey: "title|multi(count=2, key=subtitle)",
6094
+ exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
5622
6095
  },
5623
6096
  {
5624
6097
  key: ConfigKey.property_coverImage,
@@ -5744,6 +6217,17 @@ var BITS = {
5744
6217
  key: ConfigKey.group_previewVideos,
5745
6218
  description: "Array of preview videos for the catalog item",
5746
6219
  maxCount: Count.infinity
6220
+ },
6221
+ {
6222
+ // Override inherited @example from group_standardTags: string root example.
6223
+ key: ConfigKey.property_example,
6224
+ exportJsonKey: [
6225
+ { "@keyonly": { isExample: true, example: "true" } },
6226
+ { "@absent": { isExample: true, example: "true" } },
6227
+ { isExample: true, example: "$" }
6228
+ ],
6229
+ description: "The example text for the bit",
6230
+ format: TagFormat.plainText
5747
6231
  }
5748
6232
  ],
5749
6233
  rootExampleType: ExampleType.string
@@ -5945,11 +6429,13 @@ var BITS = {
5945
6429
  description: "Bit alias, used to create an alias for a bit",
5946
6430
  tags: [
5947
6431
  {
6432
+ exportJsonKey: { reference: "$" },
5948
6433
  key: ConfigKey.tag_reference,
5949
6434
  format: TagFormat.plainText,
5950
6435
  description: "The reference to the bit that this alias points to"
5951
6436
  },
5952
6437
  {
6438
+ exportJsonKey: { anchor: "$" },
5953
6439
  key: ConfigKey.tag_anchor,
5954
6440
  format: TagFormat.plainText,
5955
6441
  description: "The anchor for the bit alias, used for linking"
@@ -6151,7 +6637,8 @@ var BITS = {
6151
6637
  description: "The title of the book cover",
6152
6638
  maxCount: 2,
6153
6639
  // title & subtitle
6154
- jsonKey: "title|multi(count=2, key=subtitle)"
6640
+ jsonKey: "title|multi(count=2, key=subtitle)",
6641
+ exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
6155
6642
  },
6156
6643
  {
6157
6644
  key: ConfigKey.property_coverColor,
@@ -6295,6 +6782,7 @@ var BITS = {
6295
6782
  description: "Chapter bit, used to define chapters in books or articles",
6296
6783
  tags: [
6297
6784
  {
6785
+ exportJsonKey: { anchor: "$" },
6298
6786
  key: ConfigKey.tag_anchor,
6299
6787
  format: TagFormat.plainText,
6300
6788
  description: "The anchor for the chapter, used for linking"
@@ -6302,7 +6790,8 @@ var BITS = {
6302
6790
  {
6303
6791
  key: ConfigKey.tag_title,
6304
6792
  description: "The title of the chapter",
6305
- jsonKey: "title|setMulti(level)"
6793
+ jsonKey: "title|setMulti(level)",
6794
+ exportJsonKey: { title: "$", level: "$level" }
6306
6795
  },
6307
6796
  {
6308
6797
  key: ConfigKey.property_toc,
@@ -6355,6 +6844,7 @@ var BITS = {
6355
6844
  },
6356
6845
  {
6357
6846
  key: ConfigKey.property_isCaseSensitive,
6847
+ exportJsonKey: {},
6358
6848
  description: "If the cloze answers are case sensitive",
6359
6849
  format: TagFormat.boolean,
6360
6850
  defaultValue: "true"
@@ -6452,6 +6942,11 @@ var BITS = {
6452
6942
  description: "Formula bit, used for mathematical formulas in articles or documents",
6453
6943
  textFormatDefault: TextFormat.latex
6454
6944
  },
6945
+ [BitType.formulaImage]: {
6946
+ since: "5.23.0",
6947
+ baseBitType: BitType.formula,
6948
+ description: "Formula image bit, used for mathematical formulas rendered as images"
6949
+ },
6455
6950
  [BitType.smartStandardFormula]: {
6456
6951
  since: "3.11.0",
6457
6952
  baseBitType: BitType.formula,
@@ -6804,6 +7299,7 @@ var BITS = {
6804
7299
  {
6805
7300
  key: ConfigKey.property_servings,
6806
7301
  jsonKey: "servings.servings",
7302
+ exportJsonKey: { servings: { servings: "$" } },
6807
7303
  description: "The number of servings for the ingredients",
6808
7304
  format: TagFormat.number,
6809
7305
  chain: [
@@ -6829,6 +7325,7 @@ var BITS = {
6829
7325
  format: TagFormat.boolean
6830
7326
  },
6831
7327
  {
7328
+ exportJsonKey: { hint: "$" },
6832
7329
  key: ConfigKey.tag_hint,
6833
7330
  description: "Hint for the ingredient, used to provide additional information",
6834
7331
  format: TagFormat.plainText
@@ -7006,6 +7503,17 @@ var BITS = {
7006
7503
  description: "Reference for the essay, used to link to external resources",
7007
7504
  format: TagFormat.plainText,
7008
7505
  maxCount: Count.infinity
7506
+ },
7507
+ {
7508
+ // Override inherited @example from group_standardTags: string root example.
7509
+ key: ConfigKey.property_example,
7510
+ exportJsonKey: [
7511
+ { "@keyonly": { isExample: true, example: "true" } },
7512
+ { "@absent": { isExample: true, example: "true" } },
7513
+ { isExample: true, example: "$" }
7514
+ ],
7515
+ description: "The example text for the essay bit",
7516
+ format: TagFormat.plainText
7009
7517
  }
7010
7518
  ],
7011
7519
  rootExampleType: ExampleType.string
@@ -7026,8 +7534,20 @@ var BITS = {
7026
7534
  description: "Example bit, used to provide examples in articles or books",
7027
7535
  tags: [
7028
7536
  {
7537
+ exportJsonKey: { title: "$" },
7029
7538
  key: ConfigKey.tag_title,
7030
7539
  description: "The title of the example"
7540
+ },
7541
+ {
7542
+ // Override inherited @example from group_standardTags: string root example.
7543
+ key: ConfigKey.property_example,
7544
+ exportJsonKey: [
7545
+ { "@keyonly": { isExample: true, example: "true" } },
7546
+ { "@absent": { isExample: true, example: "true" } },
7547
+ { isExample: true, example: "$" }
7548
+ ],
7549
+ description: "The example text for the example bit",
7550
+ format: TagFormat.plainText
7031
7551
  }
7032
7552
  ],
7033
7553
  rootExampleType: ExampleType.string
@@ -7893,6 +8413,7 @@ var BITS = {
7893
8413
  // Image resource
7894
8414
  key: ConfigKey.group_resourceImage,
7895
8415
  description: "Resource image tags for logo grave images, used to attach images",
8416
+ exportJsonKey: { images: "$" },
7896
8417
  minCount: 1,
7897
8418
  maxCount: Count.infinity
7898
8419
  }
@@ -8056,15 +8577,27 @@ var BITS = {
8056
8577
  format: TagFormat.plainText,
8057
8578
  chain: [
8058
8579
  {
8580
+ exportJsonKey: { reference: "$" },
8059
8581
  key: ConfigKey.tag_reference,
8060
8582
  format: TagFormat.plainText,
8061
8583
  description: "Reference tag for the book, used to link to the book in the system",
8062
- maxCount: 2
8584
+ maxCount: 1,
8585
+ chain: [
8586
+ {
8587
+ key: ConfigKey.tag_reference,
8588
+ jsonKey: "referenceEnd",
8589
+ exportJsonKey: { referenceEnd: "$" },
8590
+ format: TagFormat.plainText,
8591
+ description: "End reference tag for the book, used to specify a range",
8592
+ maxCount: 1
8593
+ }
8594
+ ]
8063
8595
  }
8064
8596
  ]
8065
8597
  },
8066
8598
  {
8067
8599
  /* Allow incorrectly chained reference tag */
8600
+ exportJsonKey: { reference: "$" },
8068
8601
  key: ConfigKey.tag_reference,
8069
8602
  format: TagFormat.plainText,
8070
8603
  description: "Reference tag for the book, used to link to the book in the system"
@@ -8111,18 +8644,41 @@ var BITS = {
8111
8644
  format: TagFormat.plainText,
8112
8645
  chain: [
8113
8646
  {
8647
+ exportJsonKey: { reference: "$" },
8114
8648
  key: ConfigKey.tag_reference,
8115
8649
  format: TagFormat.plainText,
8116
8650
  description: "Reference tag for the book, used to link to the book in the system",
8117
- maxCount: 2
8651
+ maxCount: 1,
8652
+ chain: [
8653
+ {
8654
+ key: ConfigKey.tag_reference,
8655
+ jsonKey: "referenceEnd",
8656
+ exportJsonKey: { referenceEnd: "$" },
8657
+ format: TagFormat.plainText,
8658
+ description: "End reference tag for the book, used to specify a range",
8659
+ maxCount: 1
8660
+ }
8661
+ ]
8118
8662
  }
8119
8663
  ]
8120
8664
  },
8121
8665
  {
8122
8666
  /* Allow incorrectly chained reference tag */
8667
+ exportJsonKey: { reference: "$" },
8123
8668
  key: ConfigKey.tag_reference,
8124
8669
  format: TagFormat.plainText,
8125
- description: "Reference tag for the book, used to link to the book in the system"
8670
+ description: "Reference tag for the book, used to link to the book in the system",
8671
+ maxCount: 1,
8672
+ chain: [
8673
+ {
8674
+ key: ConfigKey.tag_reference,
8675
+ jsonKey: "referenceEnd",
8676
+ exportJsonKey: { referenceEnd: "$" },
8677
+ format: TagFormat.plainText,
8678
+ description: "End reference tag for the book, used to specify a range",
8679
+ maxCount: 1
8680
+ }
8681
+ ]
8126
8682
  },
8127
8683
  {
8128
8684
  key: ConfigKey.property_buttonCaption,
@@ -8151,10 +8707,21 @@ var BITS = {
8151
8707
  maxCount: Count.infinity,
8152
8708
  chain: [
8153
8709
  {
8710
+ exportJsonKey: { reference: "$" },
8154
8711
  key: ConfigKey.tag_reference,
8155
8712
  format: TagFormat.plainText,
8156
8713
  description: "Reference tag for the book, used to link to the book in the system",
8157
- maxCount: 2
8714
+ maxCount: 1,
8715
+ chain: [
8716
+ {
8717
+ key: ConfigKey.tag_reference,
8718
+ jsonKey: "referenceEnd",
8719
+ exportJsonKey: { referenceEnd: "$" },
8720
+ format: TagFormat.plainText,
8721
+ description: "End reference tag for the book, used to specify a range",
8722
+ maxCount: 1
8723
+ }
8724
+ ]
8158
8725
  }
8159
8726
  ]
8160
8727
  },
@@ -8321,6 +8888,7 @@ var BITS = {
8321
8888
  tags: [
8322
8889
  {
8323
8890
  key: ConfigKey.resource_backgroundWallpaper,
8891
+ exportJsonKey: { backgroundWallpaper: { type: "image", image: { src: "$" } } },
8324
8892
  description: "Background wallpaper for the image, used to set a background for the image",
8325
8893
  chain: [
8326
8894
  {
@@ -8503,6 +9071,7 @@ var BITS = {
8503
9071
  },
8504
9072
  {
8505
9073
  key: ConfigKey.resource_backgroundWallpaper,
9074
+ exportJsonKey: { backgroundWallpaper: { type: "image", image: { src: "$" } } },
8506
9075
  description: "Background wallpaper for the image, used to set a background for the image",
8507
9076
  chain: [
8508
9077
  {
@@ -8655,6 +9224,7 @@ var BITS = {
8655
9224
  // Image resource
8656
9225
  key: ConfigKey.group_resourceImage,
8657
9226
  description: "Resource image tags for logo grave images, used to attach images",
9227
+ exportJsonKey: { logos: "$" },
8658
9228
  minCount: 1,
8659
9229
  maxCount: Count.infinity
8660
9230
  }
@@ -8672,6 +9242,7 @@ var BITS = {
8672
9242
  description: "Internal link bit, used to create links to other bits in articles or books",
8673
9243
  tags: [
8674
9244
  {
9245
+ exportJsonKey: { reference: "$" },
8675
9246
  key: ConfigKey.tag_reference,
8676
9247
  format: TagFormat.plainText,
8677
9248
  description: "Reference tag for the internal link, used to link to the target bit"
@@ -8690,6 +9261,7 @@ var BITS = {
8690
9261
  },
8691
9262
  {
8692
9263
  key: ConfigKey.property_reasonableNumOfChars,
9264
+ exportJsonKey: {},
8693
9265
  description: "Reasonable number of characters for the interview, used to limit input size",
8694
9266
  format: TagFormat.number
8695
9267
  }
@@ -9065,6 +9637,7 @@ var BITS = {
9065
9637
  },
9066
9638
  {
9067
9639
  key: ConfigKey.property_isCaseSensitive,
9640
+ exportJsonKey: {},
9068
9641
  description: "Case sensitivity for matching pairs, used to define if matches are case-sensitive",
9069
9642
  format: TagFormat.boolean,
9070
9643
  defaultValue: "true"
@@ -9117,6 +9690,7 @@ var BITS = {
9117
9690
  tags: [
9118
9691
  {
9119
9692
  key: ConfigKey.property_reasonableNumOfChars,
9693
+ exportJsonKey: {},
9120
9694
  description: "Reasonable number of characters for feedback, used to limit input size",
9121
9695
  format: TagFormat.number
9122
9696
  }
@@ -9258,6 +9832,7 @@ var BITS = {
9258
9832
  description: "Page bit, used to create pages in articles or books",
9259
9833
  tags: [
9260
9834
  {
9835
+ exportJsonKey: { title: "$" },
9261
9836
  key: ConfigKey.tag_title,
9262
9837
  description: "Title of the page, used to display the page title"
9263
9838
  },
@@ -9617,6 +10192,7 @@ var BITS = {
9617
10192
  {
9618
10193
  key: ConfigKey.resource_platformBackgroundImage,
9619
10194
  jsonKey: "platformBackgroundImage|resource(type=image, key=image)",
10195
+ exportJsonKey: { platformBackgroundImage: { type: "image", image: { src: "$" } } },
9620
10196
  description: "The platform section chat background image",
9621
10197
  chain: [
9622
10198
  {
@@ -9710,6 +10286,7 @@ var BITS = {
9710
10286
  description: "Review note bit, used to create review notes in articles or books",
9711
10287
  tags: [
9712
10288
  {
10289
+ exportJsonKey: { title: "$" },
9713
10290
  key: ConfigKey.tag_title,
9714
10291
  description: "Title of the review note, used to display the note title"
9715
10292
  },
@@ -9728,6 +10305,17 @@ var BITS = {
9728
10305
  key: ConfigKey.property_resolvedBy,
9729
10306
  description: "Resolved by for the review note, used to define who resolved the note",
9730
10307
  format: TagFormat.plainText
10308
+ },
10309
+ {
10310
+ // Override inherited @example from group_standardTags: string root example.
10311
+ key: ConfigKey.property_example,
10312
+ exportJsonKey: [
10313
+ { "@keyonly": { isExample: true, example: "true" } },
10314
+ { "@absent": { isExample: true, example: "true" } },
10315
+ { isExample: true, example: "$" }
10316
+ ],
10317
+ description: "The example text for the review note bit",
10318
+ format: TagFormat.plainText
9731
10319
  }
9732
10320
  ],
9733
10321
  rootExampleType: ExampleType.string
@@ -9780,11 +10368,13 @@ var BITS = {
9780
10368
  tags: [
9781
10369
  // Not sure if these are actually valid here, but include them as they are in the test bit.
9782
10370
  {
10371
+ exportJsonKey: { anchor: "$" },
9783
10372
  key: ConfigKey.tag_anchor,
9784
10373
  format: TagFormat.plainText,
9785
10374
  description: "Anchor for the sample solution, used to link to the solution"
9786
10375
  },
9787
10376
  {
10377
+ exportJsonKey: { reference: "$" },
9788
10378
  key: ConfigKey.tag_reference,
9789
10379
  format: TagFormat.plainText,
9790
10380
  description: "Reference for the sample solution, used to link to the source of the solution"
@@ -9800,6 +10390,19 @@ var BITS = {
9800
10390
  {
9801
10391
  key: ConfigKey.group_quizCommon,
9802
10392
  description: "Common quiz tags for sequences"
10393
+ },
10394
+ {
10395
+ // Override inherited @example from group_standardTags: this bit has
10396
+ // a boolean root example (rootExampleType: boolean), so bit-level
10397
+ // [@example] writes `example: true` in addition to `isExample: true`.
10398
+ key: ConfigKey.property_example,
10399
+ exportJsonKey: [
10400
+ { "@keyonly": { isExample: true, example: true } },
10401
+ { "@absent": { isExample: true, example: true } },
10402
+ { isExample: true, example: "$" }
10403
+ ],
10404
+ description: "The example flag for the bit (boolean)",
10405
+ format: TagFormat.plainText
9803
10406
  }
9804
10407
  ],
9805
10408
  cardSet: CardSetConfigKey.elements,
@@ -9907,6 +10510,7 @@ var BITS = {
9907
10510
  {
9908
10511
  key: ConfigKey.property_ratingLevelStart,
9909
10512
  jsonKey: "ratingLevelStart.level",
10513
+ exportJsonKey: { ratingLevelStart: { level: "$" } },
9910
10514
  description: "Start level for the rating survey, used to define the lowest rating",
9911
10515
  format: TagFormat.number,
9912
10516
  chain: [
@@ -9920,6 +10524,7 @@ var BITS = {
9920
10524
  {
9921
10525
  key: ConfigKey.property_ratingLevelEnd,
9922
10526
  jsonKey: "ratingLevelEnd.level",
10527
+ exportJsonKey: { ratingLevelEnd: { level: "$" } },
9923
10528
  description: "End level for the rating survey, used to define the highest rating",
9924
10529
  format: TagFormat.number,
9925
10530
  chain: [
@@ -10072,6 +10677,7 @@ var BITS = {
10072
10677
  },
10073
10678
  {
10074
10679
  key: ConfigKey.resource_backgroundWallpaper,
10680
+ exportJsonKey: { backgroundWallpaper: { type: "image", image: { src: "$" } } },
10075
10681
  description: "Background wallpaper for the image, used to set a background for the image",
10076
10682
  chain: [
10077
10683
  {
@@ -10455,12 +11061,34 @@ var BITS = {
10455
11061
  format: TagFormat.plainText
10456
11062
  },
10457
11063
  {
11064
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: true }] },
10458
11065
  key: ConfigKey.tag_true,
10459
- description: "Tag for the true option in the true/false question"
11066
+ description: "Tag for the true option in the true/false question",
11067
+ format: TagFormat.plainText
10460
11068
  },
10461
11069
  {
11070
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
10462
11071
  key: ConfigKey.tag_false,
10463
- description: "Tag for the false option in the true/false question"
11072
+ description: "Tag for the false option in the true/false question",
11073
+ format: TagFormat.plainText
11074
+ },
11075
+ {
11076
+ // Override inherited @example from group_standardTags: boolean root
11077
+ // example. Note: the legacy reference parser ties the bare-form
11078
+ // example value to `statement.isCorrect`, but the statement is not
11079
+ // yet emitted when this tag fires at bit-header. The pattern below
11080
+ // emits a literal `true` for bare/synthesized and `$` for valued —
11081
+ // sufficient for `[+...]` (correct) statements which dominate the
11082
+ // fixtures; `[-...]` (incorrect) bits with bare `[@example]` would
11083
+ // need either a runtime extension or an explicit `[@example:false]`.
11084
+ key: ConfigKey.property_example,
11085
+ exportJsonKey: [
11086
+ { "@keyonly": { isExample: true, example: true } },
11087
+ { "@absent": { isExample: true, example: true } },
11088
+ { isExample: true, example: "$" }
11089
+ ],
11090
+ description: "The example flag for the bit (boolean)",
11091
+ format: TagFormat.plainText
10464
11092
  }
10465
11093
  ],
10466
11094
  rootExampleType: ExampleType.boolean
@@ -11043,6 +11671,8 @@ var Config = class {
11043
11671
  maxCount: 1,
11044
11672
  chain: tag.chain,
11045
11673
  jsonKey: tag.jsonKey,
11674
+ exportJsonKey: tag.exportJsonKey,
11675
+ hasExportJsonKey: tag.hasExportJsonKey,
11046
11676
  deprecated: tag.deprecated
11047
11677
  });
11048
11678
  finalResourceTags[k] = newTag;
@@ -11147,7 +11777,7 @@ var instance2 = new Config();
11147
11777
  // src/generated/package_info.ts
11148
11778
  var PACKAGE_INFO = {
11149
11779
  "name": "@gmb/bitmark-parser-generator",
11150
- "version": "5.22.0",
11780
+ "version": "5.23.0",
11151
11781
  "author": "Get More Brain Ltd",
11152
11782
  "license": "ISC",
11153
11783
  "description": "A bitmark parser and generator using Peggy.js"
@@ -11741,6 +12371,8 @@ var NodeType = {
11741
12371
  gmbExternalShopItems: "gmbExternalShopItems",
11742
12372
  groupTag: "groupTag",
11743
12373
  groupTagValue: "groupTagValue",
12374
+ gUri: "gUri",
12375
+ gUriValue: "gUriValue",
11744
12376
  handInAcceptFileType: "handInAcceptFileType",
11745
12377
  handInAcceptFileTypeValue: "handInAcceptFileTypeValue",
11746
12378
  handInInstruction: "handInInstruction",
@@ -12083,6 +12715,8 @@ var NodeType = {
12083
12715
  solution: "solution",
12084
12716
  solutions: "solutions",
12085
12717
  solutionsValue: "solutionsValue",
12718
+ sourceBB: "sourceBB",
12719
+ sourceBBValue: "sourceBBValue",
12086
12720
  sourceDocument: "sourceDocument",
12087
12721
  sourceDocumentValue: "sourceDocumentValue",
12088
12722
  sourceRL: "sourceRL",
@@ -24963,6 +25597,7 @@ var Builder = class extends BaseBuilder {
24963
25597
  isCommented: data.isCommented,
24964
25598
  // Properties
24965
25599
  id: this.toAstProperty(bitType, ConfigKey.property_id, data.id, options),
25600
+ gUri: this.toAstProperty(bitType, ConfigKey.property_gUri, data.gUri, options),
24966
25601
  internalComment: this.toAstProperty(
24967
25602
  bitType,
24968
25603
  ConfigKey.property_internalComment,
@@ -25174,6 +25809,7 @@ var Builder = class extends BaseBuilder {
25174
25809
  data.extractorInternal,
25175
25810
  options
25176
25811
  ),
25812
+ sourceBB: this.normaliseSourceBB(data.sourceBB),
25177
25813
  levelCEFRp: this.toAstProperty(
25178
25814
  bitType,
25179
25815
  ConfigKey.property_levelCEFRp,
@@ -26194,6 +26830,19 @@ var Builder = class extends BaseBuilder {
26194
26830
  nodes = Object.values(combinedNodes);
26195
26831
  return nodes.length > 0 ? nodes : void 0;
26196
26832
  }
26833
+ /**
26834
+ * Normalise a sourceBB input into the AST shape (always number[][]).
26835
+ * Accepts a single 4-number tuple or an array of tuples; returns undefined when empty.
26836
+ */
26837
+ normaliseSourceBB(data) {
26838
+ if (data == null) return void 0;
26839
+ if (!Array.isArray(data) || data.length === 0) return void 0;
26840
+ const isNested = data.some(Array.isArray);
26841
+ const tuples = (isNested ? data : [data]).filter(
26842
+ (t) => Array.isArray(t) && t.length === 4 && t.every((n) => typeof n === "number")
26843
+ );
26844
+ return tuples.length > 0 ? tuples : void 0;
26845
+ }
26197
26846
  /**
26198
26847
  * Build groupTag node
26199
26848
  *
@@ -28513,6 +29162,23 @@ var BitmarkGenerator = class extends AstWalkerGenerator {
28513
29162
  format: TagFormat.plainText
28514
29163
  });
28515
29164
  }
29165
+ // bitmarkAst -> bits -> bitsValue -> sourceBB
29166
+ enter_sourceBB(node, route) {
29167
+ const parent = this.getParentNode(route);
29168
+ if (parent?.key !== NodeType.bitsValue) return false;
29169
+ const tuples = node.value;
29170
+ if (!Array.isArray(tuples) || tuples.length === 0) return false;
29171
+ this.writeProperty(
29172
+ "sourceBB",
29173
+ tuples.map((t) => t.join(", ")),
29174
+ route,
29175
+ {
29176
+ format: TagFormat.plainText,
29177
+ array: true
29178
+ }
29179
+ );
29180
+ return false;
29181
+ }
28516
29182
  // bitmarkAst -> bits -> bitsValue -> questions -> questionsValue -> additionalSolutions -> additionalSolutionsValue
28517
29183
  leaf_additionalSolutionsValue(node, route) {
28518
29184
  const parent = this.getParentNode(route, 2);
@@ -30636,6 +31302,16 @@ var JsonGenerator = class extends AstWalkerGenerator {
30636
31302
  enter_ratingLevelEnd(node, route) {
30637
31303
  return this.standardHandler(node, route, NodeType.bitsValue, { array: false });
30638
31304
  }
31305
+ // bitmarkAst -> bits -> bitsValue -> sourceBB
31306
+ enter_sourceBB(node, route) {
31307
+ const tuples = node.value;
31308
+ const parent = this.getParentNode(route);
31309
+ if (parent?.key !== NodeType.bitsValue) return false;
31310
+ if (tuples && tuples.length > 0) {
31311
+ this.bitJson.sourceBB = tuples.length === 1 ? tuples[0] : tuples;
31312
+ }
31313
+ return false;
31314
+ }
30639
31315
  // bitmarkAst -> bits -> bitsValue -> productId
30640
31316
  enter_productId(node, route) {
30641
31317
  const productIds = node.value;
@@ -35332,6 +36008,17 @@ function propertyContentProcessor(context, contentDepth, tagsConfig, content, ta
35332
36008
  format: TextFormat.bitmarkText,
35333
36009
  location: TextLocation.tag
35334
36010
  });
36011
+ case TagFormat.coordinates:
36012
+ const coordRaw = instance3.unbreakscape(v2, {
36013
+ format: TextFormat.plainText,
36014
+ location: TextLocation.tag
36015
+ });
36016
+ if (coordRaw == null) return void 0;
36017
+ const coordParts = coordRaw.split(",").map((p) => instance6.asNumber(p.trim()));
36018
+ if (coordParts.length !== 4 || coordParts.some((n) => n == null)) {
36019
+ return void 0;
36020
+ }
36021
+ return coordParts;
35335
36022
  }
35336
36023
  }
35337
36024
  return instance3.unbreakscape(v2, {
@@ -35368,6 +36055,8 @@ function propertyContentProcessor(context, contentDepth, tagsConfig, content, ta
35368
36055
  minCount: 1,
35369
36056
  chain: void 0,
35370
36057
  jsonKey: void 0,
36058
+ exportJsonKey: void 0,
36059
+ hasExportJsonKey: false,
35371
36060
  format: TagFormat.bitmarkText,
35372
36061
  values: void 0,
35373
36062
  defaultValue: void 0,
@@ -35378,19 +36067,18 @@ function propertyContentProcessor(context, contentDepth, tagsConfig, content, ta
35378
36067
  }
35379
36068
 
35380
36069
  // src/parser/bitmark/peg/contentProcessors/ReferenceTagContentProcessor.ts
35381
- function referenceTagContentProcessor(_context, _contentDepth, _tagsConfig, content, target, isReferenceEnd) {
35382
- const { value } = content;
36070
+ function referenceTagContentProcessor(context, _contentDepth, tagsConfig, content, target) {
36071
+ const { value, chain } = content;
35383
36072
  const trimmedStringValue = stringUtils.trimmedString(value);
35384
- if (isReferenceEnd) {
35385
- target.referenceEnd = instance3.unbreakscape(trimmedStringValue, {
35386
- format: TextFormat.bitmarkText,
35387
- location: TextLocation.tag
35388
- });
35389
- } else {
35390
- target.reference = instance3.unbreakscape(trimmedStringValue, {
35391
- format: TextFormat.bitmarkText,
35392
- location: TextLocation.tag
35393
- });
36073
+ target.reference = instance3.unbreakscape(trimmedStringValue, {
36074
+ format: TextFormat.bitmarkText,
36075
+ location: TextLocation.tag
36076
+ });
36077
+ if (Array.isArray(chain) && chain.length > 0) {
36078
+ const sub = context.bitContentProcessor(ContentDepth.Chain, tagsConfig, chain);
36079
+ if (sub.reference != null) {
36080
+ target.referenceEnd = sub.reference;
36081
+ }
35394
36082
  }
35395
36083
  }
35396
36084
 
@@ -36080,7 +36768,6 @@ var BitmarkPegParserProcessor = class {
36080
36768
  result.markConfig = [];
36081
36769
  result.extraProperties = {};
36082
36770
  result.internalComments = [];
36083
- let seenReference = false;
36084
36771
  let inFooter = false;
36085
36772
  const bodyParts = [];
36086
36773
  let bodyTextPart = instance3.EMPTY_STRING;
@@ -36116,15 +36803,7 @@ var BitmarkPegParserProcessor = class {
36116
36803
  defaultTagContentProcessor(this.context, contentDepth, tagsConfig, content, result);
36117
36804
  break;
36118
36805
  case TypeKey.Reference:
36119
- referenceTagContentProcessor(
36120
- this.context,
36121
- contentDepth,
36122
- tagsConfig,
36123
- content,
36124
- result,
36125
- seenReference
36126
- );
36127
- seenReference = true;
36806
+ referenceTagContentProcessor(this.context, contentDepth, tagsConfig, content, result);
36128
36807
  break;
36129
36808
  case TypeKey.Title:
36130
36809
  titleTagContentProcessor(this.context, contentDepth, tagsConfig, content, result);
@@ -40434,52 +41113,28 @@ var ConfigBuilder = class {
40434
41113
  BitTagConfigKeyType.group,
40435
41114
  BitTagConfigKeyType.unknown
40436
41115
  ];
41116
+ const exportJsonKeyErrors = [];
40437
41117
  const resolveGroupReferences = (groupKey) => {
40438
41118
  if (squashedGroups.has(groupKey)) {
40439
41119
  const replacements = squashedGroups.get(groupKey);
40440
- return replacements.flatMap((r) => resolveGroupReferences(r));
41120
+ return replacements.flatMap(
41121
+ (r) => squashedGroups.has(r.key) ? resolveGroupReferences(r.key) : [r]
41122
+ );
40441
41123
  }
40442
- return [groupKey];
41124
+ return [{ key: groupKey }];
40443
41125
  };
40444
- const keyToJsonKey = (key, tagNameChain) => {
40445
- let jsonKey = key;
40446
- if (key === "%") {
40447
- jsonKey = "item";
40448
- } else if (key === "!") {
40449
- jsonKey = "instruction";
40450
- } else if (key === "?") {
40451
- jsonKey = "hint";
40452
- } else if (key === "#") {
40453
- jsonKey = "title";
40454
- } else if (key === "##") {
40455
- jsonKey = "subTitle";
40456
- } else if (key === "\u25BC") {
40457
- jsonKey = "anchor";
40458
- } else if (key === "\u25BA") {
40459
- jsonKey = "reference";
40460
- } else if (key === "$") {
40461
- jsonKey = "sampleSolution";
40462
- } else if (key === "+") {
40463
- jsonKey = "choices[]|set(isCorrect=true)";
40464
- } else if (key === "-") {
40465
- jsonKey = "choices[]|set(isCorrect=false)";
40466
- } else if (key === "_") {
40467
- jsonKey = "solutions[]";
40468
- } else if (key === "=") {
40469
- jsonKey = "solution";
40470
- } else if (key.startsWith("@")) {
40471
- jsonKey = key.substring(1);
40472
- } else if (key.startsWith("&")) {
40473
- jsonKey = key.substring(1);
40474
- }
40475
- const thisChain = [...tagNameChain, jsonKey];
40476
- jsonKey = thisChain.join(".");
40477
- return jsonKey;
41126
+ const bareKeyForProperty = (key) => {
41127
+ if (key.startsWith("@") || key.startsWith("&")) return key.substring(1);
41128
+ return void 0;
40478
41129
  };
40479
- const processTagEntries = (tag, tagNameChain) => {
41130
+ const legacyIsTrivialDefault = (tag) => {
41131
+ const bare = bareKeyForProperty(tag.key);
41132
+ if (bare == null) return false;
41133
+ return tag.jsonKey == null || tag.jsonKey === bare;
41134
+ };
41135
+ const processTagEntries = (tag, pathStack) => {
40480
41136
  const tags2 = [];
40481
41137
  let tagName = tag.key;
40482
- const jsonKey = tag.jsonKey ?? keyToJsonKey(tagName, tagNameChain);
40483
41138
  const tagType = typeFromConfigKey(tag.key);
40484
41139
  let format = "";
40485
41140
  let chain = void 0;
@@ -40512,32 +41167,57 @@ var ConfigBuilder = class {
40512
41167
  } else if (tagType === BitTagConfigKeyType.group) {
40513
41168
  let k = tag.key;
40514
41169
  if (k.startsWith("group_")) k = k.substring(6);
40515
- k = /*'_' +*/
40516
- stringUtils.camelToKebab(k);
41170
+ k = stringUtils.camelToKebab(k);
40517
41171
  const resolvedGroups = resolveGroupReferences(k);
40518
- for (const groupKey of resolvedGroups) {
41172
+ const hasOuterExport = Object.prototype.hasOwnProperty.call(tag, "exportJsonKey");
41173
+ if (!hasOuterExport && tag.jsonKey != null) {
41174
+ const headingPath = [...pathStack, `tags.${tag.key}`].join(" / ");
41175
+ exportJsonKeyErrors.push(
41176
+ `Missing exportJsonKey for non-default jsonKey at ${headingPath} (legacy: \`${tag.jsonKey}\`)`
41177
+ );
41178
+ }
41179
+ for (const ref of resolvedGroups) {
41180
+ const exportJsonKeyChosen = hasOuterExport ? tag.exportJsonKey : ref.exportJsonKey;
41181
+ const hasExportChosen = hasOuterExport || !!ref.hasExportJsonKey;
41182
+ const min = tag.minCount != null ? tag.minCount : ref.min;
41183
+ const max = tag.maxCount != null ? tag.maxCount : ref.max;
41184
+ const description = tag.description ? tag.description : ref.description;
40519
41185
  tags2.push({
40520
41186
  type: "group",
40521
- key: groupKey,
40522
- ...tag.jsonKey ? { jsonKey: tag.jsonKey } : {},
40523
- ...tag.minCount != null ? { min: tag.minCount } : {},
40524
- ...tag.maxCount != null ? { max: tag.maxCount } : {},
40525
- ...tag.description ? { description: tag.description } : {}
41187
+ key: ref.key,
41188
+ ...hasExportChosen ? { jsonKey: exportJsonKeyChosen } : {},
41189
+ ...min != null ? { min } : {},
41190
+ ...max != null ? { max } : {},
41191
+ ...description ? { description } : {}
40526
41192
  });
40527
41193
  }
40528
41194
  return tags2;
40529
41195
  }
40530
41196
  if (Array.isArray(tag.chain) && tag.chain.length > 0) {
40531
41197
  const chainTags = [];
40532
- for (const [_tagKey, chainTag] of tag.chain.entries()) {
40533
- chainTags.push(...processTagEntries(chainTag, []));
41198
+ const childPathStack = [...pathStack, `tags.${tag.key}`];
41199
+ for (const [, chainTag] of tag.chain.entries()) {
41200
+ chainTags.push(...processTagEntries(chainTag, childPathStack));
40534
41201
  }
40535
41202
  chain = chainTags;
40536
41203
  }
41204
+ const hasExport = Object.prototype.hasOwnProperty.call(tag, "exportJsonKey");
41205
+ let exportJsonKeyField;
41206
+ if (hasExport) {
41207
+ exportJsonKeyField = { jsonKey: tag.exportJsonKey };
41208
+ } else if (legacyIsTrivialDefault(tag)) {
41209
+ exportJsonKeyField = {};
41210
+ } else {
41211
+ const headingPath = [...pathStack, `tags.${tag.key}`].join(" / ");
41212
+ exportJsonKeyErrors.push(
41213
+ `Missing exportJsonKey for non-default jsonKey at ${headingPath}` + (tag.jsonKey ? ` (legacy: \`${tag.jsonKey}\`)` : ` (symbol-mapped tag \`${tag.key}\`)`)
41214
+ );
41215
+ exportJsonKeyField = {};
41216
+ }
40537
41217
  const t = {
40538
41218
  type: "tag",
40539
41219
  key: tagName,
40540
- jsonKey,
41220
+ ...exportJsonKeyField,
40541
41221
  format,
40542
41222
  default: tag.defaultValue ?? null,
40543
41223
  ...tag.nullable ? { nullable: true } : {},
@@ -40545,19 +41225,30 @@ var ConfigBuilder = class {
40545
41225
  max: tag.maxCount == null ? 1 : tag.maxCount,
40546
41226
  description: tag.description ?? "",
40547
41227
  tags: chain
40548
- // raw: {
40549
- // ...tag,
40550
- // },
40551
41228
  };
40552
41229
  tags2.push(t);
40553
41230
  return tags2;
40554
41231
  };
41232
+ const cardJsonKeyField = (container, legacyKey, exportKey, pathHeading) => {
41233
+ const c = container;
41234
+ const hasExport = Object.prototype.hasOwnProperty.call(c, exportKey);
41235
+ if (hasExport) return { jsonKey: c[exportKey] };
41236
+ const legacy = c[legacyKey];
41237
+ if (legacy == null) return {};
41238
+ exportJsonKeyErrors.push(
41239
+ `Missing exportJsonKey for non-default jsonKey at ${pathHeading} (legacy: \`${legacy}\`)`
41240
+ );
41241
+ return {};
41242
+ };
40555
41243
  const serializeCardSet = (cardSetKey) => {
41244
+ const variantBodyFormat = (variant) => variant.format ?? TextFormat.bitmarkText;
40556
41245
  const cardSetConfig = CARDSETS[cardSetKey];
40557
41246
  if (!cardSetConfig) return void 0;
40558
41247
  const normalizedKey = normalizeCardKey(cardSetKey);
40559
- const sides = cardSetConfig.sides.map((side) => {
40560
- const variants = side.variants.map((variant) => {
41248
+ const sides = cardSetConfig.sides.map((side, sideIdx) => {
41249
+ const sidePath = `cardSets.${normalizedKey} / sides.${side.name ?? `[${sideIdx}]`}`;
41250
+ const variants = side.variants.map((variant, variantIdx) => {
41251
+ const variantPath = `${sidePath} / variants.[${variantIdx}]`;
40561
41252
  const variantTags = [];
40562
41253
  const variantTagEntries = Object.entries(variant.tags ?? []).sort((a, b) => {
40563
41254
  const tagA = a[1];
@@ -40568,10 +41259,11 @@ var ConfigBuilder = class {
40568
41259
  return typeOrder;
40569
41260
  });
40570
41261
  for (const [, variantTag] of variantTagEntries) {
40571
- variantTags.push(...processTagEntries(variantTag, []));
41262
+ variantTags.push(...processTagEntries(variantTag, [variantPath]));
40572
41263
  }
40573
41264
  return {
40574
- ...variant.jsonKey !== void 0 ? { jsonKey: variant.jsonKey } : {},
41265
+ ...cardJsonKeyField(variant, "jsonKey", "exportJsonKey", variantPath),
41266
+ format: variantBodyFormat(variant),
40575
41267
  tags: variantTags,
40576
41268
  repeatCount: variant.repeatCount ?? 1,
40577
41269
  ...variant.bodyRequired ? { bodyRequired: true } : {},
@@ -40581,41 +41273,41 @@ var ConfigBuilder = class {
40581
41273
  return {
40582
41274
  name: side.name,
40583
41275
  ...side.repeat ? { repeat: side.repeat } : {},
40584
- ...side.jsonKey != null ? { jsonKey: side.jsonKey } : {},
41276
+ ...cardJsonKeyField(side, "jsonKey", "exportJsonKey", sidePath),
40585
41277
  variants
40586
41278
  };
40587
41279
  });
40588
41280
  if (cardSetConfig.sections) {
40589
41281
  const cards = Object.entries(cardSetConfig.sections).map(([sectionName, section]) => {
40590
- let cardSides = section.sideJsonKey ? sides.map((s) => ({ ...s, jsonKey: section.sideJsonKey })) : sides;
40591
- if (normalizedKey === "table-extended" && sectionName !== "table-header") {
40592
- cardSides = JSON.parse(JSON.stringify(cardSides));
40593
- for (const side of cardSides) {
40594
- for (const variant of side.variants) {
40595
- for (const tag of variant.tags) {
40596
- if (tag.type === "tag" && tag.key === "#" && tag.jsonKey === ".") {
40597
- tag.jsonKey = "^table.header.rows.cells[{s}].content";
40598
- }
40599
- }
40600
- }
40601
- }
41282
+ const sectionPath = `cardSets.${normalizedKey} / cards.${sectionName}`;
41283
+ const hasSideExport = Object.prototype.hasOwnProperty.call(section, "sideExportJsonKey");
41284
+ let cardSides = sides;
41285
+ if (hasSideExport || section.sideJsonKey != null) {
41286
+ const sideOverride = cardJsonKeyField(
41287
+ section,
41288
+ "sideJsonKey",
41289
+ "sideExportJsonKey",
41290
+ `${sectionPath} / sides.*`
41291
+ );
41292
+ cardSides = sides.map((s) => ({ ...s, ...sideOverride }));
40602
41293
  }
40603
41294
  return {
40604
41295
  name: sectionName,
40605
41296
  ...section.isDefault ? { isDefault: true } : {},
40606
- jsonKey: section.jsonKey,
41297
+ ...cardJsonKeyField(section, "jsonKey", "exportJsonKey", sectionPath),
40607
41298
  sides: cardSides
40608
41299
  };
40609
41300
  });
40610
41301
  return { name: normalizedKey, cards };
40611
41302
  }
41303
+ const cardSetPath = `cardSets.${normalizedKey} / cards.default`;
40612
41304
  return {
40613
41305
  name: normalizedKey,
40614
41306
  cards: [
40615
41307
  {
40616
41308
  name: "default",
40617
41309
  isDefault: true,
40618
- jsonKey: cardSetConfig.jsonKey,
41310
+ ...cardJsonKeyField(cardSetConfig, "jsonKey", "exportJsonKey", cardSetPath),
40619
41311
  sides
40620
41312
  }
40621
41313
  ]
@@ -40642,10 +41334,20 @@ var ConfigBuilder = class {
40642
41334
  if (allAreGroups && processedTags.length > 0) {
40643
41335
  const replacements = [];
40644
41336
  if (b.baseBitType) {
40645
- replacements.push(`group-${b.baseBitType}`);
41337
+ replacements.push({ key: `group-${b.baseBitType}` });
40646
41338
  }
40647
41339
  for (const t of processedTags) {
40648
- replacements.push(t.key);
41340
+ const ref = {
41341
+ key: t.key,
41342
+ ...t.min != null ? { min: t.min } : {},
41343
+ ...t.max != null ? { max: t.max } : {},
41344
+ ...t.description ? { description: t.description } : {}
41345
+ };
41346
+ if (Object.prototype.hasOwnProperty.call(t, "jsonKey")) {
41347
+ ref.exportJsonKey = t.jsonKey;
41348
+ ref.hasExportJsonKey = true;
41349
+ }
41350
+ replacements.push(ref);
40649
41351
  }
40650
41352
  squashedGroups.set(groupKey, replacements);
40651
41353
  }
@@ -40664,19 +41366,27 @@ var ConfigBuilder = class {
40664
41366
  const isInheritedFrom = bitGroupConfigKeys.has(b.bitType);
40665
41367
  if (isInheritedFrom) {
40666
41368
  const resolvedGroups = resolveGroupReferences(`group-${b.bitType}`);
40667
- for (const groupKey of resolvedGroups) {
41369
+ for (const ref of resolvedGroups) {
40668
41370
  tags2.push({
40669
41371
  type: "group",
40670
- key: groupKey
41372
+ key: ref.key,
41373
+ ...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
41374
+ ...ref.min != null ? { min: ref.min } : {},
41375
+ ...ref.max != null ? { max: ref.max } : {},
41376
+ ...ref.description ? { description: ref.description } : {}
40671
41377
  });
40672
41378
  }
40673
41379
  } else {
40674
41380
  if (b.baseBitType) {
40675
41381
  const resolvedGroups = resolveGroupReferences(`group-${b.baseBitType}`);
40676
- for (const groupKey of resolvedGroups) {
41382
+ for (const ref of resolvedGroups) {
40677
41383
  tags2.push({
40678
41384
  type: "group",
40679
- key: groupKey
41385
+ key: ref.key,
41386
+ ...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
41387
+ ...ref.min != null ? { min: ref.min } : {},
41388
+ ...ref.max != null ? { max: ref.max } : {},
41389
+ ...ref.description ? { description: ref.description } : {}
40680
41390
  });
40681
41391
  }
40682
41392
  }
@@ -40796,10 +41506,14 @@ var ConfigBuilder = class {
40796
41506
  const tags2 = [];
40797
41507
  if (b.baseBitType) {
40798
41508
  const resolvedGroups = resolveGroupReferences(`group-${b.baseBitType}`);
40799
- for (const gk of resolvedGroups) {
41509
+ for (const ref of resolvedGroups) {
40800
41510
  tags2.push({
40801
41511
  type: "group",
40802
- key: gk
41512
+ key: ref.key,
41513
+ ...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
41514
+ ...ref.min != null ? { min: ref.min } : {},
41515
+ ...ref.max != null ? { max: ref.max } : {},
41516
+ ...ref.description ? { description: ref.description } : {}
40803
41517
  });
40804
41518
  }
40805
41519
  }
@@ -40834,6 +41548,13 @@ var ConfigBuilder = class {
40834
41548
  };
40835
41549
  writeBitsAsGroupConfigs(bitGroupConfigs);
40836
41550
  writeCardConfigs();
41551
+ if (exportJsonKeyErrors.length > 0) {
41552
+ console.error("\n\u26A0\uFE0F exportJsonKey validation errors:");
41553
+ for (const e of exportJsonKeyErrors) console.error(` - ${e}`);
41554
+ throw new Error(
41555
+ `exportJsonKey validation failed: ${exportJsonKeyErrors.length} entr${exportJsonKeyErrors.length === 1 ? "y" : "ies"} with non-default jsonKey but no exportJsonKey companion.`
41556
+ );
41557
+ }
40837
41558
  Promise.all(fileWrites).then(() => {
40838
41559
  const validationErrors = this.validateConfigTree(outputFolder);
40839
41560
  if (validationErrors.length > 0) {
@@ -41722,6 +42443,117 @@ var JsonStringGenerator = class {
41722
42443
  }
41723
42444
  };
41724
42445
 
42446
+ // src/utils/BoundingBox.ts
42447
+ function toBbox(arr) {
42448
+ if (!Array.isArray(arr) || arr.length !== 4) return null;
42449
+ if (!arr.every(Number.isFinite)) return null;
42450
+ return [arr[0], arr[1], arr[2], arr[3]];
42451
+ }
42452
+ function parseSourceBB(sourceBB) {
42453
+ if (sourceBB == null) return [];
42454
+ if (!Array.isArray(sourceBB) || sourceBB.length === 0) return [];
42455
+ const isNested = sourceBB.some(Array.isArray);
42456
+ const candidates = isNested ? sourceBB : [sourceBB];
42457
+ const out = [];
42458
+ for (const candidate of candidates) {
42459
+ const box = toBbox(candidate);
42460
+ if (box) out.push(box);
42461
+ }
42462
+ return out;
42463
+ }
42464
+ function boundingBoxIntersects(a, b) {
42465
+ return a[0] < b[2] && a[2] > b[0] && a[1] < b[3] && a[3] > b[1];
42466
+ }
42467
+ function boundingBoxUnion(boxes) {
42468
+ if (boxes.length === 0) return null;
42469
+ let [x0, y0, x1, y1] = boxes[0];
42470
+ for (let i = 1; i < boxes.length; i++) {
42471
+ const b = boxes[i];
42472
+ if (b[0] < x0) x0 = b[0];
42473
+ if (b[1] < y0) y0 = b[1];
42474
+ if (b[2] > x1) x1 = b[2];
42475
+ if (b[3] > y1) y1 = b[3];
42476
+ }
42477
+ return [x0, y0, x1, y1];
42478
+ }
42479
+ var BoundingBoxIndex = class _BoundingBoxIndex {
42480
+ constructor(entries) {
42481
+ __publicField(this, "_entries");
42482
+ __publicField(this, "bitmarkParser", new BitmarkParserGenerator());
42483
+ this._entries = entries;
42484
+ }
42485
+ /**
42486
+ * Build an index from already-parsed bits. Bits without a parseable
42487
+ * `sourceBB` are dropped. Order of the input is preserved.
42488
+ *
42489
+ * Pass `options.sourceRL` to scope the index to a single source page —
42490
+ * bits whose `sourceRL` doesn't match (or is absent) are excluded.
42491
+ */
42492
+ static fromBits(wrappers, options) {
42493
+ const filterSourceRL = options?.sourceRL;
42494
+ const entries = [];
42495
+ for (const wrapper of wrappers) {
42496
+ if (!wrapper?.bit) continue;
42497
+ if (filterSourceRL !== void 0 && wrapper.bit.sourceRL !== filterSourceRL) {
42498
+ continue;
42499
+ }
42500
+ const boxes = parseSourceBB(wrapper.bit.sourceBB);
42501
+ if (boxes.length === 0) continue;
42502
+ entries.push({ bit: wrapper.bit, wrapper, boxes });
42503
+ }
42504
+ return new _BoundingBoxIndex(entries);
42505
+ }
42506
+ /** All bits with at least one valid `sourceBB`, in input order. */
42507
+ get entries() {
42508
+ return this._entries;
42509
+ }
42510
+ /**
42511
+ * Bits whose ANY `sourceBB` box intersects `query` (strict overlap —
42512
+ * touching-only edges do NOT count as an intersection).
42513
+ */
42514
+ intersecting(query) {
42515
+ const matches = [];
42516
+ for (const entry of this._entries) {
42517
+ if (entry.boxes.some((box) => boundingBoxIntersects(query, box))) {
42518
+ matches.push(entry);
42519
+ }
42520
+ }
42521
+ return matches;
42522
+ }
42523
+ /**
42524
+ * Flat list of every individual `sourceBB` box that intersects `query`.
42525
+ * For a multi-box bit, only the boxes that themselves intersected are
42526
+ * returned.
42527
+ */
42528
+ intersectingBoxes(query) {
42529
+ const matches = [];
42530
+ for (const entry of this._entries) {
42531
+ for (const box of entry.boxes) {
42532
+ if (boundingBoxIntersects(query, box)) matches.push(box);
42533
+ }
42534
+ }
42535
+ return matches;
42536
+ }
42537
+ /**
42538
+ * Smallest axis-aligned box that fully encloses every individual `sourceBB`
42539
+ * box that intersected the query. For a multi-box bit, only the boxes that
42540
+ * themselves intersected contribute to the union — non-intersecting boxes
42541
+ * from the same bit are ignored. Returns `null` if no box matches.
42542
+ */
42543
+ enclosingBoundingBox(query) {
42544
+ return boundingBoxUnion(this.intersectingBoxes(query));
42545
+ }
42546
+ /** Render selected bits back to bitmark text. Empty input returns `''`. */
42547
+ toBitmark(entries) {
42548
+ if (entries.length === 0) return "";
42549
+ const wrappers = entries.map((e) => e.wrapper);
42550
+ return this.bitmarkParser.convert(wrappers, {
42551
+ outputFormat: Output.bitmark,
42552
+ bitmarkOptions: { prettifyJson: true }
42553
+ });
42554
+ }
42555
+ };
42556
+
41725
42557
  // src/index.ts
41726
42558
  init();
41727
42559
  // Annotate the CommonJS export names for ESM import in node:
@@ -41736,6 +42568,7 @@ init();
41736
42568
  BitmarkStringGenerator,
41737
42569
  BitmarkVersion,
41738
42570
  BodyTextFormat,
42571
+ BoundingBoxIndex,
41739
42572
  Builder,
41740
42573
  CardSetVersion,
41741
42574
  FileWriter,