@gmb/bitmark-parser-generator 5.21.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",
@@ -695,6 +697,7 @@ var BitType = {
695
697
  vendorPadletEmbed: "vendor-padlet-embed",
696
698
  vendorStripePricingTable: "vendor-stripe-pricing-table",
697
699
  vendorStripePricingTableExternal: "vendor-stripe-pricing-table-external",
700
+ vendorStripePricingTablePrintOnRequest: "vendor-stripe-pricing-table-print-on-request",
698
701
  video: "video",
699
702
  videoEmbed: "video-embed",
700
703
  videoEmbedLandscape: "video-embed-landscape",
@@ -763,8 +766,10 @@ var TagFormat = {
763
766
  // If the value is treated as a boolean
764
767
  invertedBoolean: "invertedBoolean",
765
768
  // If the value is treated as a boolean with the value inverted (e.g. isLongAnswer ==> isShortAnswer = false)
766
- enumeration: "enumeration"
769
+ enumeration: "enumeration",
767
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)
768
773
  };
769
774
 
770
775
  // src/model/enum/TextFormat.ts
@@ -849,7 +854,11 @@ var AbstractTagConfig = class {
849
854
  // Default: 0
850
855
  __publicField(this, "chain");
851
856
  __publicField(this, "jsonKey");
852
- // 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
853
862
  __publicField(this, "deprecated");
854
863
  this.type = params.type;
855
864
  this.configKey = params.configKey;
@@ -858,6 +867,8 @@ var AbstractTagConfig = class {
858
867
  this.minCount = params.minCount;
859
868
  this.chain = params.chain;
860
869
  this.jsonKey = params.jsonKey;
870
+ this.exportJsonKey = params.exportJsonKey;
871
+ this.hasExportJsonKey = params.hasExportJsonKey;
861
872
  this.deprecated = params.deprecated;
862
873
  }
863
874
  };
@@ -867,7 +878,6 @@ var MarkupTagConfig = class extends AbstractTagConfig {
867
878
  constructor(params) {
868
879
  super({
869
880
  type: BitTagConfigKeyType.tag,
870
- jsonKey: void 0,
871
881
  ...params
872
882
  });
873
883
  __publicField(this, "type", BitTagConfigKeyType.tag);
@@ -979,8 +989,8 @@ var ResourceTagConfig = class extends AbstractTagConfig {
979
989
 
980
990
  // src/model/config/CardVariantConfig.ts
981
991
  var CardVariantConfig = class {
982
- // JSON path for body text
983
- constructor(tags2, bodyAllowed, bodyRequired, repeatCount, jsonKey) {
992
+ // Body text format. Default: bitmark++
993
+ constructor(tags2, bodyAllowed, bodyRequired, repeatCount, jsonKey, exportJsonKey, hasExportJsonKey = false, format) {
984
994
  __publicField(this, "tags");
985
995
  __publicField(this, "bodyAllowed");
986
996
  // Default: true
@@ -990,11 +1000,19 @@ var CardVariantConfig = class {
990
1000
  // Default: 1
991
1001
  // JSON mapping fields
992
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");
993
1008
  this.tags = tags2;
994
1009
  this.bodyAllowed = bodyAllowed == null ? true : bodyAllowed;
995
1010
  this.bodyRequired = bodyRequired;
996
1011
  this.repeatCount = repeatCount;
997
1012
  this.jsonKey = jsonKey;
1013
+ this.exportJsonKey = exportJsonKey;
1014
+ this.hasExportJsonKey = hasExportJsonKey;
1015
+ this.format = format;
998
1016
  }
999
1017
  toString(options) {
1000
1018
  const opts = Object.assign({}, options);
@@ -1018,14 +1036,18 @@ ${tag.toString(opts)}`;
1018
1036
 
1019
1037
  // src/model/config/CardSideConfig.ts
1020
1038
  var CardSideConfig = class {
1021
- constructor(name, repeat, variants, jsonKey) {
1039
+ constructor(name, repeat, variants, jsonKey, exportJsonKey, hasExportJsonKey = false) {
1022
1040
  __publicField(this, "name");
1023
1041
  __publicField(this, "repeat");
1024
1042
  __publicField(this, "jsonKey");
1043
+ __publicField(this, "exportJsonKey");
1044
+ __publicField(this, "hasExportJsonKey");
1025
1045
  __publicField(this, "variants");
1026
1046
  this.name = name;
1027
1047
  this.repeat = repeat;
1028
1048
  this.jsonKey = jsonKey;
1049
+ this.exportJsonKey = exportJsonKey;
1050
+ this.hasExportJsonKey = hasExportJsonKey;
1029
1051
  this.variants = variants;
1030
1052
  }
1031
1053
  toString(options) {
@@ -1047,13 +1069,17 @@ var CardSideConfig = class {
1047
1069
 
1048
1070
  // src/model/config/CardSetConfig.ts
1049
1071
  var CardSetConfig = class {
1050
- constructor(configKey, jsonKey, sections, sides) {
1072
+ constructor(configKey, jsonKey, exportJsonKey, hasExportJsonKey, sections, sides) {
1051
1073
  __publicField(this, "configKey");
1052
1074
  __publicField(this, "jsonKey");
1075
+ __publicField(this, "exportJsonKey");
1076
+ __publicField(this, "hasExportJsonKey");
1053
1077
  __publicField(this, "sections");
1054
1078
  __publicField(this, "sides");
1055
1079
  this.configKey = configKey;
1056
1080
  this.jsonKey = jsonKey;
1081
+ this.exportJsonKey = exportJsonKey;
1082
+ this.hasExportJsonKey = hasExportJsonKey;
1057
1083
  this.sections = sections;
1058
1084
  this.sides = sides;
1059
1085
  }
@@ -1348,6 +1374,7 @@ var propertyKeys = {
1348
1374
  property_formula: "@formula",
1349
1375
  property_fullName: "@fullName",
1350
1376
  property_groupTag: "@groupTag",
1377
+ property_gUri: "@gUri",
1351
1378
  property_handInAcceptFileType: "@handInAcceptFileType",
1352
1379
  property_handInInstruction: "@handInInstruction",
1353
1380
  property_handInRequirement: "@handInRequirement",
@@ -1406,6 +1433,8 @@ var propertyKeys = {
1406
1433
  property_padletId: "@padletId",
1407
1434
  property_page: "@page",
1408
1435
  property_printParentChapterLevel: "@printParentChapterLevel",
1436
+ property_printOnRequestCustomerId: "@printOnRequestCustomerId",
1437
+ property_printOnRequestProductId: "@printOnRequestProductId",
1409
1438
  property_pageNo: "@pageNo",
1410
1439
  property_partialAnswer: "@partialAnswer",
1411
1440
  property_partner: "@partner",
@@ -1481,6 +1510,7 @@ var propertyKeys = {
1481
1510
  property_siteName: "@siteName",
1482
1511
  property_size: "@size",
1483
1512
  property_slug: "@slug",
1513
+ property_sourceBB: "@sourceBB",
1484
1514
  property_sourceDocument: "@sourceDocument",
1485
1515
  property_sourceRL: "@sourceRL",
1486
1516
  property_spaceId: "@spaceId",
@@ -2234,25 +2264,29 @@ var CARDSETS = {
2234
2264
  //
2235
2265
  [CardSetConfigKey.flashcard]: {
2236
2266
  jsonKey: "cards",
2267
+ exportJsonKey: { cards: "$" },
2237
2268
  sides: [
2238
2269
  {
2239
2270
  name: "question",
2240
2271
  variants: [
2241
2272
  {
2242
2273
  jsonKey: "question.text",
2274
+ exportJsonKey: { question: { text: "$" } },
2243
2275
  tags: [
2244
2276
  {
2245
2277
  key: ConfigKey.group_standardTags,
2246
2278
  description: "Standard tags for the flashcard."
2247
2279
  },
2248
2280
  {
2281
+ exportJsonKey: { title: "$" },
2249
2282
  key: ConfigKey.tag_title,
2250
2283
  description: "Title of the flashcard."
2251
2284
  },
2252
2285
  {
2253
2286
  key: ConfigKey.group_resourceIcon,
2254
2287
  description: "Icon resource for the flashcard.",
2255
- jsonKey: "question.icon"
2288
+ jsonKey: "question.icon|resource(type=image, key=image)",
2289
+ exportJsonKey: { question: { icon: { type: "image", image: { src: "$" } } } }
2256
2290
  }
2257
2291
  ]
2258
2292
  }
@@ -2263,36 +2297,45 @@ var CARDSETS = {
2263
2297
  variants: [
2264
2298
  {
2265
2299
  jsonKey: "answer.text",
2300
+ exportJsonKey: { answer: { text: "$" } },
2266
2301
  tags: [
2267
2302
  {
2268
2303
  key: ConfigKey.group_standardTags,
2269
2304
  description: "Standard tags for the flashcard."
2270
2305
  },
2271
2306
  {
2307
+ exportJsonKey: { title: "$" },
2272
2308
  key: ConfigKey.tag_title,
2273
2309
  description: "Title of the flashcard."
2274
2310
  },
2275
2311
  {
2276
2312
  key: ConfigKey.group_resourceIcon,
2277
2313
  description: "Icon resource for the flashcard.",
2278
- jsonKey: "answer.icon"
2314
+ jsonKey: "answer.icon|resource(type=image, key=image)",
2315
+ exportJsonKey: { answer: { icon: { type: "image", image: { src: "$" } } } }
2279
2316
  }
2280
2317
  ]
2281
2318
  },
2282
2319
  {
2283
2320
  jsonKey: "alternativeAnswers[].text",
2321
+ exportJsonKey: { alternativeAnswers: [{ text: "$" }] },
2284
2322
  tags: [
2285
2323
  {
2286
2324
  key: ConfigKey.group_standardTags,
2287
2325
  description: "Standard tags for the flashcard."
2288
2326
  },
2289
2327
  {
2328
+ exportJsonKey: { title: "$" },
2290
2329
  key: ConfigKey.tag_title,
2291
2330
  description: "Title of the flashcard."
2292
2331
  },
2293
2332
  {
2294
2333
  key: ConfigKey.group_resourceIcon,
2295
- description: "Icon resource for the flashcard."
2334
+ description: "Icon resource for the flashcard.",
2335
+ jsonKey: "alternativeAnswers[].icon|resource(type=image, key=image)",
2336
+ exportJsonKey: {
2337
+ alternativeAnswers: [{ icon: { type: "image", image: { src: "$" } } }]
2338
+ }
2296
2339
  }
2297
2340
  ],
2298
2341
  repeatCount: Count.infinity
@@ -2306,12 +2349,14 @@ var CARDSETS = {
2306
2349
  //
2307
2350
  [CardSetConfigKey.definitionList]: {
2308
2351
  jsonKey: "definitions",
2352
+ exportJsonKey: { definitions: "$" },
2309
2353
  sides: [
2310
2354
  {
2311
2355
  name: "term",
2312
2356
  variants: [
2313
2357
  {
2314
2358
  jsonKey: "term.text",
2359
+ exportJsonKey: { term: { text: "$" } },
2315
2360
  tags: [
2316
2361
  {
2317
2362
  key: ConfigKey.group_standardTags,
@@ -2320,12 +2365,16 @@ var CARDSETS = {
2320
2365
  {
2321
2366
  key: ConfigKey.tag_title,
2322
2367
  description: "Title of the definition.",
2323
- jsonKey: "^heading.forKeys"
2368
+ format: TagFormat.plainText,
2369
+ jsonKey: "^heading.forKeys",
2370
+ exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2324
2371
  },
2325
2372
  {
2326
2373
  key: ConfigKey.group_resourceIcon,
2327
2374
  description: "Icon resource for the definition.",
2328
- jsonKey: "term.icon"
2375
+ format: TagFormat.plainText,
2376
+ jsonKey: "term.icon|resource(type=image, key=image)",
2377
+ exportJsonKey: { term: { icon: { type: "image", image: { src: "$" } } } }
2329
2378
  }
2330
2379
  ]
2331
2380
  }
@@ -2336,6 +2385,7 @@ var CARDSETS = {
2336
2385
  variants: [
2337
2386
  {
2338
2387
  jsonKey: "definition.text",
2388
+ exportJsonKey: { definition: { text: "$" } },
2339
2389
  tags: [
2340
2390
  {
2341
2391
  key: ConfigKey.group_standardTags,
@@ -2344,29 +2394,38 @@ var CARDSETS = {
2344
2394
  {
2345
2395
  key: ConfigKey.tag_title,
2346
2396
  description: "Title of the definition.",
2347
- jsonKey: "^heading.forValues"
2397
+ format: TagFormat.plainText,
2398
+ jsonKey: "^heading.forValues",
2399
+ exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2348
2400
  },
2349
2401
  {
2350
2402
  key: ConfigKey.group_resourceIcon,
2351
2403
  description: "Icon resource for the definition.",
2352
- jsonKey: "definition.icon"
2404
+ jsonKey: "definition.icon|resource(type=image, key=image)",
2405
+ exportJsonKey: { definition: { icon: { type: "image", image: { src: "$" } } } }
2353
2406
  }
2354
2407
  ]
2355
2408
  },
2356
2409
  {
2357
2410
  jsonKey: "alternativeDefinitions[].text",
2411
+ exportJsonKey: { alternativeDefinitions: [{ text: "$" }] },
2358
2412
  tags: [
2359
2413
  {
2360
2414
  key: ConfigKey.group_standardTags,
2361
2415
  description: "Standard tags for the definition."
2362
2416
  },
2363
2417
  {
2418
+ exportJsonKey: { title: "$" },
2364
2419
  key: ConfigKey.tag_title,
2365
2420
  description: "Title of the definition."
2366
2421
  },
2367
2422
  {
2368
2423
  key: ConfigKey.group_resourceIcon,
2369
- description: "Icon resource for the definition."
2424
+ description: "Icon resource for the definition.",
2425
+ jsonKey: "alternativeDefinitions[].icon|resource(type=image, key=image)",
2426
+ exportJsonKey: {
2427
+ alternativeDefinitions: [{ icon: { type: "image", image: { src: "$" } } }]
2428
+ }
2370
2429
  }
2371
2430
  ],
2372
2431
  repeatCount: Count.infinity
@@ -2380,12 +2439,14 @@ var CARDSETS = {
2380
2439
  //
2381
2440
  [CardSetConfigKey.matchPairs]: {
2382
2441
  jsonKey: "pairs",
2442
+ exportJsonKey: { pairs: "$" },
2383
2443
  sides: [
2384
2444
  {
2385
2445
  name: "key",
2386
2446
  variants: [
2387
2447
  {
2388
2448
  jsonKey: "key",
2449
+ exportJsonKey: { key: "$" },
2389
2450
  tags: [
2390
2451
  {
2391
2452
  key: ConfigKey.group_standardTags,
@@ -2394,22 +2455,30 @@ var CARDSETS = {
2394
2455
  {
2395
2456
  key: ConfigKey.tag_title,
2396
2457
  description: "Title of the match pair.",
2397
- jsonKey: "^heading.forKeys"
2458
+ format: TagFormat.plainText,
2459
+ jsonKey: "^heading.forKeys",
2460
+ exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2398
2461
  },
2399
2462
  {
2400
2463
  key: ConfigKey.property_isCaseSensitive,
2464
+ exportJsonKey: [
2465
+ { "@absent": { isCaseSensitive: "$ancestor" } },
2466
+ { isCaseSensitive: "$" }
2467
+ ],
2401
2468
  description: "Property to indicate if the match is case sensitive.",
2402
2469
  format: TagFormat.boolean
2403
2470
  },
2404
2471
  {
2405
2472
  key: ConfigKey.resource_audio,
2406
2473
  description: "Audio resource for the match pair.",
2407
- jsonKey: "keyAudio"
2474
+ jsonKey: "keyAudio",
2475
+ exportJsonKey: { keyAudio: "$" }
2408
2476
  },
2409
2477
  {
2410
2478
  key: ConfigKey.resource_image,
2411
2479
  description: "Image resource for the match pair.",
2412
- jsonKey: "keyImage"
2480
+ jsonKey: "keyImage",
2481
+ exportJsonKey: { keyImage: "$" }
2413
2482
  }
2414
2483
  ]
2415
2484
  }
@@ -2421,6 +2490,7 @@ var CARDSETS = {
2421
2490
  variants: [
2422
2491
  {
2423
2492
  jsonKey: "values[]",
2493
+ exportJsonKey: { values: ["$"] },
2424
2494
  tags: [
2425
2495
  {
2426
2496
  key: ConfigKey.group_standardTags,
@@ -2429,10 +2499,16 @@ var CARDSETS = {
2429
2499
  {
2430
2500
  key: ConfigKey.tag_title,
2431
2501
  description: "Title of the match pair.",
2432
- jsonKey: "^heading.forValues"
2502
+ format: TagFormat.plainText,
2503
+ jsonKey: "^heading.forValues",
2504
+ exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2433
2505
  },
2434
2506
  {
2435
2507
  key: ConfigKey.property_isCaseSensitive,
2508
+ exportJsonKey: [
2509
+ { "@absent": { isCaseSensitive: "$ancestor" } },
2510
+ { isCaseSensitive: "$" }
2511
+ ],
2436
2512
  description: "Property to indicate if the match is case sensitive.",
2437
2513
  format: TagFormat.boolean
2438
2514
  }
@@ -2448,12 +2524,14 @@ var CARDSETS = {
2448
2524
  //
2449
2525
  [CardSetConfigKey.matchAudioPairs]: {
2450
2526
  jsonKey: "pairs",
2527
+ exportJsonKey: { pairs: "$" },
2451
2528
  sides: [
2452
2529
  {
2453
2530
  name: "key",
2454
2531
  variants: [
2455
2532
  {
2456
2533
  jsonKey: "key",
2534
+ exportJsonKey: { key: "$" },
2457
2535
  tags: [
2458
2536
  {
2459
2537
  key: ConfigKey.group_standardTags,
@@ -2462,12 +2540,15 @@ var CARDSETS = {
2462
2540
  {
2463
2541
  key: ConfigKey.tag_title,
2464
2542
  description: "Title of the audio match pair.",
2465
- jsonKey: "^heading.forKeys"
2543
+ format: TagFormat.plainText,
2544
+ jsonKey: "^heading.forKeys",
2545
+ exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2466
2546
  },
2467
2547
  {
2468
2548
  key: ConfigKey.resource_audio,
2469
2549
  description: "Audio resource for the match pair.",
2470
- jsonKey: "keyAudio"
2550
+ jsonKey: "keyAudio",
2551
+ exportJsonKey: { keyAudio: "$" }
2471
2552
  }
2472
2553
  ]
2473
2554
  }
@@ -2479,6 +2560,7 @@ var CARDSETS = {
2479
2560
  variants: [
2480
2561
  {
2481
2562
  jsonKey: "values[]",
2563
+ exportJsonKey: { values: ["$"] },
2482
2564
  tags: [
2483
2565
  {
2484
2566
  key: ConfigKey.group_standardTags,
@@ -2487,7 +2569,9 @@ var CARDSETS = {
2487
2569
  {
2488
2570
  key: ConfigKey.tag_title,
2489
2571
  description: "Title of the audio match pair.",
2490
- jsonKey: "^heading.forValues"
2572
+ format: TagFormat.plainText,
2573
+ jsonKey: "^heading.forValues",
2574
+ exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2491
2575
  },
2492
2576
  {
2493
2577
  key: ConfigKey.resource_audio,
@@ -2505,12 +2589,14 @@ var CARDSETS = {
2505
2589
  //
2506
2590
  [CardSetConfigKey.matchImagePairs]: {
2507
2591
  jsonKey: "pairs",
2592
+ exportJsonKey: { pairs: "$" },
2508
2593
  sides: [
2509
2594
  {
2510
2595
  name: "key",
2511
2596
  variants: [
2512
2597
  {
2513
2598
  jsonKey: "key",
2599
+ exportJsonKey: { key: "$" },
2514
2600
  tags: [
2515
2601
  {
2516
2602
  key: ConfigKey.group_standardTags,
@@ -2519,12 +2605,15 @@ var CARDSETS = {
2519
2605
  {
2520
2606
  key: ConfigKey.tag_title,
2521
2607
  description: "Title of the image match pair.",
2522
- jsonKey: "^heading.forKeys"
2608
+ format: TagFormat.plainText,
2609
+ jsonKey: "^heading.forKeys",
2610
+ exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2523
2611
  },
2524
2612
  {
2525
2613
  key: ConfigKey.resource_image,
2526
2614
  description: "Image resource for the match pair.",
2527
- jsonKey: "keyImage"
2615
+ jsonKey: "keyImage",
2616
+ exportJsonKey: { keyImage: "$" }
2528
2617
  }
2529
2618
  ]
2530
2619
  }
@@ -2536,6 +2625,7 @@ var CARDSETS = {
2536
2625
  variants: [
2537
2626
  {
2538
2627
  jsonKey: "values[]",
2628
+ exportJsonKey: { values: ["$"] },
2539
2629
  tags: [
2540
2630
  {
2541
2631
  key: ConfigKey.group_standardTags,
@@ -2544,7 +2634,9 @@ var CARDSETS = {
2544
2634
  {
2545
2635
  key: ConfigKey.tag_title,
2546
2636
  description: "Title of the image match pair.",
2547
- jsonKey: "^heading.forValues"
2637
+ format: TagFormat.plainText,
2638
+ jsonKey: "^heading.forValues",
2639
+ exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2548
2640
  },
2549
2641
  {
2550
2642
  key: ConfigKey.resource_image,
@@ -2562,12 +2654,14 @@ var CARDSETS = {
2562
2654
  //
2563
2655
  [CardSetConfigKey.matchMatrix]: {
2564
2656
  jsonKey: "matrix",
2657
+ exportJsonKey: { matrix: "$" },
2565
2658
  sides: [
2566
2659
  {
2567
2660
  name: "key",
2568
2661
  variants: [
2569
2662
  {
2570
2663
  jsonKey: "key",
2664
+ exportJsonKey: { key: "$" },
2571
2665
  tags: [
2572
2666
  {
2573
2667
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -2575,16 +2669,27 @@ var CARDSETS = {
2575
2669
  },
2576
2670
  {
2577
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
+ ],
2578
2677
  description: "Example text for the match matrix.",
2579
2678
  format: TagFormat.plainText
2580
2679
  },
2581
2680
  {
2582
2681
  key: ConfigKey.tag_title,
2583
2682
  description: "Title of the match matrix.",
2584
- jsonKey: "^heading.forKeys"
2683
+ format: TagFormat.plainText,
2684
+ jsonKey: "^heading.forKeys",
2685
+ exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2585
2686
  },
2586
2687
  {
2587
2688
  key: ConfigKey.property_isCaseSensitive,
2689
+ exportJsonKey: [
2690
+ { "@absent": { isCaseSensitive: "$ancestor" } },
2691
+ { isCaseSensitive: "$" }
2692
+ ],
2588
2693
  description: "Property to indicate if the match is case sensitive.",
2589
2694
  format: TagFormat.boolean
2590
2695
  }
@@ -2598,6 +2703,7 @@ var CARDSETS = {
2598
2703
  variants: [
2599
2704
  {
2600
2705
  jsonKey: "cells[{s}].values[]",
2706
+ exportJsonKey: { cells: { $s: { values: ["$"] } } },
2601
2707
  tags: [
2602
2708
  {
2603
2709
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -2605,16 +2711,34 @@ var CARDSETS = {
2605
2711
  },
2606
2712
  {
2607
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
+ ],
2608
2726
  description: "Example text for the match matrix.",
2609
2727
  format: TagFormat.plainText
2610
2728
  },
2611
2729
  {
2612
2730
  key: ConfigKey.tag_title,
2613
2731
  description: "Title of the match matrix.",
2614
- jsonKey: "^heading.forValues"
2732
+ format: TagFormat.plainText,
2733
+ jsonKey: "^heading.forValues",
2734
+ exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2615
2735
  },
2616
2736
  {
2617
2737
  key: ConfigKey.property_isCaseSensitive,
2738
+ exportJsonKey: [
2739
+ { "@absent": { isCaseSensitive: "$ancestor" } },
2740
+ { isCaseSensitive: "$" }
2741
+ ],
2618
2742
  description: "Property to indicate if the match is case sensitive.",
2619
2743
  format: TagFormat.boolean
2620
2744
  }
@@ -2630,23 +2754,27 @@ var CARDSETS = {
2630
2754
  //
2631
2755
  [CardSetConfigKey.statements]: {
2632
2756
  jsonKey: "statements",
2757
+ exportJsonKey: { statements: "$" },
2633
2758
  sides: [
2634
2759
  {
2635
2760
  name: "statement",
2636
2761
  variants: [
2637
2762
  {
2638
2763
  jsonKey: "statement",
2764
+ exportJsonKey: { statement: "$" },
2639
2765
  tags: [
2640
2766
  {
2641
2767
  key: ConfigKey.tag_true,
2642
2768
  description: "Tag for true statements.",
2643
2769
  jsonKey: "statement|set(isCorrect=true)",
2770
+ exportJsonKey: { statement: "$", isCorrect: true },
2644
2771
  maxCount: 1
2645
2772
  },
2646
2773
  {
2647
2774
  key: ConfigKey.tag_false,
2648
2775
  description: "Tag for false statements.",
2649
2776
  jsonKey: "statement|set(isCorrect=false)",
2777
+ exportJsonKey: { statement: "$", isCorrect: false },
2650
2778
  maxCount: 1
2651
2779
  },
2652
2780
  {
@@ -2665,6 +2793,7 @@ var CARDSETS = {
2665
2793
  //
2666
2794
  [CardSetConfigKey.quiz]: {
2667
2795
  jsonKey: "quizzes",
2796
+ exportJsonKey: { quizzes: "$" },
2668
2797
  sides: [
2669
2798
  {
2670
2799
  name: "choices",
@@ -2692,6 +2821,7 @@ var CARDSETS = {
2692
2821
  //
2693
2822
  [CardSetConfigKey.feedback]: {
2694
2823
  jsonKey: "feedbacks",
2824
+ exportJsonKey: { feedbacks: "$" },
2695
2825
  sides: [
2696
2826
  {
2697
2827
  name: "choices",
@@ -2710,7 +2840,9 @@ var CARDSETS = {
2710
2840
  {
2711
2841
  key: ConfigKey.tag_title,
2712
2842
  description: "Title of the feedback.",
2713
- jsonKey: "^heading.forKeys"
2843
+ format: TagFormat.plainText,
2844
+ jsonKey: "^heading.forKeys",
2845
+ exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
2714
2846
  }
2715
2847
  ],
2716
2848
  bodyAllowed: false
@@ -2722,6 +2854,7 @@ var CARDSETS = {
2722
2854
  variants: [
2723
2855
  {
2724
2856
  jsonKey: "reason.text",
2857
+ exportJsonKey: { reason: { text: "$" } },
2725
2858
  tags: [
2726
2859
  {
2727
2860
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -2729,18 +2862,29 @@ var CARDSETS = {
2729
2862
  },
2730
2863
  {
2731
2864
  key: ConfigKey.property_reasonableNumOfChars,
2865
+ exportJsonKey: [
2866
+ { "@absent": { reasonableNumOfChars: "$ancestor" } },
2867
+ { reasonableNumOfChars: "$" }
2868
+ ],
2732
2869
  description: "Property for reasonable number of characters.",
2733
2870
  format: TagFormat.number
2734
2871
  },
2735
2872
  {
2736
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
+ ],
2737
2879
  description: "Example text for the feedback.",
2738
2880
  format: TagFormat.plainText
2739
2881
  },
2740
2882
  {
2741
2883
  key: ConfigKey.tag_title,
2742
2884
  description: "Title of the feedback.",
2743
- jsonKey: "^heading.forValues"
2885
+ format: TagFormat.plainText,
2886
+ jsonKey: "^heading.forValues",
2887
+ exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
2744
2888
  }
2745
2889
  ],
2746
2890
  bodyAllowed: true
@@ -2754,21 +2898,29 @@ var CARDSETS = {
2754
2898
  //
2755
2899
  [CardSetConfigKey.questions]: {
2756
2900
  jsonKey: "questions",
2901
+ exportJsonKey: { questions: "$" },
2757
2902
  sides: [
2758
2903
  {
2759
2904
  name: "question",
2760
2905
  variants: [
2761
2906
  {
2762
2907
  jsonKey: "question",
2908
+ exportJsonKey: { question: "$" },
2763
2909
  tags: [
2764
2910
  {
2765
2911
  key: ConfigKey.property_reasonableNumOfChars,
2912
+ exportJsonKey: [
2913
+ { "@absent": { reasonableNumOfChars: "$ancestor" } },
2914
+ { reasonableNumOfChars: "$" }
2915
+ ],
2766
2916
  description: "Property for reasonable number of characters.",
2767
2917
  format: TagFormat.number
2768
2918
  },
2769
2919
  {
2920
+ exportJsonKey: { sampleSolution: "$" },
2770
2921
  key: ConfigKey.tag_sampleSolution,
2771
- description: "Sample solution for the question."
2922
+ description: "Sample solution for the question.",
2923
+ format: TagFormat.plainText
2772
2924
  },
2773
2925
  {
2774
2926
  key: ConfigKey.property_sampleSolution,
@@ -2808,6 +2960,7 @@ var CARDSETS = {
2808
2960
  variants: [
2809
2961
  {
2810
2962
  jsonKey: "elements[]",
2963
+ exportJsonKey: { elements: ["$"] },
2811
2964
  tags: [
2812
2965
  {
2813
2966
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -2815,6 +2968,11 @@ var CARDSETS = {
2815
2968
  },
2816
2969
  {
2817
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
+ ],
2818
2976
  description: "Example text for the element.",
2819
2977
  format: TagFormat.plainText
2820
2978
  }
@@ -2830,6 +2988,7 @@ var CARDSETS = {
2830
2988
  //
2831
2989
  [CardSetConfigKey.table]: {
2832
2990
  jsonKey: "table.data",
2991
+ exportJsonKey: { table: { data: "$" } },
2833
2992
  sides: [
2834
2993
  {
2835
2994
  name: "cell",
@@ -2845,6 +3004,7 @@ var CARDSETS = {
2845
3004
  {
2846
3005
  key: ConfigKey.tag_title,
2847
3006
  jsonKey: "^table.columns[]",
3007
+ exportJsonKey: { "@bit": { table: { columns: ["$"] } } },
2848
3008
  description: "Title of the table."
2849
3009
  },
2850
3010
  {
@@ -2885,18 +3045,34 @@ var CARDSETS = {
2885
3045
  [CardSetConfigKey.tableExtended]: {
2886
3046
  jsonKey: null,
2887
3047
  sections: {
2888
- "table-header": { jsonKey: "table.header.rows", sideJsonKey: "cells[{s}]|set(title=true)" },
2889
- "table-body": { jsonKey: "table.body.rows", isDefault: true },
2890
- "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
+ }
2891
3065
  },
2892
3066
  sides: [
2893
3067
  {
2894
3068
  name: "cell",
2895
3069
  repeat: true,
2896
3070
  jsonKey: "cells[{s}]",
3071
+ exportJsonKey: { cells: { $s: "$" } },
2897
3072
  variants: [
2898
3073
  {
2899
3074
  jsonKey: "content",
3075
+ exportJsonKey: { content: "$" },
2900
3076
  tags: [
2901
3077
  {
2902
3078
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -2905,29 +3081,38 @@ var CARDSETS = {
2905
3081
  {
2906
3082
  key: ConfigKey.tag_title,
2907
3083
  jsonKey: ".",
3084
+ exportJsonKey: {
3085
+ "@bit": {
3086
+ table: { header: { rows: { cells: { cells: { $s: { content: "$" } } } } } }
3087
+ }
3088
+ },
2908
3089
  description: "Title of the table cell."
2909
3090
  },
2910
3091
  {
2911
3092
  key: ConfigKey.property_tableCellType,
2912
3093
  jsonKey: "title|bool(th)",
3094
+ exportJsonKey: [{ "@value=th": { title: true } }],
2913
3095
  description: "Table cell type (th/td).",
2914
3096
  format: TagFormat.plainText
2915
3097
  },
2916
3098
  {
2917
3099
  key: ConfigKey.property_tableRowSpan,
2918
3100
  jsonKey: "rowspan",
3101
+ exportJsonKey: { rowspan: "$" },
2919
3102
  description: "Number of rows the cell spans.",
2920
3103
  format: TagFormat.number
2921
3104
  },
2922
3105
  {
2923
3106
  key: ConfigKey.property_tableColSpan,
2924
3107
  jsonKey: "colspan",
3108
+ exportJsonKey: { colspan: "$" },
2925
3109
  description: "Number of columns the cell spans.",
2926
3110
  format: TagFormat.number
2927
3111
  },
2928
3112
  {
2929
3113
  key: ConfigKey.property_tableScope,
2930
3114
  jsonKey: "scope",
3115
+ exportJsonKey: { scope: "$" },
2931
3116
  description: "Scope attribute for header cells.",
2932
3117
  format: TagFormat.plainText
2933
3118
  },
@@ -2948,6 +3133,7 @@ var CARDSETS = {
2948
3133
  //
2949
3134
  [CardSetConfigKey.pronunciationTable]: {
2950
3135
  jsonKey: "pronunciationTable.data",
3136
+ exportJsonKey: { pronunciationTable: { data: "$" } },
2951
3137
  sides: [
2952
3138
  {
2953
3139
  name: "cell",
@@ -2955,12 +3141,14 @@ var CARDSETS = {
2955
3141
  variants: [
2956
3142
  {
2957
3143
  jsonKey: "body",
3144
+ exportJsonKey: { body: "$" },
2958
3145
  tags: [
2959
3146
  {
2960
3147
  key: ConfigKey.group_standardItemLeadInstructionHint,
2961
3148
  description: "Standard tags for lead, instruction, and hint."
2962
3149
  },
2963
3150
  {
3151
+ exportJsonKey: { title: "$" },
2964
3152
  key: ConfigKey.tag_title,
2965
3153
  description: "Title of the pronunciation table."
2966
3154
  },
@@ -2981,12 +3169,15 @@ var CARDSETS = {
2981
3169
  //
2982
3170
  [CardSetConfigKey.botActionResponses]: {
2983
3171
  jsonKey: "responses",
3172
+ exportJsonKey: { responses: "$" },
2984
3173
  sides: [
2985
3174
  {
2986
3175
  name: "response",
2987
3176
  variants: [
2988
3177
  {
2989
3178
  jsonKey: "feedback",
3179
+ exportJsonKey: { feedback: "$" },
3180
+ format: TextFormat.plainText,
2990
3181
  tags: [
2991
3182
  {
2992
3183
  key: ConfigKey.property_reaction,
@@ -2994,16 +3185,53 @@ var CARDSETS = {
2994
3185
  format: TagFormat.plainText
2995
3186
  },
2996
3187
  {
2997
- key: ConfigKey.group_standardItemLead,
2998
- 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
+ ]
2999
3220
  },
3000
3221
  {
3001
3222
  key: ConfigKey.tag_instruction,
3002
3223
  description: "The response label for the bot action.",
3003
- jsonKey: "response"
3224
+ jsonKey: "response",
3225
+ exportJsonKey: { response: "$" },
3226
+ format: TagFormat.plainText
3004
3227
  },
3005
3228
  {
3006
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
+ ],
3007
3235
  description: "Example text for the bot action response.",
3008
3236
  format: TagFormat.plainText
3009
3237
  }
@@ -3018,12 +3246,14 @@ var CARDSETS = {
3018
3246
  //
3019
3247
  [CardSetConfigKey.clozeList]: {
3020
3248
  jsonKey: "listItems",
3249
+ exportJsonKey: { listItems: "$" },
3021
3250
  sides: [
3022
3251
  {
3023
3252
  name: "content",
3024
3253
  variants: [
3025
3254
  {
3026
3255
  jsonKey: "body",
3256
+ exportJsonKey: { body: "$" },
3027
3257
  tags: [
3028
3258
  {
3029
3259
  key: ConfigKey.group_standardTags,
@@ -3044,18 +3274,21 @@ var CARDSETS = {
3044
3274
  //
3045
3275
  [CardSetConfigKey.exampleBitList]: {
3046
3276
  jsonKey: "listItems",
3277
+ exportJsonKey: { listItems: "$" },
3047
3278
  sides: [
3048
3279
  {
3049
3280
  name: "item",
3050
3281
  variants: [
3051
3282
  {
3052
3283
  jsonKey: "body",
3284
+ exportJsonKey: { body: "$" },
3053
3285
  tags: [
3054
3286
  {
3055
3287
  key: ConfigKey.group_standardTags,
3056
3288
  description: "Standard tags for example bits."
3057
3289
  },
3058
3290
  {
3291
+ exportJsonKey: { title: "$" },
3059
3292
  key: ConfigKey.tag_title,
3060
3293
  description: "Title of the example bit."
3061
3294
  }
@@ -3070,28 +3303,35 @@ var CARDSETS = {
3070
3303
  //
3071
3304
  [CardSetConfigKey.ingredients]: {
3072
3305
  jsonKey: "ingredients",
3306
+ exportJsonKey: { ingredients: "$" },
3073
3307
  sides: [
3074
3308
  {
3075
3309
  name: "ingredient",
3076
3310
  variants: [
3077
3311
  {
3078
3312
  jsonKey: "ingredient",
3313
+ exportJsonKey: { ingredient: "$" },
3079
3314
  tags: [
3080
3315
  {
3316
+ exportJsonKey: { title: "$" },
3081
3317
  key: ConfigKey.tag_title,
3082
3318
  description: "Title of the ingredient."
3083
3319
  },
3084
3320
  {
3085
3321
  key: ConfigKey.tag_true,
3086
3322
  description: "Checked state for the ingredient.",
3087
- jsonKey: "ingredient|set(checked=true)",
3323
+ jsonKey: "|set(checked=true)",
3324
+ exportJsonKey: { checked: true, $: "$" },
3088
3325
  maxCount: 1
3326
+ // nullable: true,
3089
3327
  },
3090
3328
  {
3091
3329
  key: ConfigKey.tag_false,
3092
3330
  description: "Unchecked state for the ingredient.",
3093
- jsonKey: "ingredient|set(checked=false)",
3331
+ jsonKey: "|set(checked=false)",
3332
+ exportJsonKey: { checked: false, $: "$" },
3094
3333
  maxCount: 1
3334
+ // nullable: true,
3095
3335
  },
3096
3336
  {
3097
3337
  key: ConfigKey.group_standardItemLead,
@@ -3100,9 +3340,12 @@ var CARDSETS = {
3100
3340
  {
3101
3341
  key: ConfigKey.tag_instruction,
3102
3342
  description: "The quantity of the ingredient.",
3103
- jsonKey: "quantity"
3343
+ jsonKey: "quantity",
3344
+ exportJsonKey: { quantity: "$" },
3345
+ format: TagFormat.number
3104
3346
  },
3105
3347
  {
3348
+ exportJsonKey: { hint: "$" },
3106
3349
  key: ConfigKey.tag_hint,
3107
3350
  description: "The hint for the ingredient."
3108
3351
  },
@@ -3138,6 +3381,7 @@ var CARDSETS = {
3138
3381
  //
3139
3382
  [CardSetConfigKey.bookReferenceList]: {
3140
3383
  jsonKey: "bookReferences",
3384
+ exportJsonKey: { bookReferences: "$" },
3141
3385
  sides: [
3142
3386
  {
3143
3387
  name: "reference",
@@ -3197,6 +3441,11 @@ var GROUPS = {
3197
3441
  format: TagFormat.plainText,
3198
3442
  maxCount: Count.infinity
3199
3443
  },
3444
+ {
3445
+ key: ConfigKey.property_gUri,
3446
+ description: "Global URI for the bit",
3447
+ format: TagFormat.plainText
3448
+ },
3200
3449
  {
3201
3450
  key: ConfigKey.property_customerId,
3202
3451
  description: "The customer-specific identifier for the bit",
@@ -3380,12 +3629,14 @@ var GROUPS = {
3380
3629
  {
3381
3630
  key: ConfigKey.property_groupTag,
3382
3631
  jsonKey: "groupTag.name",
3632
+ exportJsonKey: { groupTag: { name: "$" } },
3383
3633
  description: "The group tag(s) for the bit",
3384
3634
  format: TagFormat.plainText,
3385
3635
  maxCount: Count.infinity,
3386
3636
  chain: [
3387
3637
  {
3388
3638
  key: ConfigKey.property_tag,
3639
+ exportJsonKey: { tags: ["$"] },
3389
3640
  description: "The tag(s) for the group",
3390
3641
  format: TagFormat.plainText,
3391
3642
  maxCount: Count.infinity
@@ -3416,6 +3667,12 @@ var GROUPS = {
3416
3667
  format: TagFormat.plainText,
3417
3668
  maxCount: Count.infinity
3418
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
+ },
3419
3676
  {
3420
3677
  key: ConfigKey.property_levelCEFRp,
3421
3678
  description: "The CEFRp level for the bit",
@@ -3453,8 +3710,10 @@ var GROUPS = {
3453
3710
  maxCount: Count.infinity
3454
3711
  },
3455
3712
  {
3713
+ exportJsonKey: { anchor: "$" },
3456
3714
  key: ConfigKey.tag_anchor,
3457
3715
  name: "Anchor",
3716
+ format: TagFormat.plainText,
3458
3717
  description: "The anchor for the bit"
3459
3718
  },
3460
3719
  {
@@ -3489,23 +3748,27 @@ var GROUPS = {
3489
3748
  {
3490
3749
  key: ConfigKey.tag_item,
3491
3750
  jsonKey: "item",
3751
+ exportJsonKey: { item: "$" },
3492
3752
  description: "The item for the bit",
3493
3753
  chain: [
3494
3754
  {
3495
3755
  key: ConfigKey.tag_item,
3496
3756
  jsonKey: "lead",
3757
+ exportJsonKey: { lead: "$" },
3497
3758
  description: "The lead for the bit",
3498
3759
  maxCount: 1,
3499
3760
  chain: [
3500
3761
  {
3501
3762
  key: ConfigKey.tag_item,
3502
3763
  jsonKey: "pageNumber",
3764
+ exportJsonKey: { pageNumber: "$" },
3503
3765
  description: "The page number for the bit",
3504
3766
  maxCount: 1,
3505
3767
  chain: [
3506
3768
  {
3507
3769
  key: ConfigKey.tag_item,
3508
3770
  jsonKey: "marginNumber",
3771
+ exportJsonKey: { marginNumber: "$" },
3509
3772
  description: "The margin number for the bit",
3510
3773
  maxCount: 1
3511
3774
  }
@@ -3526,11 +3789,13 @@ var GROUPS = {
3526
3789
  description: "Item, lead, page number, and margin number tags"
3527
3790
  },
3528
3791
  {
3792
+ exportJsonKey: { instruction: "$" },
3529
3793
  key: ConfigKey.tag_instruction,
3530
3794
  name: "Instruction",
3531
3795
  description: "The instruction for the bit"
3532
3796
  },
3533
3797
  {
3798
+ exportJsonKey: { hint: "$" },
3534
3799
  key: ConfigKey.tag_hint,
3535
3800
  name: "Hint",
3536
3801
  description: "The hint for the bit"
@@ -3550,9 +3815,17 @@ var GROUPS = {
3550
3815
  description: "Item, lead, page number, margin number, instruction and hint tags"
3551
3816
  },
3552
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).
3553
3821
  key: ConfigKey.property_example,
3822
+ exportJsonKey: [
3823
+ { "@keyonly": { isExample: true } },
3824
+ { "@absent": { isExample: true } },
3825
+ { isExample: true, example: "$" }
3826
+ ],
3554
3827
  description: "The example(s) for the bit",
3555
- format: TagFormat.plainText
3828
+ format: TagFormat.bitmarkText
3556
3829
  }
3557
3830
  ]
3558
3831
  },
@@ -3563,6 +3836,7 @@ var GROUPS = {
3563
3836
  {
3564
3837
  key: ConfigKey.property_imageSource,
3565
3838
  jsonKey: "imageSource.url",
3839
+ exportJsonKey: { imageSource: { url: "$" } },
3566
3840
  description: "The source of an image",
3567
3841
  format: TagFormat.plainText,
3568
3842
  chain: [
@@ -3597,6 +3871,7 @@ var GROUPS = {
3597
3871
  {
3598
3872
  key: ConfigKey.property_technicalTerm,
3599
3873
  jsonKey: "technicalTerm.technicalTerm",
3874
+ exportJsonKey: { technicalTerm: { technicalTerm: "$" } },
3600
3875
  description: "The technical term",
3601
3876
  format: TagFormat.plainText,
3602
3877
  chain: [
@@ -3615,7 +3890,8 @@ var GROUPS = {
3615
3890
  tags: [
3616
3891
  {
3617
3892
  key: ConfigKey.property_person,
3618
- jsonKey: "person.name",
3893
+ jsonKey: "partner.name",
3894
+ exportJsonKey: { partner: { name: "$" } },
3619
3895
  description: "A person",
3620
3896
  format: TagFormat.plainText,
3621
3897
  chain: [
@@ -3626,6 +3902,8 @@ var GROUPS = {
3626
3902
  },
3627
3903
  {
3628
3904
  key: ConfigKey.group_resourceImage,
3905
+ jsonKey: "avatarImage|resource(type=image, key=image)",
3906
+ exportJsonKey: { avatarImage: { type: "image", image: { src: "$" } } },
3629
3907
  description: "The image of the person"
3630
3908
  }
3631
3909
  ]
@@ -3634,6 +3912,7 @@ var GROUPS = {
3634
3912
  // Deprecated (parter renamed to person)
3635
3913
  key: ConfigKey.property_partner,
3636
3914
  jsonKey: "partner.name",
3915
+ exportJsonKey: { partner: { name: "$" } },
3637
3916
  description: "A partner",
3638
3917
  format: TagFormat.plainText,
3639
3918
  chain: [
@@ -3644,6 +3923,8 @@ var GROUPS = {
3644
3923
  },
3645
3924
  {
3646
3925
  key: ConfigKey.group_resourceImage,
3926
+ jsonKey: "avatarImage|resource(type=image, key=image)",
3927
+ exportJsonKey: { avatarImage: { type: "image", image: { src: "$" } } },
3647
3928
  description: "The image of the partner"
3648
3929
  }
3649
3930
  ]
@@ -3655,15 +3936,19 @@ var GROUPS = {
3655
3936
  description: "Gap chain",
3656
3937
  tags: [
3657
3938
  {
3939
+ exportJsonKey: { solutions: [["$"]] },
3658
3940
  key: ConfigKey.tag_gap,
3659
3941
  description: "The value of a gap in the content",
3660
3942
  maxCount: Count.infinity,
3943
+ format: TagFormat.plainText,
3661
3944
  chain: [
3662
3945
  {
3663
3946
  key: ConfigKey.tag_gap,
3664
3947
  jsonKey: "solutions[]",
3948
+ exportJsonKey: { solutions: ["$"] },
3665
3949
  description: "Alternative values for the gaps in the content",
3666
- maxCount: Count.infinity
3950
+ maxCount: Count.infinity,
3951
+ format: TagFormat.plainText
3667
3952
  },
3668
3953
  {
3669
3954
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -3672,12 +3957,33 @@ var GROUPS = {
3672
3957
  {
3673
3958
  key: ConfigKey.property_example,
3674
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
+ ],
3675
3977
  description: "An example for the gap",
3676
- format: TagFormat.plainText
3978
+ format: TagFormat.bitmarkText
3677
3979
  },
3678
3980
  {
3679
3981
  key: ConfigKey.property_isCaseSensitive,
3680
3982
  jsonKey: "isCaseSensitive",
3983
+ exportJsonKey: [
3984
+ { "@absent": { isCaseSensitive: "$ancestor" } },
3985
+ { isCaseSensitive: "$" }
3986
+ ],
3681
3987
  description: "If true, the gap text is case sensitive",
3682
3988
  format: TagFormat.boolean,
3683
3989
  defaultValue: "true"
@@ -3691,21 +3997,27 @@ var GROUPS = {
3691
3997
  description: "True/False chain",
3692
3998
  tags: [
3693
3999
  {
4000
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: true }] },
3694
4001
  key: ConfigKey.tag_true,
3695
4002
  description: "True value for a true/false statement/question",
3696
4003
  maxCount: Count.infinity,
4004
+ format: TagFormat.plainText,
3697
4005
  chain: [
3698
4006
  {
3699
4007
  key: ConfigKey.tag_true,
3700
4008
  jsonKey: "choices[]|set(isCorrect=true)",
4009
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: true }] },
3701
4010
  description: "True values for a true/false statement/question",
3702
- maxCount: Count.infinity
4011
+ maxCount: Count.infinity,
4012
+ format: TagFormat.plainText
3703
4013
  },
3704
4014
  {
3705
4015
  key: ConfigKey.tag_false,
3706
4016
  jsonKey: "choices[]|set(isCorrect=false)",
4017
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
3707
4018
  description: "False values for a true/false statement/question",
3708
- maxCount: Count.infinity
4019
+ maxCount: Count.infinity,
4020
+ format: TagFormat.plainText
3709
4021
  },
3710
4022
  {
3711
4023
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -3714,27 +4026,50 @@ var GROUPS = {
3714
4026
  {
3715
4027
  key: ConfigKey.property_example,
3716
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
+ ],
3717
4046
  description: "An example for the true/false statement/question",
3718
- format: TagFormat.plainText
4047
+ format: TagFormat.bitmarkText
3719
4048
  }
3720
4049
  ]
3721
4050
  },
3722
4051
  {
4052
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
3723
4053
  key: ConfigKey.tag_false,
3724
4054
  description: "False value for a true/false statement/question",
3725
4055
  maxCount: Count.infinity,
4056
+ format: TagFormat.plainText,
3726
4057
  chain: [
3727
4058
  {
3728
4059
  key: ConfigKey.tag_true,
3729
4060
  jsonKey: "choices[]|set(isCorrect=true)",
4061
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: true }] },
3730
4062
  description: "True values for a true/false statement/question",
3731
- maxCount: Count.infinity
4063
+ maxCount: Count.infinity,
4064
+ format: TagFormat.plainText
3732
4065
  },
3733
4066
  {
3734
4067
  key: ConfigKey.tag_false,
3735
4068
  jsonKey: "choices[]|set(isCorrect=false)",
4069
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
3736
4070
  description: "False values for a true/false statement/question",
3737
- maxCount: Count.infinity
4071
+ maxCount: Count.infinity,
4072
+ format: TagFormat.plainText
3738
4073
  },
3739
4074
  {
3740
4075
  key: ConfigKey.group_standardItemLeadInstructionHint,
@@ -3743,8 +4078,25 @@ var GROUPS = {
3743
4078
  {
3744
4079
  key: ConfigKey.property_example,
3745
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
+ ],
3746
4098
  description: "An example for the true/false statement/question",
3747
- format: TagFormat.plainText
4099
+ format: TagFormat.bitmarkText
3748
4100
  }
3749
4101
  ]
3750
4102
  }
@@ -3757,6 +4109,7 @@ var GROUPS = {
3757
4109
  {
3758
4110
  key: ConfigKey.property_mark,
3759
4111
  jsonKey: "marks.mark",
4112
+ exportJsonKey: { marks: { mark: ["$"] } },
3760
4113
  description: "The mark configuration",
3761
4114
  format: TagFormat.plainText,
3762
4115
  maxCount: Count.infinity,
@@ -3780,9 +4133,11 @@ var GROUPS = {
3780
4133
  description: "Mark chain",
3781
4134
  tags: [
3782
4135
  {
4136
+ exportJsonKey: { solution: ["$"] },
3783
4137
  key: ConfigKey.tag_mark,
3784
4138
  description: "The marked content",
3785
4139
  maxCount: Count.infinity,
4140
+ format: TagFormat.plainText,
3786
4141
  chain: [
3787
4142
  {
3788
4143
  key: ConfigKey.property_mark,
@@ -3793,8 +4148,13 @@ var GROUPS = {
3793
4148
  {
3794
4149
  key: ConfigKey.property_example,
3795
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
+ ],
3796
4156
  description: "An example for the marked content",
3797
- format: TagFormat.plainText
4157
+ format: TagFormat.bitmarkText
3798
4158
  }
3799
4159
  ]
3800
4160
  }
@@ -3882,7 +4242,9 @@ var GROUPS = {
3882
4242
  key: ConfigKey.tag_title,
3883
4243
  name: "Title",
3884
4244
  description: "The title of the book",
3885
- maxCount: 2
4245
+ maxCount: 2,
4246
+ jsonKey: "title|multi(count=2, key=subtitle)",
4247
+ exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
3886
4248
  },
3887
4249
  {
3888
4250
  key: ConfigKey.property_subtype,
@@ -3897,6 +4259,8 @@ var GROUPS = {
3897
4259
  },
3898
4260
  {
3899
4261
  key: ConfigKey.resource_coverImage,
4262
+ jsonKey: "coverImage|resource(type=image, key=image)",
4263
+ exportJsonKey: { coverImage: { type: "image", image: { src: "$" } } },
3900
4264
  description: "The cover image of the book",
3901
4265
  chain: [
3902
4266
  {
@@ -3913,6 +4277,8 @@ var GROUPS = {
3913
4277
  },
3914
4278
  {
3915
4279
  key: ConfigKey.resource_backgroundImage,
4280
+ jsonKey: "backgroundImage|resource(type=image, key=image)",
4281
+ exportJsonKey: { backgroundImage: { type: "image", image: { src: "$" } } },
3916
4282
  description: "The background image of the book",
3917
4283
  chain: [
3918
4284
  {
@@ -4072,9 +4438,21 @@ var GROUPS = {
4072
4438
  format: TagFormat.plainText,
4073
4439
  chain: [
4074
4440
  {
4441
+ exportJsonKey: { reference: "$" },
4075
4442
  key: ConfigKey.tag_reference,
4076
- description: "The reference(s) for the book(s) in the learning path",
4077
- maxCount: 2
4443
+ format: TagFormat.plainText,
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
+ ]
4078
4456
  }
4079
4457
  ]
4080
4458
  }
@@ -4214,6 +4592,8 @@ var GROUPS = {
4214
4592
  tags: [
4215
4593
  {
4216
4594
  key: ConfigKey.resource_imagePlaceholder,
4595
+ jsonKey: "imagePlaceholder|resource(type=image, key=image)",
4596
+ exportJsonKey: { imagePlaceholder: { type: "image", image: { src: "$" } } },
4217
4597
  description: "Placeholder image for the resource",
4218
4598
  chain: [
4219
4599
  {
@@ -4398,6 +4778,7 @@ var GROUPS = {
4398
4778
  {
4399
4779
  key: ConfigKey.property_posterImage,
4400
4780
  jsonKey: "posterImage.src",
4781
+ exportJsonKey: { posterImage: { src: "$" } },
4401
4782
  description: "The poster image for the video",
4402
4783
  format: TagFormat.plainText,
4403
4784
  chain: [
@@ -4454,6 +4835,7 @@ var GROUPS = {
4454
4835
  tags: [
4455
4836
  {
4456
4837
  key: ConfigKey.resource_image,
4838
+ exportJsonKey: { resource: { type: "image", image: { src: "$" } } },
4457
4839
  description: "The image resource",
4458
4840
  chain: [
4459
4841
  {
@@ -4518,6 +4900,7 @@ var GROUPS = {
4518
4900
  tags: [
4519
4901
  {
4520
4902
  key: ConfigKey.resource_imageLink,
4903
+ exportJsonKey: { resource: { type: "image-link", imageLink: { url: "$" } } },
4521
4904
  description: "The link to the image resource",
4522
4905
  chain: [
4523
4906
  {
@@ -4534,6 +4917,7 @@ var GROUPS = {
4534
4917
  tags: [
4535
4918
  {
4536
4919
  key: ConfigKey.resource_audio,
4920
+ exportJsonKey: { resource: { type: "audio", audio: { src: "$" } } },
4537
4921
  description: "The audio resource",
4538
4922
  chain: [
4539
4923
  {
@@ -4550,6 +4934,7 @@ var GROUPS = {
4550
4934
  tags: [
4551
4935
  {
4552
4936
  key: ConfigKey.resource_audioEmbed,
4937
+ exportJsonKey: { resource: { type: "audio-embed", audioEmbed: { src: "$" } } },
4553
4938
  description: "The embedded audio resource",
4554
4939
  chain: [
4555
4940
  {
@@ -4566,6 +4951,7 @@ var GROUPS = {
4566
4951
  tags: [
4567
4952
  {
4568
4953
  key: ConfigKey.resource_audioLink,
4954
+ exportJsonKey: { resource: { type: "audio-link", audioLink: { url: "$" } } },
4569
4955
  description: "The link to the audio resource",
4570
4956
  chain: [
4571
4957
  {
@@ -4582,6 +4968,7 @@ var GROUPS = {
4582
4968
  tags: [
4583
4969
  {
4584
4970
  key: ConfigKey.resource_video,
4971
+ exportJsonKey: { resource: { type: "video", video: { src: "$" } } },
4585
4972
  description: "The video resource",
4586
4973
  chain: [
4587
4974
  {
@@ -4598,6 +4985,7 @@ var GROUPS = {
4598
4985
  tags: [
4599
4986
  {
4600
4987
  key: ConfigKey.resource_videoEmbed,
4988
+ exportJsonKey: { resource: { type: "video-embed", videoEmbed: { url: "$" } } },
4601
4989
  description: "The embedded video resource",
4602
4990
  chain: [
4603
4991
  {
@@ -4614,6 +5002,7 @@ var GROUPS = {
4614
5002
  tags: [
4615
5003
  {
4616
5004
  key: ConfigKey.resource_videoLink,
5005
+ exportJsonKey: { resource: { type: "video-link", videoLink: { url: "$" } } },
4617
5006
  description: "The link to the video resource",
4618
5007
  chain: [
4619
5008
  {
@@ -4630,6 +5019,9 @@ var GROUPS = {
4630
5019
  tags: [
4631
5020
  {
4632
5021
  key: ConfigKey.resource_stillImageFilmEmbed,
5022
+ exportJsonKey: {
5023
+ resource: { type: "still-image-film-embed", stillImageFilmEmbed: { url: "$" } }
5024
+ },
4633
5025
  description: "The embedded still image film resource",
4634
5026
  chain: [
4635
5027
  {
@@ -4646,6 +5038,9 @@ var GROUPS = {
4646
5038
  tags: [
4647
5039
  {
4648
5040
  key: ConfigKey.resource_stillImageFilmLink,
5041
+ exportJsonKey: {
5042
+ resource: { type: "still-image-film-link", stillImageFilmLink: { url: "$" } }
5043
+ },
4649
5044
  description: "The link to the still image film resource",
4650
5045
  chain: [
4651
5046
  {
@@ -4710,6 +5105,7 @@ var GROUPS = {
4710
5105
  tags: [
4711
5106
  {
4712
5107
  key: ConfigKey.resource_document,
5108
+ exportJsonKey: { resource: { type: "document", document: { url: "$" } } },
4713
5109
  description: "The document resource",
4714
5110
  chain: [
4715
5111
  {
@@ -4726,6 +5122,7 @@ var GROUPS = {
4726
5122
  tags: [
4727
5123
  {
4728
5124
  key: ConfigKey.resource_documentEmbed,
5125
+ exportJsonKey: { resource: { type: "document-embed", documentEmbed: { url: "$" } } },
4729
5126
  description: "The embedded document resource",
4730
5127
  chain: [
4731
5128
  {
@@ -4742,6 +5139,7 @@ var GROUPS = {
4742
5139
  tags: [
4743
5140
  {
4744
5141
  key: ConfigKey.resource_documentLink,
5142
+ exportJsonKey: { resource: { type: "document-link", documentLink: { url: "$" } } },
4745
5143
  description: "The link to the document resource",
4746
5144
  chain: [
4747
5145
  {
@@ -4758,6 +5156,7 @@ var GROUPS = {
4758
5156
  tags: [
4759
5157
  {
4760
5158
  key: ConfigKey.resource_documentDownload,
5159
+ exportJsonKey: { resource: { type: "document-download", documentDownload: { url: "$" } } },
4761
5160
  description: "The downloadable document resource",
4762
5161
  chain: [
4763
5162
  {
@@ -4774,6 +5173,7 @@ var GROUPS = {
4774
5173
  tags: [
4775
5174
  {
4776
5175
  key: ConfigKey.resource_appLink,
5176
+ exportJsonKey: { resource: { type: "app-link", appLink: { url: "$" } } },
4777
5177
  description: "The link to the app resource",
4778
5178
  chain: [
4779
5179
  {
@@ -4790,6 +5190,7 @@ var GROUPS = {
4790
5190
  tags: [
4791
5191
  {
4792
5192
  key: ConfigKey.resource_websiteLink,
5193
+ exportJsonKey: { resource: { type: "website-link", websiteLink: { url: "$" } } },
4793
5194
  description: "The link to the website resource",
4794
5195
  chain: [
4795
5196
  {
@@ -4847,6 +5248,8 @@ var GROUPS = {
4847
5248
  tags: [
4848
5249
  {
4849
5250
  key: ConfigKey.resource_previewImage,
5251
+ jsonKey: "previewImage|resource(type=image, key=image)",
5252
+ exportJsonKey: { previewImage: { type: "image", image: { src: "$" } } },
4850
5253
  description: "The preview image resource",
4851
5254
  chain: [
4852
5255
  {
@@ -4863,6 +5266,8 @@ var GROUPS = {
4863
5266
  tags: [
4864
5267
  {
4865
5268
  key: ConfigKey.resource_previewVideo,
5269
+ jsonKey: "previewVideo|resource(type=video, key=video)",
5270
+ exportJsonKey: { previewVideo: { type: "video", video: { src: "$" } } },
4866
5271
  description: "The preview video resource",
4867
5272
  chain: [
4868
5273
  {
@@ -4927,20 +5332,48 @@ var ConfigHydrator = class {
4927
5332
  _side.name,
4928
5333
  _side.repeat ?? false,
4929
5334
  variantsOfSide,
4930
- _side.jsonKey
5335
+ _side.jsonKey,
5336
+ _side.exportJsonKey,
5337
+ Object.prototype.hasOwnProperty.call(_side, "exportJsonKey")
4931
5338
  );
4932
5339
  sides.push(sideConfig);
4933
5340
  }
4934
5341
  const cardSetConfig = new CardSetConfig(
4935
5342
  _cardSet,
4936
5343
  _cardSetConfig.jsonKey,
4937
- _cardSetConfig.sections,
5344
+ _cardSetConfig.exportJsonKey,
5345
+ Object.prototype.hasOwnProperty.call(_cardSetConfig, "exportJsonKey"),
5346
+ this.hydrateCardSections(_cardSetConfig.sections),
4938
5347
  sides
4939
5348
  );
4940
5349
  return cardSetConfig;
4941
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
+ }
4942
5367
  hydrateTagConfig(_tag) {
4943
- 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;
4944
5377
  const configKey = (0, import_superenum15.Enum)(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
4945
5378
  if (!configKey) throw new Error(`No tag key found for config key '${configKey}'`);
4946
5379
  const tag = (0, import_superenum15.Enum)(Tag).fromValue(configKey);
@@ -4955,6 +5388,9 @@ var ConfigHydrator = class {
4955
5388
  maxCount: maxCount ?? MAX_COUNT_DEFAULT,
4956
5389
  minCount: minCount ?? MIN_COUNT_DEFAULT,
4957
5390
  chain,
5391
+ jsonKey,
5392
+ exportJsonKey,
5393
+ hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
4958
5394
  deprecated
4959
5395
  });
4960
5396
  return {
@@ -4973,7 +5409,8 @@ var ConfigHydrator = class {
4973
5409
  format,
4974
5410
  values,
4975
5411
  defaultValue,
4976
- jsonKey
5412
+ jsonKey,
5413
+ exportJsonKey
4977
5414
  } = _tag;
4978
5415
  const configKey = (0, import_superenum15.Enum)(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
4979
5416
  if (!configKey) throw new Error(`No property key found for config key '${configKey}'`);
@@ -4989,6 +5426,8 @@ var ConfigHydrator = class {
4989
5426
  minCount: minCount ?? MIN_COUNT_DEFAULT,
4990
5427
  chain,
4991
5428
  jsonKey,
5429
+ exportJsonKey,
5430
+ hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
4992
5431
  format,
4993
5432
  values,
4994
5433
  defaultValue,
@@ -5001,7 +5440,15 @@ var ConfigHydrator = class {
5001
5440
  };
5002
5441
  }
5003
5442
  hydrateResourceTagConfig(_tag) {
5004
- 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;
5005
5452
  const configKey = (0, import_superenum15.Enum)(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
5006
5453
  if (!configKey) throw new Error(`No resource key found for config key '${configKey}'`);
5007
5454
  const tag = _configKey.substring(1);
@@ -5016,6 +5463,8 @@ var ConfigHydrator = class {
5016
5463
  minCount: minCount ?? MIN_COUNT_DEFAULT,
5017
5464
  chain,
5018
5465
  jsonKey,
5466
+ exportJsonKey,
5467
+ hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
5019
5468
  deprecated
5020
5469
  });
5021
5470
  return {
@@ -5047,14 +5496,25 @@ var ConfigHydrator = class {
5047
5496
  };
5048
5497
  }
5049
5498
  hydrateCardVariantConfig(_variant) {
5050
- 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;
5051
5508
  const tags2 = this.hydrateTagsConfig(_tags);
5052
5509
  const cardSetConfig = new CardVariantConfig(
5053
5510
  tags2.tags,
5054
5511
  bodyAllowed,
5055
5512
  bodyRequired,
5056
5513
  repeatCount,
5057
- jsonKey
5514
+ jsonKey,
5515
+ exportJsonKey,
5516
+ Object.prototype.hasOwnProperty.call(_variant, "exportJsonKey"),
5517
+ format
5058
5518
  );
5059
5519
  return cardSetConfig;
5060
5520
  }
@@ -5092,6 +5552,7 @@ var BITS = {
5092
5552
  description: "Common tags for quiz bits"
5093
5553
  },
5094
5554
  {
5555
+ exportJsonKey: { title: "$" },
5095
5556
  key: ConfigKey.tag_title,
5096
5557
  description: "The title of the flashcard quiz"
5097
5558
  },
@@ -5100,6 +5561,20 @@ var BITS = {
5100
5561
  description: "The flashcard set to use for the app flashcards",
5101
5562
  format: TagFormat.plainText,
5102
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
5103
5578
  }
5104
5579
  ],
5105
5580
  rootExampleType: ExampleType.string
@@ -5181,6 +5656,7 @@ var BITS = {
5181
5656
  description: "Article bit, used for articles / paragraphs",
5182
5657
  tags: [
5183
5658
  {
5659
+ exportJsonKey: { title: "$" },
5184
5660
  key: ConfigKey.tag_title,
5185
5661
  description: "The title of the article"
5186
5662
  }
@@ -5287,7 +5763,9 @@ var BITS = {
5287
5763
  {
5288
5764
  key: ConfigKey.tag_title,
5289
5765
  description: "Title and subtitle of the catalog item",
5290
- maxCount: 2
5766
+ maxCount: 2,
5767
+ jsonKey: "title|multi(count=2, key=subtitle)",
5768
+ exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
5291
5769
  },
5292
5770
  {
5293
5771
  key: ConfigKey.property_coverImage,
@@ -5296,6 +5774,8 @@ var BITS = {
5296
5774
  },
5297
5775
  {
5298
5776
  key: ConfigKey.resource_coverImage,
5777
+ jsonKey: "coverImage|resource(type=image, key=image)",
5778
+ exportJsonKey: { coverImage: { type: "image", image: { src: "$" } } },
5299
5779
  description: "Cover image of the catalog item",
5300
5780
  chain: [
5301
5781
  {
@@ -5423,6 +5903,17 @@ var BITS = {
5423
5903
  key: ConfigKey.group_previewVideos,
5424
5904
  description: "Array of preview videos for the catalog item",
5425
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
5426
5917
  }
5427
5918
  ],
5428
5919
  rootExampleType: ExampleType.string
@@ -5435,7 +5926,9 @@ var BITS = {
5435
5926
  {
5436
5927
  key: ConfigKey.tag_title,
5437
5928
  description: "Title and subtitle of the catalog item",
5438
- maxCount: 2
5929
+ maxCount: 2,
5930
+ jsonKey: "title|multi(count=2, key=subtitle)",
5931
+ exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
5439
5932
  },
5440
5933
  {
5441
5934
  key: ConfigKey.property_coverImage,
@@ -5444,6 +5937,8 @@ var BITS = {
5444
5937
  },
5445
5938
  {
5446
5939
  key: ConfigKey.resource_coverImage,
5940
+ jsonKey: "coverImage|resource(type=image, key=image)",
5941
+ exportJsonKey: { coverImage: { type: "image", image: { src: "$" } } },
5447
5942
  description: "Cover image of the catalog item",
5448
5943
  chain: [
5449
5944
  {
@@ -5571,6 +6066,17 @@ var BITS = {
5571
6066
  key: ConfigKey.group_previewVideos,
5572
6067
  description: "Array of preview videos for the catalog item",
5573
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
5574
6080
  }
5575
6081
  ],
5576
6082
  rootExampleType: ExampleType.string
@@ -5583,7 +6089,9 @@ var BITS = {
5583
6089
  {
5584
6090
  key: ConfigKey.tag_title,
5585
6091
  description: "Title and subtitle of the catalog item",
5586
- maxCount: 2
6092
+ maxCount: 2,
6093
+ jsonKey: "title|multi(count=2, key=subtitle)",
6094
+ exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
5587
6095
  },
5588
6096
  {
5589
6097
  key: ConfigKey.property_coverImage,
@@ -5709,6 +6217,17 @@ var BITS = {
5709
6217
  key: ConfigKey.group_previewVideos,
5710
6218
  description: "Array of preview videos for the catalog item",
5711
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
5712
6231
  }
5713
6232
  ],
5714
6233
  rootExampleType: ExampleType.string
@@ -5910,11 +6429,15 @@ var BITS = {
5910
6429
  description: "Bit alias, used to create an alias for a bit",
5911
6430
  tags: [
5912
6431
  {
6432
+ exportJsonKey: { reference: "$" },
5913
6433
  key: ConfigKey.tag_reference,
6434
+ format: TagFormat.plainText,
5914
6435
  description: "The reference to the bit that this alias points to"
5915
6436
  },
5916
6437
  {
6438
+ exportJsonKey: { anchor: "$" },
5917
6439
  key: ConfigKey.tag_anchor,
6440
+ format: TagFormat.plainText,
5918
6441
  description: "The anchor for the bit alias, used for linking"
5919
6442
  }
5920
6443
  ]
@@ -6112,8 +6635,10 @@ var BITS = {
6112
6635
  {
6113
6636
  key: ConfigKey.tag_title,
6114
6637
  description: "The title of the book cover",
6115
- maxCount: 2
6638
+ maxCount: 2,
6116
6639
  // title & subtitle
6640
+ jsonKey: "title|multi(count=2, key=subtitle)",
6641
+ exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
6117
6642
  },
6118
6643
  {
6119
6644
  key: ConfigKey.property_coverColor,
@@ -6257,12 +6782,16 @@ var BITS = {
6257
6782
  description: "Chapter bit, used to define chapters in books or articles",
6258
6783
  tags: [
6259
6784
  {
6785
+ exportJsonKey: { anchor: "$" },
6260
6786
  key: ConfigKey.tag_anchor,
6787
+ format: TagFormat.plainText,
6261
6788
  description: "The anchor for the chapter, used for linking"
6262
6789
  },
6263
6790
  {
6264
6791
  key: ConfigKey.tag_title,
6265
- description: "The title of the chapter"
6792
+ description: "The title of the chapter",
6793
+ jsonKey: "title|setMulti(level)",
6794
+ exportJsonKey: { title: "$", level: "$level" }
6266
6795
  },
6267
6796
  {
6268
6797
  key: ConfigKey.property_toc,
@@ -6315,6 +6844,7 @@ var BITS = {
6315
6844
  },
6316
6845
  {
6317
6846
  key: ConfigKey.property_isCaseSensitive,
6847
+ exportJsonKey: {},
6318
6848
  description: "If the cloze answers are case sensitive",
6319
6849
  format: TagFormat.boolean,
6320
6850
  defaultValue: "true"
@@ -6412,6 +6942,11 @@ var BITS = {
6412
6942
  description: "Formula bit, used for mathematical formulas in articles or documents",
6413
6943
  textFormatDefault: TextFormat.latex
6414
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
+ },
6415
6950
  [BitType.smartStandardFormula]: {
6416
6951
  since: "3.11.0",
6417
6952
  baseBitType: BitType.formula,
@@ -6764,6 +7299,7 @@ var BITS = {
6764
7299
  {
6765
7300
  key: ConfigKey.property_servings,
6766
7301
  jsonKey: "servings.servings",
7302
+ exportJsonKey: { servings: { servings: "$" } },
6767
7303
  description: "The number of servings for the ingredients",
6768
7304
  format: TagFormat.number,
6769
7305
  chain: [
@@ -6789,8 +7325,10 @@ var BITS = {
6789
7325
  format: TagFormat.boolean
6790
7326
  },
6791
7327
  {
7328
+ exportJsonKey: { hint: "$" },
6792
7329
  key: ConfigKey.tag_hint,
6793
- description: "Hint for the ingredient, used to provide additional information"
7330
+ description: "Hint for the ingredient, used to provide additional information",
7331
+ format: TagFormat.plainText
6794
7332
  }
6795
7333
  ]
6796
7334
  }
@@ -6965,6 +7503,17 @@ var BITS = {
6965
7503
  description: "Reference for the essay, used to link to external resources",
6966
7504
  format: TagFormat.plainText,
6967
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
6968
7517
  }
6969
7518
  ],
6970
7519
  rootExampleType: ExampleType.string
@@ -6985,8 +7534,20 @@ var BITS = {
6985
7534
  description: "Example bit, used to provide examples in articles or books",
6986
7535
  tags: [
6987
7536
  {
7537
+ exportJsonKey: { title: "$" },
6988
7538
  key: ConfigKey.tag_title,
6989
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
6990
7551
  }
6991
7552
  ],
6992
7553
  rootExampleType: ExampleType.string
@@ -7852,6 +8413,7 @@ var BITS = {
7852
8413
  // Image resource
7853
8414
  key: ConfigKey.group_resourceImage,
7854
8415
  description: "Resource image tags for logo grave images, used to attach images",
8416
+ exportJsonKey: { images: "$" },
7855
8417
  minCount: 1,
7856
8418
  maxCount: Count.infinity
7857
8419
  }
@@ -8015,15 +8577,29 @@ var BITS = {
8015
8577
  format: TagFormat.plainText,
8016
8578
  chain: [
8017
8579
  {
8580
+ exportJsonKey: { reference: "$" },
8018
8581
  key: ConfigKey.tag_reference,
8582
+ format: TagFormat.plainText,
8019
8583
  description: "Reference tag for the book, used to link to the book in the system",
8020
- 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
+ ]
8021
8595
  }
8022
8596
  ]
8023
8597
  },
8024
8598
  {
8025
8599
  /* Allow incorrectly chained reference tag */
8600
+ exportJsonKey: { reference: "$" },
8026
8601
  key: ConfigKey.tag_reference,
8602
+ format: TagFormat.plainText,
8027
8603
  description: "Reference tag for the book, used to link to the book in the system"
8028
8604
  },
8029
8605
  {
@@ -8068,16 +8644,41 @@ var BITS = {
8068
8644
  format: TagFormat.plainText,
8069
8645
  chain: [
8070
8646
  {
8647
+ exportJsonKey: { reference: "$" },
8071
8648
  key: ConfigKey.tag_reference,
8649
+ format: TagFormat.plainText,
8072
8650
  description: "Reference tag for the book, used to link to the book in the system",
8073
- 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
+ ]
8074
8662
  }
8075
8663
  ]
8076
8664
  },
8077
8665
  {
8078
8666
  /* Allow incorrectly chained reference tag */
8667
+ exportJsonKey: { reference: "$" },
8079
8668
  key: ConfigKey.tag_reference,
8080
- description: "Reference tag for the book, used to link to the book in the system"
8669
+ format: TagFormat.plainText,
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
+ ]
8081
8682
  },
8082
8683
  {
8083
8684
  key: ConfigKey.property_buttonCaption,
@@ -8106,9 +8707,21 @@ var BITS = {
8106
8707
  maxCount: Count.infinity,
8107
8708
  chain: [
8108
8709
  {
8710
+ exportJsonKey: { reference: "$" },
8109
8711
  key: ConfigKey.tag_reference,
8712
+ format: TagFormat.plainText,
8110
8713
  description: "Reference tag for the book, used to link to the book in the system",
8111
- 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
+ ]
8112
8725
  }
8113
8726
  ]
8114
8727
  },
@@ -8275,6 +8888,7 @@ var BITS = {
8275
8888
  tags: [
8276
8889
  {
8277
8890
  key: ConfigKey.resource_backgroundWallpaper,
8891
+ exportJsonKey: { backgroundWallpaper: { type: "image", image: { src: "$" } } },
8278
8892
  description: "Background wallpaper for the image, used to set a background for the image",
8279
8893
  chain: [
8280
8894
  {
@@ -8457,6 +9071,7 @@ var BITS = {
8457
9071
  },
8458
9072
  {
8459
9073
  key: ConfigKey.resource_backgroundWallpaper,
9074
+ exportJsonKey: { backgroundWallpaper: { type: "image", image: { src: "$" } } },
8460
9075
  description: "Background wallpaper for the image, used to set a background for the image",
8461
9076
  chain: [
8462
9077
  {
@@ -8609,6 +9224,7 @@ var BITS = {
8609
9224
  // Image resource
8610
9225
  key: ConfigKey.group_resourceImage,
8611
9226
  description: "Resource image tags for logo grave images, used to attach images",
9227
+ exportJsonKey: { logos: "$" },
8612
9228
  minCount: 1,
8613
9229
  maxCount: Count.infinity
8614
9230
  }
@@ -8626,7 +9242,9 @@ var BITS = {
8626
9242
  description: "Internal link bit, used to create links to other bits in articles or books",
8627
9243
  tags: [
8628
9244
  {
9245
+ exportJsonKey: { reference: "$" },
8629
9246
  key: ConfigKey.tag_reference,
9247
+ format: TagFormat.plainText,
8630
9248
  description: "Reference tag for the internal link, used to link to the target bit"
8631
9249
  }
8632
9250
  ]
@@ -8643,6 +9261,7 @@ var BITS = {
8643
9261
  },
8644
9262
  {
8645
9263
  key: ConfigKey.property_reasonableNumOfChars,
9264
+ exportJsonKey: {},
8646
9265
  description: "Reasonable number of characters for the interview, used to limit input size",
8647
9266
  format: TagFormat.number
8648
9267
  }
@@ -9018,6 +9637,7 @@ var BITS = {
9018
9637
  },
9019
9638
  {
9020
9639
  key: ConfigKey.property_isCaseSensitive,
9640
+ exportJsonKey: {},
9021
9641
  description: "Case sensitivity for matching pairs, used to define if matches are case-sensitive",
9022
9642
  format: TagFormat.boolean,
9023
9643
  defaultValue: "true"
@@ -9070,6 +9690,7 @@ var BITS = {
9070
9690
  tags: [
9071
9691
  {
9072
9692
  key: ConfigKey.property_reasonableNumOfChars,
9693
+ exportJsonKey: {},
9073
9694
  description: "Reasonable number of characters for feedback, used to limit input size",
9074
9695
  format: TagFormat.number
9075
9696
  }
@@ -9211,6 +9832,7 @@ var BITS = {
9211
9832
  description: "Page bit, used to create pages in articles or books",
9212
9833
  tags: [
9213
9834
  {
9835
+ exportJsonKey: { title: "$" },
9214
9836
  key: ConfigKey.tag_title,
9215
9837
  description: "Title of the page, used to display the page title"
9216
9838
  },
@@ -9569,6 +10191,8 @@ var BITS = {
9569
10191
  },
9570
10192
  {
9571
10193
  key: ConfigKey.resource_platformBackgroundImage,
10194
+ jsonKey: "platformBackgroundImage|resource(type=image, key=image)",
10195
+ exportJsonKey: { platformBackgroundImage: { type: "image", image: { src: "$" } } },
9572
10196
  description: "The platform section chat background image",
9573
10197
  chain: [
9574
10198
  {
@@ -9662,6 +10286,7 @@ var BITS = {
9662
10286
  description: "Review note bit, used to create review notes in articles or books",
9663
10287
  tags: [
9664
10288
  {
10289
+ exportJsonKey: { title: "$" },
9665
10290
  key: ConfigKey.tag_title,
9666
10291
  description: "Title of the review note, used to display the note title"
9667
10292
  },
@@ -9680,6 +10305,17 @@ var BITS = {
9680
10305
  key: ConfigKey.property_resolvedBy,
9681
10306
  description: "Resolved by for the review note, used to define who resolved the note",
9682
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
9683
10319
  }
9684
10320
  ],
9685
10321
  rootExampleType: ExampleType.string
@@ -9732,11 +10368,15 @@ var BITS = {
9732
10368
  tags: [
9733
10369
  // Not sure if these are actually valid here, but include them as they are in the test bit.
9734
10370
  {
10371
+ exportJsonKey: { anchor: "$" },
9735
10372
  key: ConfigKey.tag_anchor,
10373
+ format: TagFormat.plainText,
9736
10374
  description: "Anchor for the sample solution, used to link to the solution"
9737
10375
  },
9738
10376
  {
10377
+ exportJsonKey: { reference: "$" },
9739
10378
  key: ConfigKey.tag_reference,
10379
+ format: TagFormat.plainText,
9740
10380
  description: "Reference for the sample solution, used to link to the source of the solution"
9741
10381
  }
9742
10382
  ]
@@ -9750,6 +10390,19 @@ var BITS = {
9750
10390
  {
9751
10391
  key: ConfigKey.group_quizCommon,
9752
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
9753
10406
  }
9754
10407
  ],
9755
10408
  cardSet: CardSetConfigKey.elements,
@@ -9857,6 +10510,7 @@ var BITS = {
9857
10510
  {
9858
10511
  key: ConfigKey.property_ratingLevelStart,
9859
10512
  jsonKey: "ratingLevelStart.level",
10513
+ exportJsonKey: { ratingLevelStart: { level: "$" } },
9860
10514
  description: "Start level for the rating survey, used to define the lowest rating",
9861
10515
  format: TagFormat.number,
9862
10516
  chain: [
@@ -9870,6 +10524,7 @@ var BITS = {
9870
10524
  {
9871
10525
  key: ConfigKey.property_ratingLevelEnd,
9872
10526
  jsonKey: "ratingLevelEnd.level",
10527
+ exportJsonKey: { ratingLevelEnd: { level: "$" } },
9873
10528
  description: "End level for the rating survey, used to define the highest rating",
9874
10529
  format: TagFormat.number,
9875
10530
  chain: [
@@ -10022,6 +10677,7 @@ var BITS = {
10022
10677
  },
10023
10678
  {
10024
10679
  key: ConfigKey.resource_backgroundWallpaper,
10680
+ exportJsonKey: { backgroundWallpaper: { type: "image", image: { src: "$" } } },
10025
10681
  description: "Background wallpaper for the image, used to set a background for the image",
10026
10682
  chain: [
10027
10683
  {
@@ -10405,12 +11061,34 @@ var BITS = {
10405
11061
  format: TagFormat.plainText
10406
11062
  },
10407
11063
  {
11064
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: true }] },
10408
11065
  key: ConfigKey.tag_true,
10409
- 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
10410
11068
  },
10411
11069
  {
11070
+ exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
10412
11071
  key: ConfigKey.tag_false,
10413
- 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
10414
11092
  }
10415
11093
  ],
10416
11094
  rootExampleType: ExampleType.boolean
@@ -10618,6 +11296,25 @@ var BITS = {
10618
11296
  baseBitType: BitType.vendorStripePricingTable,
10619
11297
  description: "External Stripe pricing table bit, used to embed external Stripe pricing tables in articles or books"
10620
11298
  },
11299
+ [BitType.vendorStripePricingTablePrintOnRequest]: {
11300
+ since: "5.21.0",
11301
+ baseBitType: BitType.vendorStripePricingTable,
11302
+ description: "Stripe pricing table bit with print-on-request customer/product IDs, used to embed Stripe pricing tables tied to a specific print-on-request customer and product",
11303
+ tags: [
11304
+ {
11305
+ key: ConfigKey.property_printOnRequestCustomerId,
11306
+ description: "Print-on-request customer ID, used to identify the customer for the print-on-request flow",
11307
+ format: TagFormat.plainText,
11308
+ minCount: 1
11309
+ },
11310
+ {
11311
+ key: ConfigKey.property_printOnRequestProductId,
11312
+ description: "Print-on-request product ID, used to identify the product for the print-on-request flow",
11313
+ format: TagFormat.plainText,
11314
+ minCount: 1
11315
+ }
11316
+ ]
11317
+ },
10621
11318
  [BitType.video]: {
10622
11319
  since: "1.3.0",
10623
11320
  baseBitType: BitType._standard,
@@ -10974,6 +11671,8 @@ var Config = class {
10974
11671
  maxCount: 1,
10975
11672
  chain: tag.chain,
10976
11673
  jsonKey: tag.jsonKey,
11674
+ exportJsonKey: tag.exportJsonKey,
11675
+ hasExportJsonKey: tag.hasExportJsonKey,
10977
11676
  deprecated: tag.deprecated
10978
11677
  });
10979
11678
  finalResourceTags[k] = newTag;
@@ -11078,7 +11777,7 @@ var instance2 = new Config();
11078
11777
  // src/generated/package_info.ts
11079
11778
  var PACKAGE_INFO = {
11080
11779
  "name": "@gmb/bitmark-parser-generator",
11081
- "version": "5.21.0",
11780
+ "version": "5.23.0",
11082
11781
  "author": "Get More Brain Ltd",
11083
11782
  "license": "ISC",
11084
11783
  "description": "A bitmark parser and generator using Peggy.js"
@@ -11672,6 +12371,8 @@ var NodeType = {
11672
12371
  gmbExternalShopItems: "gmbExternalShopItems",
11673
12372
  groupTag: "groupTag",
11674
12373
  groupTagValue: "groupTagValue",
12374
+ gUri: "gUri",
12375
+ gUriValue: "gUriValue",
11675
12376
  handInAcceptFileType: "handInAcceptFileType",
11676
12377
  handInAcceptFileTypeValue: "handInAcceptFileTypeValue",
11677
12378
  handInInstruction: "handInInstruction",
@@ -11893,6 +12594,10 @@ var NodeType = {
11893
12594
  previewVideoValue: "previewVideoValue",
11894
12595
  printParentChapterLevel: "printParentChapterLevel",
11895
12596
  printParentChapterLevelValue: "printParentChapterLevelValue",
12597
+ printOnRequestCustomerId: "printOnRequestCustomerId",
12598
+ printOnRequestCustomerIdValue: "printOnRequestCustomerIdValue",
12599
+ printOnRequestProductId: "printOnRequestProductId",
12600
+ printOnRequestProductIdValue: "printOnRequestProductIdValue",
11896
12601
  processHandIn: "processHandIn",
11897
12602
  processHandInLocation: "processHandInLocation",
11898
12603
  processHandInLocationValue: "processHandInLocationValue",
@@ -12010,6 +12715,8 @@ var NodeType = {
12010
12715
  solution: "solution",
12011
12716
  solutions: "solutions",
12012
12717
  solutionsValue: "solutionsValue",
12718
+ sourceBB: "sourceBB",
12719
+ sourceBBValue: "sourceBBValue",
12013
12720
  sourceDocument: "sourceDocument",
12014
12721
  sourceDocumentValue: "sourceDocumentValue",
12015
12722
  sourceRL: "sourceRL",
@@ -12647,6 +13354,17 @@ function convertBasicToExtendedTableFormat(table) {
12647
13354
  }))
12648
13355
  };
12649
13356
  }
13357
+ if (Array.isArray(table.columnWidths) && table.columnWidths.length > 0) {
13358
+ const targetCells = tableExtended.header?.rows[0]?.cells ?? tableExtended.body?.rows[0]?.cells;
13359
+ if (targetCells) {
13360
+ for (let i = 0; i < table.columnWidths.length; i++) {
13361
+ const width = table.columnWidths[i];
13362
+ if (typeof width === "number" && width > 0 && targetCells[i]) {
13363
+ targetCells[i].colwidth = width;
13364
+ }
13365
+ }
13366
+ }
13367
+ }
12650
13368
  return tableExtended;
12651
13369
  }
12652
13370
  function convertExtendedToBasicTableFormat(tableExtended) {
@@ -12658,7 +13376,23 @@ function convertExtendedToBasicTableFormat(tableExtended) {
12658
13376
  return row.cells.map((cell) => cell?.content).filter((content) => content !== void 0);
12659
13377
  };
12660
13378
  const dataRows = [];
13379
+ const widths = [];
13380
+ let hasAnyWidth = false;
13381
+ let maxCellCount = 0;
13382
+ const collectWidths = (cells) => {
13383
+ if (!cells) return;
13384
+ if (cells.length > maxCellCount) maxCellCount = cells.length;
13385
+ cells.forEach((cell, idx) => {
13386
+ if (cell && typeof cell.colwidth === "number" && cell.colwidth > 0) {
13387
+ widths[idx] = cell.colwidth;
13388
+ hasAnyWidth = true;
13389
+ }
13390
+ });
13391
+ };
12661
13392
  const headRows = tableExtended.header?.rows ?? [];
13393
+ headRows.forEach((row) => collectWidths(row?.cells));
13394
+ (tableExtended.body?.rows ?? []).forEach((row) => collectWidths(row?.cells));
13395
+ (tableExtended.footer?.rows ?? []).forEach((row) => collectWidths(row?.cells));
12662
13396
  if (headRows.length > 0) {
12663
13397
  const primaryHeader = extractRowCells(headRows[0]);
12664
13398
  if (primaryHeader.length > 0) {
@@ -12688,6 +13422,15 @@ function convertExtendedToBasicTableFormat(tableExtended) {
12688
13422
  if (dataRows.length > 0) {
12689
13423
  table.data = dataRows;
12690
13424
  }
13425
+ if (hasAnyWidth) {
13426
+ const columnCount = table.columns?.length ?? maxCellCount;
13427
+ const columnWidths = new Array(columnCount).fill(null);
13428
+ for (let i = 0; i < columnCount; i++) {
13429
+ const w = widths[i];
13430
+ if (typeof w === "number") columnWidths[i] = w;
13431
+ }
13432
+ table.columnWidths = columnWidths;
13433
+ }
12691
13434
  return table;
12692
13435
  }
12693
13436
  function normalizeTableFormat(bitType, table) {
@@ -24854,6 +25597,7 @@ var Builder = class extends BaseBuilder {
24854
25597
  isCommented: data.isCommented,
24855
25598
  // Properties
24856
25599
  id: this.toAstProperty(bitType, ConfigKey.property_id, data.id, options),
25600
+ gUri: this.toAstProperty(bitType, ConfigKey.property_gUri, data.gUri, options),
24857
25601
  internalComment: this.toAstProperty(
24858
25602
  bitType,
24859
25603
  ConfigKey.property_internalComment,
@@ -25065,6 +25809,7 @@ var Builder = class extends BaseBuilder {
25065
25809
  data.extractorInternal,
25066
25810
  options
25067
25811
  ),
25812
+ sourceBB: this.normaliseSourceBB(data.sourceBB),
25068
25813
  levelCEFRp: this.toAstProperty(
25069
25814
  bitType,
25070
25815
  ConfigKey.property_levelCEFRp,
@@ -25709,6 +26454,18 @@ var Builder = class extends BaseBuilder {
25709
26454
  data.printParentChapterLevel,
25710
26455
  options
25711
26456
  ),
26457
+ printOnRequestCustomerId: this.toAstProperty(
26458
+ bitType,
26459
+ ConfigKey.property_printOnRequestCustomerId,
26460
+ data.printOnRequestCustomerId,
26461
+ options
26462
+ ),
26463
+ printOnRequestProductId: this.toAstProperty(
26464
+ bitType,
26465
+ ConfigKey.property_printOnRequestProductId,
26466
+ data.printOnRequestProductId,
26467
+ options
26468
+ ),
25712
26469
  platformBrandTarget: this.toAstProperty(
25713
26470
  bitType,
25714
26471
  ConfigKey.property_platformBrandTarget,
@@ -26073,6 +26830,19 @@ var Builder = class extends BaseBuilder {
26073
26830
  nodes = Object.values(combinedNodes);
26074
26831
  return nodes.length > 0 ? nodes : void 0;
26075
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
+ }
26076
26846
  /**
26077
26847
  * Build groupTag node
26078
26848
  *
@@ -26541,6 +27311,17 @@ var Builder = class extends BaseBuilder {
26541
27311
  (row) => (row || []).map((cell) => this.handleJsonText(context, TextLocation.tag, cell))
26542
27312
  );
26543
27313
  }
27314
+ if (Array.isArray(nodeTable.columnWidths)) {
27315
+ const columnCount = Array.isArray(nodeTable.columns) ? nodeTable.columns.length : void 0;
27316
+ const source = columnCount != null ? nodeTable.columnWidths.slice(0, columnCount) : nodeTable.columnWidths;
27317
+ const normalized = source.map((w) => typeof w === "number" && w > 0 ? w : null);
27318
+ const hasAny = normalized.some((w) => w != null);
27319
+ if (hasAny) {
27320
+ nodeTable.columnWidths = normalized;
27321
+ } else {
27322
+ delete nodeTable.columnWidths;
27323
+ }
27324
+ }
26544
27325
  const buildSection = (section) => {
26545
27326
  if (!section || !Array.isArray(section.rows)) return void 0;
26546
27327
  const rows = section.rows.map((row) => {
@@ -28381,6 +29162,23 @@ var BitmarkGenerator = class extends AstWalkerGenerator {
28381
29162
  format: TagFormat.plainText
28382
29163
  });
28383
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
+ }
28384
29182
  // bitmarkAst -> bits -> bitsValue -> questions -> questionsValue -> additionalSolutions -> additionalSolutionsValue
28385
29183
  leaf_additionalSolutionsValue(node, route) {
28386
29184
  const parent = this.getParentNode(route, 2);
@@ -30504,6 +31302,16 @@ var JsonGenerator = class extends AstWalkerGenerator {
30504
31302
  enter_ratingLevelEnd(node, route) {
30505
31303
  return this.standardHandler(node, route, NodeType.bitsValue, { array: false });
30506
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
+ }
30507
31315
  // bitmarkAst -> bits -> bitsValue -> productId
30508
31316
  enter_productId(node, route) {
30509
31317
  const productIds = node.value;
@@ -31531,6 +32339,10 @@ var JsonGenerator = class extends AstWalkerGenerator {
31531
32339
  if (instance2.isOfBitType(bitType, BitType.vendorStripePricingTable)) {
31532
32340
  if (bitJson.stripePricingTableId == null) bitJson.stripePricingTableId = "";
31533
32341
  if (bitJson.stripePublishableKey == null) bitJson.stripePublishableKey = "";
32342
+ if (instance2.isOfBitType(bitType, BitType.vendorStripePricingTablePrintOnRequest)) {
32343
+ if (bitJson.printOnRequestCustomerId == null) bitJson.printOnRequestCustomerId = "";
32344
+ if (bitJson.printOnRequestProductId == null) bitJson.printOnRequestProductId = "";
32345
+ }
31534
32346
  }
31535
32347
  if (instance2.isOfBitType(bitType, BitType.callToAction)) {
31536
32348
  if (bitJson.buttonCaption == null) bitJson.buttonCaption = "";
@@ -35196,6 +36008,17 @@ function propertyContentProcessor(context, contentDepth, tagsConfig, content, ta
35196
36008
  format: TextFormat.bitmarkText,
35197
36009
  location: TextLocation.tag
35198
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;
35199
36022
  }
35200
36023
  }
35201
36024
  return instance3.unbreakscape(v2, {
@@ -35232,6 +36055,8 @@ function propertyContentProcessor(context, contentDepth, tagsConfig, content, ta
35232
36055
  minCount: 1,
35233
36056
  chain: void 0,
35234
36057
  jsonKey: void 0,
36058
+ exportJsonKey: void 0,
36059
+ hasExportJsonKey: false,
35235
36060
  format: TagFormat.bitmarkText,
35236
36061
  values: void 0,
35237
36062
  defaultValue: void 0,
@@ -35242,19 +36067,18 @@ function propertyContentProcessor(context, contentDepth, tagsConfig, content, ta
35242
36067
  }
35243
36068
 
35244
36069
  // src/parser/bitmark/peg/contentProcessors/ReferenceTagContentProcessor.ts
35245
- function referenceTagContentProcessor(_context, _contentDepth, _tagsConfig, content, target, isReferenceEnd) {
35246
- const { value } = content;
36070
+ function referenceTagContentProcessor(context, _contentDepth, tagsConfig, content, target) {
36071
+ const { value, chain } = content;
35247
36072
  const trimmedStringValue = stringUtils.trimmedString(value);
35248
- if (isReferenceEnd) {
35249
- target.referenceEnd = instance3.unbreakscape(trimmedStringValue, {
35250
- format: TextFormat.bitmarkText,
35251
- location: TextLocation.tag
35252
- });
35253
- } else {
35254
- target.reference = instance3.unbreakscape(trimmedStringValue, {
35255
- format: TextFormat.bitmarkText,
35256
- location: TextLocation.tag
35257
- });
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
+ }
35258
36082
  }
35259
36083
  }
35260
36084
 
@@ -35944,7 +36768,6 @@ var BitmarkPegParserProcessor = class {
35944
36768
  result.markConfig = [];
35945
36769
  result.extraProperties = {};
35946
36770
  result.internalComments = [];
35947
- let seenReference = false;
35948
36771
  let inFooter = false;
35949
36772
  const bodyParts = [];
35950
36773
  let bodyTextPart = instance3.EMPTY_STRING;
@@ -35980,15 +36803,7 @@ var BitmarkPegParserProcessor = class {
35980
36803
  defaultTagContentProcessor(this.context, contentDepth, tagsConfig, content, result);
35981
36804
  break;
35982
36805
  case TypeKey.Reference:
35983
- referenceTagContentProcessor(
35984
- this.context,
35985
- contentDepth,
35986
- tagsConfig,
35987
- content,
35988
- result,
35989
- seenReference
35990
- );
35991
- seenReference = true;
36806
+ referenceTagContentProcessor(this.context, contentDepth, tagsConfig, content, result);
35992
36807
  break;
35993
36808
  case TypeKey.Title:
35994
36809
  titleTagContentProcessor(this.context, contentDepth, tagsConfig, content, result);
@@ -40298,58 +41113,44 @@ var ConfigBuilder = class {
40298
41113
  BitTagConfigKeyType.group,
40299
41114
  BitTagConfigKeyType.unknown
40300
41115
  ];
41116
+ const exportJsonKeyErrors = [];
40301
41117
  const resolveGroupReferences = (groupKey) => {
40302
41118
  if (squashedGroups.has(groupKey)) {
40303
41119
  const replacements = squashedGroups.get(groupKey);
40304
- return replacements.flatMap((r) => resolveGroupReferences(r));
41120
+ return replacements.flatMap(
41121
+ (r) => squashedGroups.has(r.key) ? resolveGroupReferences(r.key) : [r]
41122
+ );
40305
41123
  }
40306
- return [groupKey];
41124
+ return [{ key: groupKey }];
40307
41125
  };
40308
- const keyToJsonKey = (key, tagNameChain) => {
40309
- let jsonKey = key;
40310
- if (key === "%") {
40311
- jsonKey = "item";
40312
- } else if (key === "!") {
40313
- jsonKey = "instruction";
40314
- } else if (key === "?") {
40315
- jsonKey = "hint";
40316
- } else if (key === "#") {
40317
- jsonKey = "title";
40318
- } else if (key === "##") {
40319
- jsonKey = "subTitle";
40320
- } else if (key === "\u25BC") {
40321
- jsonKey = "anchor";
40322
- } else if (key === "\u25BA") {
40323
- jsonKey = "reference";
40324
- } else if (key === "$") {
40325
- jsonKey = "sampleSolution";
40326
- } else if (key === "+") {
40327
- jsonKey = "choices[]|set(isCorrect=true)";
40328
- } else if (key === "-") {
40329
- jsonKey = "choices[]|set(isCorrect=false)";
40330
- } else if (key === "_") {
40331
- jsonKey = "solutions[]";
40332
- } else if (key === "=") {
40333
- jsonKey = "solution";
40334
- } else if (key.startsWith("@")) {
40335
- jsonKey = key.substring(1);
40336
- } else if (key.startsWith("&")) {
40337
- jsonKey = key.substring(1);
40338
- }
40339
- const thisChain = [...tagNameChain, jsonKey];
40340
- jsonKey = thisChain.join(".");
40341
- return jsonKey;
41126
+ const bareKeyForProperty = (key) => {
41127
+ if (key.startsWith("@") || key.startsWith("&")) return key.substring(1);
41128
+ return void 0;
40342
41129
  };
40343
- 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) => {
40344
41136
  const tags2 = [];
40345
41137
  let tagName = tag.key;
40346
- const jsonKey = tag.jsonKey ?? keyToJsonKey(tagName, tagNameChain);
40347
41138
  const tagType = typeFromConfigKey(tag.key);
40348
41139
  let format = "";
40349
41140
  let chain = void 0;
40350
41141
  if (tagType === BitTagConfigKeyType.tag) {
40351
41142
  tagName = tag.key;
40352
- format = "bitmark--";
41143
+ if (tag.format === TagFormat.plainText) {
41144
+ format = "string";
41145
+ } else if (tag.format === TagFormat.boolean) {
41146
+ format = "bool";
41147
+ } else if (tag.format === TagFormat.bitmarkText) {
41148
+ format = "bitmark";
41149
+ } else if (tag.format === TagFormat.number) {
41150
+ format = "number";
41151
+ } else {
41152
+ format = "bitmark--";
41153
+ }
40353
41154
  } else if (tagType === BitTagConfigKeyType.property) {
40354
41155
  tagName = tag.key;
40355
41156
  if (tag.format === TagFormat.plainText) {
@@ -40366,48 +41167,88 @@ var ConfigBuilder = class {
40366
41167
  } else if (tagType === BitTagConfigKeyType.group) {
40367
41168
  let k = tag.key;
40368
41169
  if (k.startsWith("group_")) k = k.substring(6);
40369
- k = /*'_' +*/
40370
- stringUtils.camelToKebab(k);
41170
+ k = stringUtils.camelToKebab(k);
40371
41171
  const resolvedGroups = resolveGroupReferences(k);
40372
- 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;
40373
41185
  tags2.push({
40374
41186
  type: "group",
40375
- key: groupKey,
40376
- ...tag.jsonKey ? { jsonKey: tag.jsonKey } : {}
41187
+ key: ref.key,
41188
+ ...hasExportChosen ? { jsonKey: exportJsonKeyChosen } : {},
41189
+ ...min != null ? { min } : {},
41190
+ ...max != null ? { max } : {},
41191
+ ...description ? { description } : {}
40377
41192
  });
40378
41193
  }
40379
41194
  return tags2;
40380
41195
  }
40381
41196
  if (Array.isArray(tag.chain) && tag.chain.length > 0) {
40382
41197
  const chainTags = [];
40383
- for (const [_tagKey, chainTag] of tag.chain.entries()) {
40384
- 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));
40385
41201
  }
40386
41202
  chain = chainTags;
40387
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
+ }
40388
41217
  const t = {
40389
41218
  type: "tag",
40390
41219
  key: tagName,
40391
- jsonKey,
41220
+ ...exportJsonKeyField,
40392
41221
  format,
40393
41222
  default: tag.defaultValue ?? null,
41223
+ ...tag.nullable ? { nullable: true } : {},
40394
41224
  min: tag.minCount == null ? 0 : tag.minCount,
40395
41225
  max: tag.maxCount == null ? 1 : tag.maxCount,
40396
41226
  description: tag.description ?? "",
40397
41227
  tags: chain
40398
- // raw: {
40399
- // ...tag,
40400
- // },
40401
41228
  };
40402
41229
  tags2.push(t);
40403
41230
  return tags2;
40404
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
+ };
40405
41243
  const serializeCardSet = (cardSetKey) => {
41244
+ const variantBodyFormat = (variant) => variant.format ?? TextFormat.bitmarkText;
40406
41245
  const cardSetConfig = CARDSETS[cardSetKey];
40407
41246
  if (!cardSetConfig) return void 0;
40408
41247
  const normalizedKey = normalizeCardKey(cardSetKey);
40409
- const sides = cardSetConfig.sides.map((side) => {
40410
- 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}]`;
40411
41252
  const variantTags = [];
40412
41253
  const variantTagEntries = Object.entries(variant.tags ?? []).sort((a, b) => {
40413
41254
  const tagA = a[1];
@@ -40418,10 +41259,11 @@ var ConfigBuilder = class {
40418
41259
  return typeOrder;
40419
41260
  });
40420
41261
  for (const [, variantTag] of variantTagEntries) {
40421
- variantTags.push(...processTagEntries(variantTag, []));
41262
+ variantTags.push(...processTagEntries(variantTag, [variantPath]));
40422
41263
  }
40423
41264
  return {
40424
- ...variant.jsonKey !== void 0 ? { jsonKey: variant.jsonKey } : {},
41265
+ ...cardJsonKeyField(variant, "jsonKey", "exportJsonKey", variantPath),
41266
+ format: variantBodyFormat(variant),
40425
41267
  tags: variantTags,
40426
41268
  repeatCount: variant.repeatCount ?? 1,
40427
41269
  ...variant.bodyRequired ? { bodyRequired: true } : {},
@@ -40431,41 +41273,41 @@ var ConfigBuilder = class {
40431
41273
  return {
40432
41274
  name: side.name,
40433
41275
  ...side.repeat ? { repeat: side.repeat } : {},
40434
- ...side.jsonKey != null ? { jsonKey: side.jsonKey } : {},
41276
+ ...cardJsonKeyField(side, "jsonKey", "exportJsonKey", sidePath),
40435
41277
  variants
40436
41278
  };
40437
41279
  });
40438
41280
  if (cardSetConfig.sections) {
40439
41281
  const cards = Object.entries(cardSetConfig.sections).map(([sectionName, section]) => {
40440
- let cardSides = section.sideJsonKey ? sides.map((s) => ({ ...s, jsonKey: section.sideJsonKey })) : sides;
40441
- if (normalizedKey === "table-extended" && sectionName !== "table-header") {
40442
- cardSides = JSON.parse(JSON.stringify(cardSides));
40443
- for (const side of cardSides) {
40444
- for (const variant of side.variants) {
40445
- for (const tag of variant.tags) {
40446
- if (tag.type === "tag" && tag.key === "#" && tag.jsonKey === ".") {
40447
- tag.jsonKey = "^table.header.rows.cells[{s}].content";
40448
- }
40449
- }
40450
- }
40451
- }
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 }));
40452
41293
  }
40453
41294
  return {
40454
41295
  name: sectionName,
40455
41296
  ...section.isDefault ? { isDefault: true } : {},
40456
- jsonKey: section.jsonKey,
41297
+ ...cardJsonKeyField(section, "jsonKey", "exportJsonKey", sectionPath),
40457
41298
  sides: cardSides
40458
41299
  };
40459
41300
  });
40460
41301
  return { name: normalizedKey, cards };
40461
41302
  }
41303
+ const cardSetPath = `cardSets.${normalizedKey} / cards.default`;
40462
41304
  return {
40463
41305
  name: normalizedKey,
40464
41306
  cards: [
40465
41307
  {
40466
41308
  name: "default",
40467
41309
  isDefault: true,
40468
- jsonKey: cardSetConfig.jsonKey,
41310
+ ...cardJsonKeyField(cardSetConfig, "jsonKey", "exportJsonKey", cardSetPath),
40469
41311
  sides
40470
41312
  }
40471
41313
  ]
@@ -40492,10 +41334,20 @@ var ConfigBuilder = class {
40492
41334
  if (allAreGroups && processedTags.length > 0) {
40493
41335
  const replacements = [];
40494
41336
  if (b.baseBitType) {
40495
- replacements.push(`group-${b.baseBitType}`);
41337
+ replacements.push({ key: `group-${b.baseBitType}` });
40496
41338
  }
40497
41339
  for (const t of processedTags) {
40498
- 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);
40499
41351
  }
40500
41352
  squashedGroups.set(groupKey, replacements);
40501
41353
  }
@@ -40514,19 +41366,27 @@ var ConfigBuilder = class {
40514
41366
  const isInheritedFrom = bitGroupConfigKeys.has(b.bitType);
40515
41367
  if (isInheritedFrom) {
40516
41368
  const resolvedGroups = resolveGroupReferences(`group-${b.bitType}`);
40517
- for (const groupKey of resolvedGroups) {
41369
+ for (const ref of resolvedGroups) {
40518
41370
  tags2.push({
40519
41371
  type: "group",
40520
- 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 } : {}
40521
41377
  });
40522
41378
  }
40523
41379
  } else {
40524
41380
  if (b.baseBitType) {
40525
41381
  const resolvedGroups = resolveGroupReferences(`group-${b.baseBitType}`);
40526
- for (const groupKey of resolvedGroups) {
41382
+ for (const ref of resolvedGroups) {
40527
41383
  tags2.push({
40528
41384
  type: "group",
40529
- 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 } : {}
40530
41390
  });
40531
41391
  }
40532
41392
  }
@@ -40646,10 +41506,14 @@ var ConfigBuilder = class {
40646
41506
  const tags2 = [];
40647
41507
  if (b.baseBitType) {
40648
41508
  const resolvedGroups = resolveGroupReferences(`group-${b.baseBitType}`);
40649
- for (const gk of resolvedGroups) {
41509
+ for (const ref of resolvedGroups) {
40650
41510
  tags2.push({
40651
41511
  type: "group",
40652
- 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 } : {}
40653
41517
  });
40654
41518
  }
40655
41519
  }
@@ -40684,6 +41548,13 @@ var ConfigBuilder = class {
40684
41548
  };
40685
41549
  writeBitsAsGroupConfigs(bitGroupConfigs);
40686
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
+ }
40687
41558
  Promise.all(fileWrites).then(() => {
40688
41559
  const validationErrors = this.validateConfigTree(outputFolder);
40689
41560
  if (validationErrors.length > 0) {
@@ -41572,6 +42443,117 @@ var JsonStringGenerator = class {
41572
42443
  }
41573
42444
  };
41574
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
+
41575
42557
  // src/index.ts
41576
42558
  init();
41577
42559
  // Annotate the CommonJS export names for ESM import in node:
@@ -41586,6 +42568,7 @@ init();
41586
42568
  BitmarkStringGenerator,
41587
42569
  BitmarkVersion,
41588
42570
  BodyTextFormat,
42571
+ BoundingBoxIndex,
41589
42572
  Builder,
41590
42573
  CardSetVersion,
41591
42574
  FileWriter,