@gmb/bitmark-parser-generator 5.23.0 → 5.24.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/browser/bitmark-parser-generator.min.js +1 -1
- package/dist/browser/bundle-report.html +2 -2
- package/dist/browser/cjs/index.cjs +1866 -154
- package/dist/browser/cjs/index.cjs.map +1 -1
- package/dist/browser/cjs/index.d.cts +20 -0
- package/dist/browser/esm/index.d.ts +20 -0
- package/dist/browser/esm/index.js +1866 -154
- package/dist/browser/esm/index.js.map +1 -1
- package/dist/cli/main.js +1893 -158
- package/dist/cli/main.js.map +1 -1
- package/dist/index.cjs +1893 -158
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +1893 -158
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -792,10 +792,12 @@ var TextFormat = {
|
|
|
792
792
|
var import_superenum7 = require("@ncoderz/superenum");
|
|
793
793
|
var CardSetConfigKey = {
|
|
794
794
|
flashcard: "flashcard",
|
|
795
|
+
flashcard1: "flashcard1",
|
|
795
796
|
definitionList: "definitionList",
|
|
796
797
|
elements: "elements",
|
|
797
798
|
statements: "statements",
|
|
798
799
|
quiz: "quiz",
|
|
800
|
+
quizResponses: "quizResponses",
|
|
799
801
|
feedback: "feedback",
|
|
800
802
|
questions: "questions",
|
|
801
803
|
matchPairs: "matchPairs",
|
|
@@ -807,6 +809,7 @@ var CardSetConfigKey = {
|
|
|
807
809
|
pronunciationTable: "pronunciationTable",
|
|
808
810
|
botActionResponses: "botActionResponses",
|
|
809
811
|
exampleBitList: "exampleBitList",
|
|
812
|
+
pageFooterSections: "pageFooterSections",
|
|
810
813
|
clozeList: "clozeList",
|
|
811
814
|
ingredients: "ingredients",
|
|
812
815
|
// DEPRECATED - TO BE REMOVED IN THE FUTURE
|
|
@@ -1223,12 +1226,17 @@ var groupKeys = {
|
|
|
1223
1226
|
group_standardAllBits: "group_standardAllBits",
|
|
1224
1227
|
group_standardItemLead: "group_standardItemLead",
|
|
1225
1228
|
group_standardItemLeadInstructionHint: "group_standardItemLeadInstructionHint",
|
|
1229
|
+
group_standardInstructionHint: "group_standardInstructionHint",
|
|
1226
1230
|
group_standardTags: "group_standardTags",
|
|
1231
|
+
group_standardTagsNoItemLead: "group_standardTagsNoItemLead",
|
|
1227
1232
|
group_imageSource: "group_imageSource",
|
|
1228
1233
|
group_technicalTerm: "group_technicalTerm",
|
|
1229
1234
|
group_person: "group_person",
|
|
1230
1235
|
group_gap: "group_gap",
|
|
1231
1236
|
group_trueFalse: "group_trueFalse",
|
|
1237
|
+
group_trueFalseInlineHighlight: "group_trueFalseInlineHighlight",
|
|
1238
|
+
group_trueFalseInlineSelect: "group_trueFalseInlineSelect",
|
|
1239
|
+
group_trueFalseResponses: "group_trueFalseResponses",
|
|
1232
1240
|
group_markConfig: "group_markConfig",
|
|
1233
1241
|
group_mark: "group_mark",
|
|
1234
1242
|
group_bookCommon: "group_bookCommon",
|
|
@@ -1236,14 +1244,18 @@ var groupKeys = {
|
|
|
1236
1244
|
group_advertisingCommon: "group_advertisingCommon",
|
|
1237
1245
|
group_platformStylesCommon: "group_platformStylesCommon",
|
|
1238
1246
|
group_quizCommon: "group_quizCommon",
|
|
1247
|
+
group_backgroundWallpaper: "group_backgroundWallpaper",
|
|
1248
|
+
group_imageNoZoom: "group_imageNoZoom",
|
|
1239
1249
|
group_resourceBitTags: "group_resourceBitTags",
|
|
1240
1250
|
group_resourceCommon: "group_resourceCommon",
|
|
1241
1251
|
group_resourceImageCommon: "group_resourceImageCommon",
|
|
1252
|
+
group_resourceImageCommonNoZoom: "group_resourceImageCommonNoZoom",
|
|
1242
1253
|
group_resourceAudioCommon: "group_resourceAudioCommon",
|
|
1243
1254
|
group_resourceVideoCommon: "group_resourceVideoCommon",
|
|
1244
1255
|
group_resourceIcon: "group_resourceIcon",
|
|
1245
1256
|
// Alias for image
|
|
1246
1257
|
group_resourceImage: "group_resourceImage",
|
|
1258
|
+
group_resourceImageNoZoom: "group_resourceImageNoZoom",
|
|
1247
1259
|
group_resourceImageEmbed: "group_resourceImageEmbed",
|
|
1248
1260
|
group_resourceImageLink: "group_resourceImageLink",
|
|
1249
1261
|
group_resourceImageResponsive: "group_resourceImageResponsive",
|
|
@@ -1520,6 +1532,7 @@ var propertyKeys = {
|
|
|
1520
1532
|
property_src4x: "@src4x",
|
|
1521
1533
|
property_srcAlt: "@srcAlt",
|
|
1522
1534
|
property_stripePricingTableId: "@stripePricingTableId",
|
|
1535
|
+
property_stripePricingTableDescriptiveName: "@stripePricingTableDescriptiveName",
|
|
1523
1536
|
property_stripePublishableKey: "@stripePublishableKey",
|
|
1524
1537
|
property_subject: "@subject",
|
|
1525
1538
|
property_subtype: "@subtype",
|
|
@@ -2271,7 +2284,7 @@ var CARDSETS = {
|
|
|
2271
2284
|
variants: [
|
|
2272
2285
|
{
|
|
2273
2286
|
jsonKey: "question.text",
|
|
2274
|
-
exportJsonKey: { question: { text: "$" } },
|
|
2287
|
+
exportJsonKey: [{ "@absent": { question: {} } }, { question: { text: "$" } }],
|
|
2275
2288
|
tags: [
|
|
2276
2289
|
{
|
|
2277
2290
|
key: ConfigKey.group_standardTags,
|
|
@@ -2287,6 +2300,136 @@ var CARDSETS = {
|
|
|
2287
2300
|
description: "Icon resource for the flashcard.",
|
|
2288
2301
|
jsonKey: "question.icon|resource(type=image, key=image)",
|
|
2289
2302
|
exportJsonKey: { question: { icon: { type: "image", image: { src: "$" } } } }
|
|
2303
|
+
},
|
|
2304
|
+
{
|
|
2305
|
+
key: ConfigKey.property_example,
|
|
2306
|
+
exportJsonKey: [
|
|
2307
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2308
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2309
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2310
|
+
],
|
|
2311
|
+
description: "Example marker for the flashcard question.",
|
|
2312
|
+
format: TagFormat.bitmarkText,
|
|
2313
|
+
nullable: true
|
|
2314
|
+
}
|
|
2315
|
+
]
|
|
2316
|
+
}
|
|
2317
|
+
]
|
|
2318
|
+
},
|
|
2319
|
+
{
|
|
2320
|
+
name: "answer",
|
|
2321
|
+
variants: [
|
|
2322
|
+
{
|
|
2323
|
+
jsonKey: "answer.text",
|
|
2324
|
+
exportJsonKey: [{ "@absent": { answer: {} } }, { answer: { text: "$" } }],
|
|
2325
|
+
tags: [
|
|
2326
|
+
{
|
|
2327
|
+
key: ConfigKey.group_standardTags,
|
|
2328
|
+
description: "Standard tags for the flashcard."
|
|
2329
|
+
},
|
|
2330
|
+
{
|
|
2331
|
+
exportJsonKey: { title: "$" },
|
|
2332
|
+
key: ConfigKey.tag_title,
|
|
2333
|
+
description: "Title of the flashcard."
|
|
2334
|
+
},
|
|
2335
|
+
{
|
|
2336
|
+
key: ConfigKey.group_resourceIcon,
|
|
2337
|
+
description: "Icon resource for the flashcard.",
|
|
2338
|
+
jsonKey: "answer.icon|resource(type=image, key=image)",
|
|
2339
|
+
exportJsonKey: { answer: { icon: { type: "image", image: { src: "$" } } } }
|
|
2340
|
+
},
|
|
2341
|
+
{
|
|
2342
|
+
key: ConfigKey.property_example,
|
|
2343
|
+
exportJsonKey: [
|
|
2344
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2345
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2346
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2347
|
+
],
|
|
2348
|
+
description: "Example marker for the flashcard answer.",
|
|
2349
|
+
format: TagFormat.bitmarkText,
|
|
2350
|
+
nullable: true
|
|
2351
|
+
}
|
|
2352
|
+
]
|
|
2353
|
+
},
|
|
2354
|
+
{
|
|
2355
|
+
jsonKey: "alternativeAnswers[].text",
|
|
2356
|
+
exportJsonKey: { alternativeAnswers: [{ text: "$" }] },
|
|
2357
|
+
tags: [
|
|
2358
|
+
{
|
|
2359
|
+
key: ConfigKey.group_standardTags,
|
|
2360
|
+
description: "Standard tags for the flashcard."
|
|
2361
|
+
},
|
|
2362
|
+
{
|
|
2363
|
+
exportJsonKey: { title: "$" },
|
|
2364
|
+
key: ConfigKey.tag_title,
|
|
2365
|
+
description: "Title of the flashcard."
|
|
2366
|
+
},
|
|
2367
|
+
{
|
|
2368
|
+
key: ConfigKey.group_resourceIcon,
|
|
2369
|
+
description: "Icon resource for the flashcard.",
|
|
2370
|
+
jsonKey: "alternativeAnswers[].icon|resource(type=image, key=image)",
|
|
2371
|
+
exportJsonKey: {
|
|
2372
|
+
alternativeAnswers: [{ icon: { type: "image", image: { src: "$" } } }]
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
],
|
|
2376
|
+
repeatCount: Count.infinity
|
|
2377
|
+
}
|
|
2378
|
+
]
|
|
2379
|
+
}
|
|
2380
|
+
]
|
|
2381
|
+
},
|
|
2382
|
+
//
|
|
2383
|
+
// flashcard1 — single-card variant of flashcard. Same shape, but capped
|
|
2384
|
+
// at one card via `sections.default.maxCount = 1` (PLAN-085). Used by
|
|
2385
|
+
// the `flashcard-1` bit type; the multi-card `flashcard` and
|
|
2386
|
+
// `q-and-a-card` bit types continue to use the unbounded `flashcard`
|
|
2387
|
+
// cardset.
|
|
2388
|
+
//
|
|
2389
|
+
[CardSetConfigKey.flashcard1]: {
|
|
2390
|
+
jsonKey: "cards",
|
|
2391
|
+
exportJsonKey: { cards: "$" },
|
|
2392
|
+
sections: {
|
|
2393
|
+
default: {
|
|
2394
|
+
jsonKey: "cards",
|
|
2395
|
+
exportJsonKey: { cards: "$" },
|
|
2396
|
+
isDefault: true,
|
|
2397
|
+
maxCount: 1
|
|
2398
|
+
}
|
|
2399
|
+
},
|
|
2400
|
+
sides: [
|
|
2401
|
+
{
|
|
2402
|
+
name: "question",
|
|
2403
|
+
variants: [
|
|
2404
|
+
{
|
|
2405
|
+
jsonKey: "question.text",
|
|
2406
|
+
exportJsonKey: [{ "@absent": { question: {} } }, { question: { text: "$" } }],
|
|
2407
|
+
tags: [
|
|
2408
|
+
{
|
|
2409
|
+
key: ConfigKey.group_standardTags,
|
|
2410
|
+
description: "Standard tags for the flashcard."
|
|
2411
|
+
},
|
|
2412
|
+
{
|
|
2413
|
+
exportJsonKey: { title: "$" },
|
|
2414
|
+
key: ConfigKey.tag_title,
|
|
2415
|
+
description: "Title of the flashcard."
|
|
2416
|
+
},
|
|
2417
|
+
{
|
|
2418
|
+
key: ConfigKey.group_resourceIcon,
|
|
2419
|
+
description: "Icon resource for the flashcard.",
|
|
2420
|
+
jsonKey: "question.icon|resource(type=image, key=image)",
|
|
2421
|
+
exportJsonKey: { question: { icon: { type: "image", image: { src: "$" } } } }
|
|
2422
|
+
},
|
|
2423
|
+
{
|
|
2424
|
+
key: ConfigKey.property_example,
|
|
2425
|
+
exportJsonKey: [
|
|
2426
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2427
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2428
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2429
|
+
],
|
|
2430
|
+
description: "Example marker for the flashcard question.",
|
|
2431
|
+
format: TagFormat.bitmarkText,
|
|
2432
|
+
nullable: true
|
|
2290
2433
|
}
|
|
2291
2434
|
]
|
|
2292
2435
|
}
|
|
@@ -2297,7 +2440,7 @@ var CARDSETS = {
|
|
|
2297
2440
|
variants: [
|
|
2298
2441
|
{
|
|
2299
2442
|
jsonKey: "answer.text",
|
|
2300
|
-
exportJsonKey: { answer: { text: "$" } },
|
|
2443
|
+
exportJsonKey: [{ "@absent": { answer: {} } }, { answer: { text: "$" } }],
|
|
2301
2444
|
tags: [
|
|
2302
2445
|
{
|
|
2303
2446
|
key: ConfigKey.group_standardTags,
|
|
@@ -2313,6 +2456,17 @@ var CARDSETS = {
|
|
|
2313
2456
|
description: "Icon resource for the flashcard.",
|
|
2314
2457
|
jsonKey: "answer.icon|resource(type=image, key=image)",
|
|
2315
2458
|
exportJsonKey: { answer: { icon: { type: "image", image: { src: "$" } } } }
|
|
2459
|
+
},
|
|
2460
|
+
{
|
|
2461
|
+
key: ConfigKey.property_example,
|
|
2462
|
+
exportJsonKey: [
|
|
2463
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2464
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2465
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2466
|
+
],
|
|
2467
|
+
description: "Example marker for the flashcard answer.",
|
|
2468
|
+
format: TagFormat.bitmarkText,
|
|
2469
|
+
nullable: true
|
|
2316
2470
|
}
|
|
2317
2471
|
]
|
|
2318
2472
|
},
|
|
@@ -2356,7 +2510,7 @@ var CARDSETS = {
|
|
|
2356
2510
|
variants: [
|
|
2357
2511
|
{
|
|
2358
2512
|
jsonKey: "term.text",
|
|
2359
|
-
exportJsonKey: { term: { text: "$" } },
|
|
2513
|
+
exportJsonKey: [{ "@absent": { term: {} } }, { term: { text: "$" } }],
|
|
2360
2514
|
tags: [
|
|
2361
2515
|
{
|
|
2362
2516
|
key: ConfigKey.group_standardTags,
|
|
@@ -2375,6 +2529,17 @@ var CARDSETS = {
|
|
|
2375
2529
|
format: TagFormat.plainText,
|
|
2376
2530
|
jsonKey: "term.icon|resource(type=image, key=image)",
|
|
2377
2531
|
exportJsonKey: { term: { icon: { type: "image", image: { src: "$" } } } }
|
|
2532
|
+
},
|
|
2533
|
+
{
|
|
2534
|
+
key: ConfigKey.property_example,
|
|
2535
|
+
exportJsonKey: [
|
|
2536
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2537
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2538
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2539
|
+
],
|
|
2540
|
+
description: "Example marker for the definition term.",
|
|
2541
|
+
format: TagFormat.bitmarkText,
|
|
2542
|
+
nullable: true
|
|
2378
2543
|
}
|
|
2379
2544
|
]
|
|
2380
2545
|
}
|
|
@@ -2385,7 +2550,7 @@ var CARDSETS = {
|
|
|
2385
2550
|
variants: [
|
|
2386
2551
|
{
|
|
2387
2552
|
jsonKey: "definition.text",
|
|
2388
|
-
exportJsonKey: { definition: { text: "$" } },
|
|
2553
|
+
exportJsonKey: [{ "@absent": { definition: {} } }, { definition: { text: "$" } }],
|
|
2389
2554
|
tags: [
|
|
2390
2555
|
{
|
|
2391
2556
|
key: ConfigKey.group_standardTags,
|
|
@@ -2403,6 +2568,17 @@ var CARDSETS = {
|
|
|
2403
2568
|
description: "Icon resource for the definition.",
|
|
2404
2569
|
jsonKey: "definition.icon|resource(type=image, key=image)",
|
|
2405
2570
|
exportJsonKey: { definition: { icon: { type: "image", image: { src: "$" } } } }
|
|
2571
|
+
},
|
|
2572
|
+
{
|
|
2573
|
+
key: ConfigKey.property_example,
|
|
2574
|
+
exportJsonKey: [
|
|
2575
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2576
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2577
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2578
|
+
],
|
|
2579
|
+
description: "Example marker for the definition.",
|
|
2580
|
+
format: TagFormat.bitmarkText,
|
|
2581
|
+
nullable: true
|
|
2406
2582
|
}
|
|
2407
2583
|
]
|
|
2408
2584
|
},
|
|
@@ -2447,11 +2623,51 @@ var CARDSETS = {
|
|
|
2447
2623
|
{
|
|
2448
2624
|
jsonKey: "key",
|
|
2449
2625
|
exportJsonKey: { key: "$" },
|
|
2626
|
+
format: TextFormat.plainText,
|
|
2450
2627
|
tags: [
|
|
2451
2628
|
{
|
|
2452
2629
|
key: ConfigKey.group_standardTags,
|
|
2453
2630
|
description: "Standard tags for the match pair."
|
|
2454
2631
|
},
|
|
2632
|
+
{
|
|
2633
|
+
// Pair-level example: emit `isExample` alongside `example`
|
|
2634
|
+
// (matches OLD parser's per-pair allow-list behaviour).
|
|
2635
|
+
//
|
|
2636
|
+
// PLAN-074: a valued cascade source (`[@example:V]` anywhere
|
|
2637
|
+
// in the cardset) fills each pair's `example` with `V`
|
|
2638
|
+
// once per pair from the keys-side cascade fire (single
|
|
2639
|
+
// parsed_variant per pair — no per-value duplication).
|
|
2640
|
+
//
|
|
2641
|
+
// PLAN-076 NOTE: matchPairs (TAG 415) KEEPS `example: '$'`
|
|
2642
|
+
// at the pair-object level. BPG `parseMatchPairs`
|
|
2643
|
+
// (`CardContentProcessor.ts:714-723`) emits ONE example
|
|
2644
|
+
// per PAIR (the `exampleCard` accumulator), placed at the
|
|
2645
|
+
// pair object. Unlike matchMatrix (per-cell example),
|
|
2646
|
+
// matchPairs has no nested per-cell layer, so the pair-key
|
|
2647
|
+
// `[@example:V]` must double-emit as the visible field.
|
|
2648
|
+
// Confirmed via `chaining` fixture: `match-solution-grouped`
|
|
2649
|
+
// expects `example: "packen"` at pair-object level from
|
|
2650
|
+
// `die Koffer[%1][@example:packen]`. Original PLAN-076
|
|
2651
|
+
// draft applied to both keys-side tags; the matchPairs
|
|
2652
|
+
// half was reverted after fixture parity testing.
|
|
2653
|
+
key: ConfigKey.property_example,
|
|
2654
|
+
exportJsonKey: [
|
|
2655
|
+
{ "@keyonly": { isExample: true, "@bit": { isExample: true } } },
|
|
2656
|
+
{
|
|
2657
|
+
predicates: ["@absent", { $cascade: "*" }],
|
|
2658
|
+
rule: {
|
|
2659
|
+
isExample: true,
|
|
2660
|
+
example: "$cascade",
|
|
2661
|
+
"@bit": { isExample: true }
|
|
2662
|
+
}
|
|
2663
|
+
},
|
|
2664
|
+
{ "@absent": { isExample: true } },
|
|
2665
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2666
|
+
],
|
|
2667
|
+
description: "Example marker / value on the match pair.",
|
|
2668
|
+
format: TagFormat.bitmarkText,
|
|
2669
|
+
nullable: true
|
|
2670
|
+
},
|
|
2455
2671
|
{
|
|
2456
2672
|
key: ConfigKey.tag_title,
|
|
2457
2673
|
description: "Title of the match pair.",
|
|
@@ -2460,9 +2676,19 @@ var CARDSETS = {
|
|
|
2460
2676
|
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2461
2677
|
},
|
|
2462
2678
|
{
|
|
2679
|
+
// PLAN-084: gate the key-side `@absent → $ancestor` cascade
|
|
2680
|
+
// synth with `@variantLacksTag=isCaseSensitive` so the rule
|
|
2681
|
+
// only fires when NO variant in the active card explicitly
|
|
2682
|
+
// carries `[@isCaseSensitive]`. When a value-side variant
|
|
2683
|
+
// carries the tag (e.g. `[@isCaseSensitive:false]`), the
|
|
2684
|
+
// synth is skipped here; the value-side explicit fire owns
|
|
2685
|
+
// the pair-level emission.
|
|
2463
2686
|
key: ConfigKey.property_isCaseSensitive,
|
|
2464
2687
|
exportJsonKey: [
|
|
2465
|
-
{
|
|
2688
|
+
{
|
|
2689
|
+
predicates: ["@absent", { "@variantLacksTag": "@isCaseSensitive" }],
|
|
2690
|
+
rule: { isCaseSensitive: "$ancestor" }
|
|
2691
|
+
},
|
|
2466
2692
|
{ isCaseSensitive: "$" }
|
|
2467
2693
|
],
|
|
2468
2694
|
description: "Property to indicate if the match is case sensitive.",
|
|
@@ -2491,10 +2717,85 @@ var CARDSETS = {
|
|
|
2491
2717
|
{
|
|
2492
2718
|
jsonKey: "values[]",
|
|
2493
2719
|
exportJsonKey: { values: ["$"] },
|
|
2720
|
+
format: TextFormat.plainText,
|
|
2494
2721
|
tags: [
|
|
2495
2722
|
{
|
|
2496
|
-
|
|
2497
|
-
|
|
2723
|
+
// PLAN-084: value-side excludes item/lead/pageNumber/marginNumber.
|
|
2724
|
+
// BPG `parseMatchPairs` does `delete tags.item; delete tags.lead;`
|
|
2725
|
+
// for sideIdx > 0; the schema-side equivalent is to use a
|
|
2726
|
+
// group_standardTags variant that omits group_standardItemLead.
|
|
2727
|
+
key: ConfigKey.group_standardTagsNoItemLead,
|
|
2728
|
+
description: "Standard tags for the match pair (values side, no item/lead)."
|
|
2729
|
+
},
|
|
2730
|
+
{
|
|
2731
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.6: cascade-fired
|
|
2732
|
+
// `@example` from the bit header fills each pair's
|
|
2733
|
+
// `example` with the pair's first value (mirrors BPG's
|
|
2734
|
+
// `fillStringExample(pairs, __defaultExample=values[0])`).
|
|
2735
|
+
//
|
|
2736
|
+
// PLAN-074: the cascade-source-VALUE branch is handled by
|
|
2737
|
+
// TAG 415 (keys side) which fires once per pair — keeping
|
|
2738
|
+
// it here would emit `example` twice per pair (one per
|
|
2739
|
+
// values-side parsed_variant) and merge them into a
|
|
2740
|
+
// multi-paragraph array.
|
|
2741
|
+
//
|
|
2742
|
+
// PLAN-075: bare `$parent` reads the parent variant fire's
|
|
2743
|
+
// source `$` value (the current `++`-iteration's value
|
|
2744
|
+
// text). For single-value pairs this matches the old
|
|
2745
|
+
// `$parent.values[0]`; for multi-value pairs with
|
|
2746
|
+
// `[@example]` attached to a non-first value, it correctly
|
|
2747
|
+
// resolves to that value.
|
|
2748
|
+
//
|
|
2749
|
+
// PLAN-077: dual `[@absent, { '$cascade': '*' }]` rule
|
|
2750
|
+
// routes pair-key `[@example:V]` (a per-pair cascade
|
|
2751
|
+
// source, bound via per-card CascadeCounters scope) and
|
|
2752
|
+
// bit-header `[@example:V]` (cardset cascade) into the
|
|
2753
|
+
// pair-level `example` via `$cascade`. The aggregator in
|
|
2754
|
+
// `populate_variants` fires this rule ONCE per pair (BPG
|
|
2755
|
+
// `parseMatchPairs` `exampleCard` precedence), avoiding
|
|
2756
|
+
// per-iter pollution.
|
|
2757
|
+
key: ConfigKey.property_example,
|
|
2758
|
+
exportJsonKey: [
|
|
2759
|
+
// PLAN-084: bare `[@example]` on a values-side variant fires
|
|
2760
|
+
// once per pair (first-wins, mirrors BPG `parseMatchPairs`
|
|
2761
|
+
// `exampleCard` + `pushDownTree` set-if-null semantic).
|
|
2762
|
+
// `maxEmits: 1` enforced inside the per-pair cascade-counter
|
|
2763
|
+
// scope opened by `build_card_item`.
|
|
2764
|
+
{
|
|
2765
|
+
predicates: ["@keyonly"],
|
|
2766
|
+
maxEmits: 1,
|
|
2767
|
+
rule: {
|
|
2768
|
+
isExample: true,
|
|
2769
|
+
example: "$parent",
|
|
2770
|
+
"@bit": { isExample: true }
|
|
2771
|
+
}
|
|
2772
|
+
},
|
|
2773
|
+
{
|
|
2774
|
+
predicates: ["@absent", { $cascade: "*" }],
|
|
2775
|
+
rule: {
|
|
2776
|
+
isExample: true,
|
|
2777
|
+
example: "$cascade",
|
|
2778
|
+
"@bit": { isExample: true }
|
|
2779
|
+
}
|
|
2780
|
+
},
|
|
2781
|
+
{
|
|
2782
|
+
"@absent": {
|
|
2783
|
+
isExample: true,
|
|
2784
|
+
example: "$parent",
|
|
2785
|
+
"@bit": { isExample: true }
|
|
2786
|
+
}
|
|
2787
|
+
},
|
|
2788
|
+
// PLAN-084: same cap applies to the explicit-value `[@example:V]`
|
|
2789
|
+
// form so per-`++`-iter values-side fires also first-win.
|
|
2790
|
+
{
|
|
2791
|
+
predicates: [],
|
|
2792
|
+
maxEmits: 1,
|
|
2793
|
+
rule: { isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2794
|
+
}
|
|
2795
|
+
],
|
|
2796
|
+
description: "Example marker / value on the match pair (values side).",
|
|
2797
|
+
format: TagFormat.bitmarkText,
|
|
2798
|
+
nullable: true
|
|
2498
2799
|
},
|
|
2499
2800
|
{
|
|
2500
2801
|
key: ConfigKey.tag_title,
|
|
@@ -2504,9 +2805,13 @@ var CARDSETS = {
|
|
|
2504
2805
|
exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
|
|
2505
2806
|
},
|
|
2506
2807
|
{
|
|
2808
|
+
// PLAN-084: symmetric @variantLacksTag gating with the key-side.
|
|
2507
2809
|
key: ConfigKey.property_isCaseSensitive,
|
|
2508
2810
|
exportJsonKey: [
|
|
2509
|
-
{
|
|
2811
|
+
{
|
|
2812
|
+
predicates: ["@absent", { "@variantLacksTag": "@isCaseSensitive" }],
|
|
2813
|
+
rule: { isCaseSensitive: "$ancestor" }
|
|
2814
|
+
},
|
|
2510
2815
|
{ isCaseSensitive: "$" }
|
|
2511
2816
|
],
|
|
2512
2817
|
description: "Property to indicate if the match is case sensitive.",
|
|
@@ -2532,6 +2837,7 @@ var CARDSETS = {
|
|
|
2532
2837
|
{
|
|
2533
2838
|
jsonKey: "key",
|
|
2534
2839
|
exportJsonKey: { key: "$" },
|
|
2840
|
+
format: TextFormat.plainText,
|
|
2535
2841
|
tags: [
|
|
2536
2842
|
{
|
|
2537
2843
|
key: ConfigKey.group_standardTags,
|
|
@@ -2561,10 +2867,12 @@ var CARDSETS = {
|
|
|
2561
2867
|
{
|
|
2562
2868
|
jsonKey: "values[]",
|
|
2563
2869
|
exportJsonKey: { values: ["$"] },
|
|
2870
|
+
format: TextFormat.plainText,
|
|
2564
2871
|
tags: [
|
|
2565
2872
|
{
|
|
2566
|
-
|
|
2567
|
-
|
|
2873
|
+
// PLAN-084: value-side excludes item/lead/pageNumber/marginNumber.
|
|
2874
|
+
key: ConfigKey.group_standardTagsNoItemLead,
|
|
2875
|
+
description: "Standard tags for the audio match pair (values side, no item/lead)."
|
|
2568
2876
|
},
|
|
2569
2877
|
{
|
|
2570
2878
|
key: ConfigKey.tag_title,
|
|
@@ -2597,6 +2905,7 @@ var CARDSETS = {
|
|
|
2597
2905
|
{
|
|
2598
2906
|
jsonKey: "key",
|
|
2599
2907
|
exportJsonKey: { key: "$" },
|
|
2908
|
+
format: TextFormat.plainText,
|
|
2600
2909
|
tags: [
|
|
2601
2910
|
{
|
|
2602
2911
|
key: ConfigKey.group_standardTags,
|
|
@@ -2626,10 +2935,12 @@ var CARDSETS = {
|
|
|
2626
2935
|
{
|
|
2627
2936
|
jsonKey: "values[]",
|
|
2628
2937
|
exportJsonKey: { values: ["$"] },
|
|
2938
|
+
format: TextFormat.plainText,
|
|
2629
2939
|
tags: [
|
|
2630
2940
|
{
|
|
2631
|
-
|
|
2632
|
-
|
|
2941
|
+
// PLAN-084: value-side excludes item/lead/pageNumber/marginNumber.
|
|
2942
|
+
key: ConfigKey.group_standardTagsNoItemLead,
|
|
2943
|
+
description: "Standard tags for the image match pair (values side, no item/lead)."
|
|
2633
2944
|
},
|
|
2634
2945
|
{
|
|
2635
2946
|
key: ConfigKey.tag_title,
|
|
@@ -2662,20 +2973,49 @@ var CARDSETS = {
|
|
|
2662
2973
|
{
|
|
2663
2974
|
jsonKey: "key",
|
|
2664
2975
|
exportJsonKey: { key: "$" },
|
|
2976
|
+
format: TextFormat.plainText,
|
|
2665
2977
|
tags: [
|
|
2666
2978
|
{
|
|
2667
2979
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2668
2980
|
description: "Standard tags for lead, instruction, and hint."
|
|
2669
2981
|
},
|
|
2670
2982
|
{
|
|
2983
|
+
// PLAN-076: drop `example: '$'` from valued rule — pair-key
|
|
2984
|
+
// `[@example:V]` is consumed as the per-pair cascade source.
|
|
2985
|
+
// PLAN-077 R14 follow-up: investigation showed the fixture
|
|
2986
|
+
// reference is INCONSISTENT — bits without a cardset-level
|
|
2987
|
+
// cascade (e.g. bit 3 `[@example:Y]should be...`) expect
|
|
2988
|
+
// pair-level `example: V` at pair scope, but bits WITH a
|
|
2989
|
+
// cardset cascade (e.g. bit 8 `[@example:99]` in title-row
|
|
2990
|
+
// PLUS pair-key `[@example:Y]`) expect NO pair-level
|
|
2991
|
+
// example. Emitting `example: $` here satisfies bit 3 but
|
|
2992
|
+
// breaks bit 8; dropping it satisfies bit 8 but breaks bit
|
|
2993
|
+
// 3. Conditional emission would require runtime gating on
|
|
2994
|
+
// the cardset cascade scope state. Left dropped pending a
|
|
2995
|
+
// dedicated plan — accepted divergence on bit 3's pair-
|
|
2996
|
+
// level emission (cells still get the per-cell `example`
|
|
2997
|
+
// correctly via PLAN-077 §4.2 + §4.3).
|
|
2671
2998
|
key: ConfigKey.property_example,
|
|
2672
2999
|
exportJsonKey: [
|
|
2673
|
-
{
|
|
2674
|
-
|
|
2675
|
-
|
|
3000
|
+
{
|
|
3001
|
+
"@keyonly": {
|
|
3002
|
+
isExample: true,
|
|
3003
|
+
"@bit": { isExample: true },
|
|
3004
|
+
"@card": { isExample: true }
|
|
3005
|
+
}
|
|
3006
|
+
},
|
|
3007
|
+
{
|
|
3008
|
+
"@absent": {
|
|
3009
|
+
isExample: true,
|
|
3010
|
+
"@bit": { isExample: true },
|
|
3011
|
+
"@card": { isExample: true }
|
|
3012
|
+
}
|
|
3013
|
+
},
|
|
3014
|
+
{ isExample: true, "@bit": { isExample: true }, "@card": { isExample: true } }
|
|
2676
3015
|
],
|
|
2677
3016
|
description: "Example text for the match matrix.",
|
|
2678
|
-
format: TagFormat.plainText
|
|
3017
|
+
format: TagFormat.plainText,
|
|
3018
|
+
nullable: true
|
|
2679
3019
|
},
|
|
2680
3020
|
{
|
|
2681
3021
|
key: ConfigKey.tag_title,
|
|
@@ -2703,35 +3043,96 @@ var CARDSETS = {
|
|
|
2703
3043
|
variants: [
|
|
2704
3044
|
{
|
|
2705
3045
|
jsonKey: "cells[{s}].values[]",
|
|
2706
|
-
exportJsonKey:
|
|
3046
|
+
exportJsonKey: [
|
|
3047
|
+
// PLAN-085 / R14: the positional-blank emission for an
|
|
3048
|
+
// effectively-absent cell side fires ONLY when the active
|
|
3049
|
+
// card has at least one `[#]` variant fire. This matches
|
|
3050
|
+
// BPG `extractHeadingCard`'s `isHeading` gate: when no
|
|
3051
|
+
// `[#]` exists anywhere in the title card, BPG returns
|
|
3052
|
+
// undefined and no `heading` is emitted. The phantom
|
|
3053
|
+
// `forValues:['']` placeholder is appropriate only when
|
|
3054
|
+
// the card is being treated as a title-row.
|
|
3055
|
+
{
|
|
3056
|
+
predicates: ["@absent", { "@variantHasTag": "#" }],
|
|
3057
|
+
rule: { "@bit": { heading: { forValues: [""] } } }
|
|
3058
|
+
},
|
|
3059
|
+
{ cells: { $s: { values: ["$"] } } }
|
|
3060
|
+
],
|
|
3061
|
+
format: TextFormat.plainText,
|
|
2707
3062
|
tags: [
|
|
2708
3063
|
{
|
|
2709
3064
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2710
3065
|
description: "Standard tags for lead, instruction, and hint."
|
|
2711
3066
|
},
|
|
2712
3067
|
{
|
|
3068
|
+
// PLAN-075: bare `$parent` reads the parent variant fire's
|
|
3069
|
+
// source `$` value (the current `++`-iteration's cell text).
|
|
3070
|
+
// Replaces `$parent.values[0]` which pinned to position 0
|
|
3071
|
+
// regardless of which `++`-value `[@example]` was on.
|
|
3072
|
+
//
|
|
3073
|
+
// PLAN-077: dual `[@absent, { '$cascade': '*' }]` rule
|
|
3074
|
+
// routes pair-key `[@example:V]` (a per-pair cascade
|
|
3075
|
+
// source, bound via per-card CascadeCounters scope) and
|
|
3076
|
+
// bit-header `[@example:V]` (cardset cascade) into the
|
|
3077
|
+
// per-cell `example` via `$cascade`. The aggregator in
|
|
3078
|
+
// `populate_variants` fires this rule ONCE per cell (BPG
|
|
3079
|
+
// `parseMatchMatrix` `exampleSide` precedence), avoiding
|
|
3080
|
+
// per-iter pollution.
|
|
3081
|
+
// @card scope-shift writes matrix-row container isExample.
|
|
2713
3082
|
key: ConfigKey.property_example,
|
|
2714
3083
|
exportJsonKey: [
|
|
2715
3084
|
{
|
|
2716
3085
|
"@keyonly": {
|
|
2717
|
-
cells: { $s: { isExample: true, example: "$parent
|
|
2718
|
-
"@bit": { isExample: true }
|
|
3086
|
+
cells: { $s: { isExample: true, example: "$parent" } },
|
|
3087
|
+
"@bit": { isExample: true },
|
|
3088
|
+
"@card": { isExample: true }
|
|
2719
3089
|
}
|
|
2720
3090
|
},
|
|
2721
3091
|
{
|
|
2722
|
-
"@absent"
|
|
3092
|
+
predicates: ["@absent", { $cascade: "*" }],
|
|
3093
|
+
rule: {
|
|
3094
|
+
cells: { $s: { isExample: true, example: "$cascade" } },
|
|
3095
|
+
"@bit": { isExample: true },
|
|
3096
|
+
"@card": { isExample: true }
|
|
3097
|
+
}
|
|
2723
3098
|
},
|
|
2724
|
-
{
|
|
3099
|
+
{
|
|
3100
|
+
"@absent": {
|
|
3101
|
+
cells: { $s: { isExample: true, example: "$parent" } },
|
|
3102
|
+
"@bit": { isExample: true },
|
|
3103
|
+
"@card": { isExample: true }
|
|
3104
|
+
}
|
|
3105
|
+
},
|
|
3106
|
+
{
|
|
3107
|
+
cells: { $s: { isExample: true, example: "$" } },
|
|
3108
|
+
"@bit": { isExample: true },
|
|
3109
|
+
"@card": { isExample: true }
|
|
3110
|
+
}
|
|
2725
3111
|
],
|
|
2726
3112
|
description: "Example text for the match matrix.",
|
|
2727
|
-
format: TagFormat.
|
|
3113
|
+
format: TagFormat.bitmarkText,
|
|
3114
|
+
nullable: true
|
|
2728
3115
|
},
|
|
2729
3116
|
{
|
|
3117
|
+
// PLAN-085 / R14: bare `[#]` on a value-side emits the
|
|
3118
|
+
// empty-string positional blank into `forValues` so the
|
|
3119
|
+
// array stays aligned with the cell positions (matches BPG
|
|
3120
|
+
// `extractHeadingCard`'s "all value-side headings present"
|
|
3121
|
+
// shape). The `@keyonly` rule is required for two reasons:
|
|
3122
|
+
// 1) it provides an emission for bare `[#]` (the `$` sigil
|
|
3123
|
+
// in the unconditional rule has no source for bare); and
|
|
3124
|
+
// 2) the presence of any `@keyonly` rule disables the
|
|
3125
|
+
// optimised-mode `should_suppress_outcome` strip (see
|
|
3126
|
+
// `forward_emit.rs`) so the resulting `forValues: [""]`
|
|
3127
|
+
// survives the all-natural-defaults check.
|
|
2730
3128
|
key: ConfigKey.tag_title,
|
|
2731
3129
|
description: "Title of the match matrix.",
|
|
2732
3130
|
format: TagFormat.plainText,
|
|
2733
3131
|
jsonKey: "^heading.forValues",
|
|
2734
|
-
exportJsonKey:
|
|
3132
|
+
exportJsonKey: [
|
|
3133
|
+
{ "@keyonly": { "@bit": { heading: { forValues: [""] } } } },
|
|
3134
|
+
{ "@bit": { heading: { forValues: ["$"] } } }
|
|
3135
|
+
]
|
|
2735
3136
|
},
|
|
2736
3137
|
{
|
|
2737
3138
|
key: ConfigKey.property_isCaseSensitive,
|
|
@@ -2780,6 +3181,35 @@ var CARDSETS = {
|
|
|
2780
3181
|
{
|
|
2781
3182
|
key: ConfigKey.group_standardTags,
|
|
2782
3183
|
description: "Standard tags for the statement."
|
|
3184
|
+
},
|
|
3185
|
+
{
|
|
3186
|
+
// PLAN-072: cascade-fired `@example` from the bit header
|
|
3187
|
+
// fills each statement entry's `example` with the entry's
|
|
3188
|
+
// own `isCorrect`, mirroring BPG's `pushExampleDownTree`
|
|
3189
|
+
// for the statements cardset. Per-array-item strip removes
|
|
3190
|
+
// `example: false` from incorrect entries so only correct
|
|
3191
|
+
// entries retain `example: true`.
|
|
3192
|
+
key: ConfigKey.property_example,
|
|
3193
|
+
exportJsonKey: [
|
|
3194
|
+
{
|
|
3195
|
+
"@keyonly": {
|
|
3196
|
+
isExample: true,
|
|
3197
|
+
example: true,
|
|
3198
|
+
"@bit": { isExample: true }
|
|
3199
|
+
}
|
|
3200
|
+
},
|
|
3201
|
+
{
|
|
3202
|
+
"@absent": {
|
|
3203
|
+
isExample: true,
|
|
3204
|
+
example: "$parent.isCorrect",
|
|
3205
|
+
"@bit": { isExample: true }
|
|
3206
|
+
}
|
|
3207
|
+
},
|
|
3208
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3209
|
+
],
|
|
3210
|
+
description: "Example marker on the statement. Bare `[@example]` emits the boolean marker; valued `[@example:true|false]` emits the literal value. Cascade from bit-header fills `example` with the entry\u2019s own `isCorrect`.",
|
|
3211
|
+
format: TagFormat.boolean,
|
|
3212
|
+
nullable: true
|
|
2783
3213
|
}
|
|
2784
3214
|
],
|
|
2785
3215
|
bodyAllowed: false
|
|
@@ -2808,6 +3238,71 @@ var CARDSETS = {
|
|
|
2808
3238
|
{
|
|
2809
3239
|
key: ConfigKey.group_standardTags,
|
|
2810
3240
|
description: "Standard tags for the quiz."
|
|
3241
|
+
},
|
|
3242
|
+
{
|
|
3243
|
+
// ALIGN-EXAMPLE-CASCADE §3.2: variant-level cascade for
|
|
3244
|
+
// quiz choices is delegated to group_trueFalse's
|
|
3245
|
+
// chain-child `@example` (`+` chain with maxEmits:1 +
|
|
3246
|
+
// `@parent.isCorrect=true`). Variant-level `@absent`
|
|
3247
|
+
// would over-fire on subsequent correct choices and on
|
|
3248
|
+
// incorrect ones — drop it.
|
|
3249
|
+
key: ConfigKey.property_example,
|
|
3250
|
+
exportJsonKey: [
|
|
3251
|
+
{ "@keyonly": { isExample: true, "@bit": { isExample: true } } },
|
|
3252
|
+
{ isExample: true, "@bit": { isExample: true } }
|
|
3253
|
+
],
|
|
3254
|
+
description: "Example marker on the quiz choice (entry-local only; cascade handled by group_trueFalse chain-children).",
|
|
3255
|
+
format: TagFormat.boolean,
|
|
3256
|
+
nullable: true
|
|
3257
|
+
}
|
|
3258
|
+
],
|
|
3259
|
+
bodyAllowed: false
|
|
3260
|
+
}
|
|
3261
|
+
]
|
|
3262
|
+
}
|
|
3263
|
+
]
|
|
3264
|
+
},
|
|
3265
|
+
//
|
|
3266
|
+
// quiz (responses)
|
|
3267
|
+
//
|
|
3268
|
+
[CardSetConfigKey.quizResponses]: {
|
|
3269
|
+
jsonKey: "quizzes",
|
|
3270
|
+
exportJsonKey: { quizzes: "$" },
|
|
3271
|
+
sides: [
|
|
3272
|
+
{
|
|
3273
|
+
name: "responses",
|
|
3274
|
+
variants: [
|
|
3275
|
+
{
|
|
3276
|
+
jsonKey: null,
|
|
3277
|
+
tags: [
|
|
3278
|
+
{
|
|
3279
|
+
key: ConfigKey.group_trueFalseResponses,
|
|
3280
|
+
description: "Group for true/false questions."
|
|
3281
|
+
},
|
|
3282
|
+
{
|
|
3283
|
+
key: ConfigKey.group_standardTags,
|
|
3284
|
+
description: "Standard tags for the quiz."
|
|
3285
|
+
},
|
|
3286
|
+
{
|
|
3287
|
+
// PLAN-072: cascade-fired `@example` from the bit header
|
|
3288
|
+
// fills each response entry's `example` with the entry's
|
|
3289
|
+
// own `isCorrect`, mirroring BPG's `pushExampleDownTree`
|
|
3290
|
+
// for the quiz-responses cardset (statements-style).
|
|
3291
|
+
key: ConfigKey.property_example,
|
|
3292
|
+
exportJsonKey: [
|
|
3293
|
+
{ "@keyonly": { isExample: true, "@bit": { isExample: true } } },
|
|
3294
|
+
{
|
|
3295
|
+
"@absent": {
|
|
3296
|
+
isExample: true,
|
|
3297
|
+
example: "$parent.isCorrect",
|
|
3298
|
+
"@bit": { isExample: true }
|
|
3299
|
+
}
|
|
3300
|
+
},
|
|
3301
|
+
{ isExample: true, "@bit": { isExample: true } }
|
|
3302
|
+
],
|
|
3303
|
+
description: "Example marker on the quiz response; cascade from bit-header fills `example` with the entry\u2019s own `isCorrect`.",
|
|
3304
|
+
format: TagFormat.boolean,
|
|
3305
|
+
nullable: true
|
|
2811
3306
|
}
|
|
2812
3307
|
],
|
|
2813
3308
|
bodyAllowed: false
|
|
@@ -2833,6 +3328,73 @@ var CARDSETS = {
|
|
|
2833
3328
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2834
3329
|
description: "Standard tags for lead, instruction, and hint."
|
|
2835
3330
|
},
|
|
3331
|
+
{
|
|
3332
|
+
// Feedback choices: `[+]` / `[-]` map to choice + `requireReason`
|
|
3333
|
+
// (NOT `isCorrect` like trueFalse). Shadow the inherited
|
|
3334
|
+
// `tag_true` / `tag_false` from `group_trueFalse` to emit the
|
|
3335
|
+
// feedback-specific shape.
|
|
3336
|
+
//
|
|
3337
|
+
// Chain @example: `[+ X][@example]` writes
|
|
3338
|
+
// `isExample/example` onto the X choice only. BPG's
|
|
3339
|
+
// `setIsExampleFlags` (Builder.ts:4041-4172) does NOT
|
|
3340
|
+
// iterate `cardNode.feedbacks` — so unlike multipleChoice,
|
|
3341
|
+
// there is no bubble to bit-level or feedbacks-level
|
|
3342
|
+
// isExample. Pattern omits `@bit` scope-shift accordingly.
|
|
3343
|
+
// No `@absent`/`@parent.isCorrect` cascade rules either:
|
|
3344
|
+
// BPG's `pushExampleDownTree` (Builder.ts:3777-3849) has
|
|
3345
|
+
// no feedback dispatch, so bit-header `[@example]` does
|
|
3346
|
+
// not flow into feedback choices.
|
|
3347
|
+
key: ConfigKey.tag_true,
|
|
3348
|
+
exportJsonKey: { choices: [{ choice: "$", requireReason: true }] },
|
|
3349
|
+
description: "Reason-required choice for feedback (`[+]`).",
|
|
3350
|
+
maxCount: Count.infinity,
|
|
3351
|
+
format: TagFormat.plainText,
|
|
3352
|
+
chain: [
|
|
3353
|
+
{
|
|
3354
|
+
key: ConfigKey.property_example,
|
|
3355
|
+
exportJsonKey: [
|
|
3356
|
+
{ "@keyonly": { isExample: true, example: true } },
|
|
3357
|
+
{ isExample: true, example: "$" }
|
|
3358
|
+
],
|
|
3359
|
+
description: "Per-choice example marker for feedback `[+]`.",
|
|
3360
|
+
format: TagFormat.boolean,
|
|
3361
|
+
maxCount: 1,
|
|
3362
|
+
nullable: true
|
|
3363
|
+
},
|
|
3364
|
+
{
|
|
3365
|
+
// `[+ X][! foo]` chains `!` (instruction) onto the
|
|
3366
|
+
// choice; same for `[?]` (hint), `[%]` (item),
|
|
3367
|
+
// `[%2]`/`[%3]`/`[%4]` (lead/pageNumber/marginNumber).
|
|
3368
|
+
// Mirrors group_trueFalse's `+` chain shape.
|
|
3369
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3370
|
+
description: "Item, lead, page number, margin number, instruction and hint chained onto the feedback choice."
|
|
3371
|
+
}
|
|
3372
|
+
]
|
|
3373
|
+
},
|
|
3374
|
+
{
|
|
3375
|
+
key: ConfigKey.tag_false,
|
|
3376
|
+
exportJsonKey: { choices: [{ choice: "$", requireReason: false }] },
|
|
3377
|
+
description: "Reason-not-required choice for feedback (`[-]`).",
|
|
3378
|
+
maxCount: Count.infinity,
|
|
3379
|
+
format: TagFormat.plainText,
|
|
3380
|
+
chain: [
|
|
3381
|
+
{
|
|
3382
|
+
key: ConfigKey.property_example,
|
|
3383
|
+
exportJsonKey: [
|
|
3384
|
+
{ "@keyonly": { isExample: true, example: true } },
|
|
3385
|
+
{ isExample: true, example: "$" }
|
|
3386
|
+
],
|
|
3387
|
+
description: "Per-choice example marker for feedback `[-]`.",
|
|
3388
|
+
format: TagFormat.boolean,
|
|
3389
|
+
maxCount: 1,
|
|
3390
|
+
nullable: true
|
|
3391
|
+
},
|
|
3392
|
+
{
|
|
3393
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3394
|
+
description: "Item, lead, page number, margin number, instruction and hint chained onto the feedback choice."
|
|
3395
|
+
}
|
|
3396
|
+
]
|
|
3397
|
+
},
|
|
2836
3398
|
{
|
|
2837
3399
|
key: ConfigKey.group_trueFalse,
|
|
2838
3400
|
description: "Group for true/false feedback."
|
|
@@ -2853,31 +3415,71 @@ var CARDSETS = {
|
|
|
2853
3415
|
name: "reason",
|
|
2854
3416
|
variants: [
|
|
2855
3417
|
{
|
|
3418
|
+
// PLAN: feedback.reason — Object-only variant pattern. Per
|
|
3419
|
+
// SYNTAX.md §8.1, sibling tag emissions do NOT auto-wrap
|
|
3420
|
+
// under `reason.*`; each tag here spells out the full path.
|
|
3421
|
+
// Body is a plain string (BPG `parseFeedback` uses
|
|
3422
|
+
// `cardBodyStr ?? ''` for `reason.text`).
|
|
2856
3423
|
jsonKey: "reason.text",
|
|
2857
3424
|
exportJsonKey: { reason: { text: "$" } },
|
|
3425
|
+
format: TextFormat.plainText,
|
|
2858
3426
|
tags: [
|
|
2859
3427
|
{
|
|
2860
|
-
|
|
2861
|
-
|
|
3428
|
+
// Instruction lands under reason. Hint/item/lead/etc.
|
|
3429
|
+
// omitted: not exercised by any fixture and BPG's
|
|
3430
|
+
// `parseFeedback` spreads only the tags actually present
|
|
3431
|
+
// — adding the rest can be done lazily as fixtures
|
|
3432
|
+
// require them, with the same `{reason: {…}}` wrapper.
|
|
3433
|
+
key: ConfigKey.tag_instruction,
|
|
3434
|
+
exportJsonKey: { reason: { instruction: "$" } },
|
|
3435
|
+
description: "Instruction for the feedback reason.",
|
|
3436
|
+
format: TagFormat.bitmarkText
|
|
2862
3437
|
},
|
|
2863
3438
|
{
|
|
2864
3439
|
key: ConfigKey.property_reasonableNumOfChars,
|
|
2865
3440
|
exportJsonKey: [
|
|
2866
|
-
{ "@absent": { reasonableNumOfChars: "$ancestor" } },
|
|
2867
|
-
{ reasonableNumOfChars: "$" }
|
|
3441
|
+
{ "@absent": { reason: { reasonableNumOfChars: "$ancestor" } } },
|
|
3442
|
+
{ reason: { reasonableNumOfChars: "$" } }
|
|
2868
3443
|
],
|
|
2869
3444
|
description: "Property for reasonable number of characters.",
|
|
2870
3445
|
format: TagFormat.number
|
|
2871
3446
|
},
|
|
2872
3447
|
{
|
|
3448
|
+
// ALIGN-EXAMPLE-CASCADE §3.9: `feedback.reason` is NOT in
|
|
3449
|
+
// BPG's `pushExampleDownTree` dispatch — no bit-header
|
|
3450
|
+
// cascade. Local emission only.
|
|
3451
|
+
//
|
|
3452
|
+
// Both `reason.example` and `feedbacks[].example` are
|
|
3453
|
+
// `TextAst` per BPG's schema — paragraph arrays. Format
|
|
3454
|
+
// here is `bitmarkText` so `$` coerces to a paragraph
|
|
3455
|
+
// array at both write sites.
|
|
2873
3456
|
key: ConfigKey.property_example,
|
|
2874
3457
|
exportJsonKey: [
|
|
2875
|
-
{
|
|
2876
|
-
|
|
2877
|
-
|
|
3458
|
+
{
|
|
3459
|
+
// Bare `[@example]`: reason.example is TextAst — BPG
|
|
3460
|
+
// coerces the boolean default to a paragraph
|
|
3461
|
+
// containing the string "true". feedbacks[].example
|
|
3462
|
+
// is not TextAst, stays a boolean. Two literal writes.
|
|
3463
|
+
"@keyonly": {
|
|
3464
|
+
reason: {
|
|
3465
|
+
isExample: true,
|
|
3466
|
+
example: [{ type: "paragraph", content: [{ text: "true", type: "text" }] }]
|
|
3467
|
+
},
|
|
3468
|
+
isExample: true,
|
|
3469
|
+
example: true,
|
|
3470
|
+
"@bit": { isExample: true }
|
|
3471
|
+
}
|
|
3472
|
+
},
|
|
3473
|
+
{
|
|
3474
|
+
reason: { isExample: true, example: "$" },
|
|
3475
|
+
isExample: true,
|
|
3476
|
+
example: "$",
|
|
3477
|
+
"@bit": { isExample: true }
|
|
3478
|
+
}
|
|
2878
3479
|
],
|
|
2879
|
-
description: "Example text for the feedback.",
|
|
2880
|
-
format: TagFormat.
|
|
3480
|
+
description: "Example text for the feedback reason (entry-local only; no bit-header cascade).",
|
|
3481
|
+
format: TagFormat.bitmarkText,
|
|
3482
|
+
nullable: true
|
|
2881
3483
|
},
|
|
2882
3484
|
{
|
|
2883
3485
|
key: ConfigKey.tag_title,
|
|
@@ -2941,6 +3543,22 @@ var CARDSETS = {
|
|
|
2941
3543
|
{
|
|
2942
3544
|
key: ConfigKey.group_standardTags,
|
|
2943
3545
|
description: "Standard tags for the question."
|
|
3546
|
+
},
|
|
3547
|
+
{
|
|
3548
|
+
// ALIGN-EXAMPLE-CASCADE §3.10: `questions` is NOT in BPG's
|
|
3549
|
+
// `pushExampleDownTree` dispatch — bit-header `[@example]`
|
|
3550
|
+
// does not propagate `example`/`isExample` onto question
|
|
3551
|
+
// entries. Only entry-local `[@example]` fires (handled by
|
|
3552
|
+
// `@keyonly` and the unconditional fallback). No `@absent`
|
|
3553
|
+
// rule.
|
|
3554
|
+
key: ConfigKey.property_example,
|
|
3555
|
+
exportJsonKey: [
|
|
3556
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
3557
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3558
|
+
],
|
|
3559
|
+
description: "Example marker for the question (entry-local only; no bit-header cascade).",
|
|
3560
|
+
format: TagFormat.bitmarkText,
|
|
3561
|
+
nullable: true
|
|
2944
3562
|
}
|
|
2945
3563
|
]
|
|
2946
3564
|
}
|
|
@@ -2967,14 +3585,16 @@ var CARDSETS = {
|
|
|
2967
3585
|
description: "Standard tags for lead, instruction, and hint."
|
|
2968
3586
|
},
|
|
2969
3587
|
{
|
|
3588
|
+
// ALIGN-EXAMPLE-CASCADE §3.11: `elements` is NOT in BPG's
|
|
3589
|
+
// `pushExampleDownTree` dispatch — no bit-header cascade.
|
|
2970
3590
|
key: ConfigKey.property_example,
|
|
2971
3591
|
exportJsonKey: [
|
|
2972
3592
|
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2973
|
-
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2974
3593
|
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2975
3594
|
],
|
|
2976
|
-
description: "Example text for the element.",
|
|
2977
|
-
format: TagFormat.plainText
|
|
3595
|
+
description: "Example text for the element (entry-local only; no bit-header cascade).",
|
|
3596
|
+
format: TagFormat.plainText,
|
|
3597
|
+
nullable: true
|
|
2978
3598
|
}
|
|
2979
3599
|
],
|
|
2980
3600
|
repeatCount: Count.infinity
|
|
@@ -2986,9 +3606,57 @@ var CARDSETS = {
|
|
|
2986
3606
|
//
|
|
2987
3607
|
// table
|
|
2988
3608
|
//
|
|
3609
|
+
// PLAN-079: supports BOTH source formats and collapses to the same basic
|
|
3610
|
+
// output (`{ columns?, data, columnWidths? }`):
|
|
3611
|
+
//
|
|
3612
|
+
// 1. Basic format — first card carries `[#X]` markers (fire `tag_title`
|
|
3613
|
+
// → `^table.columns[]`); subsequent cards are body rows. Cards have
|
|
3614
|
+
// no qualifier, so they route to the `table-body` (default) section.
|
|
3615
|
+
//
|
|
3616
|
+
// 2. Extended format — `==== table-header ====` / `==== table-footer ====`
|
|
3617
|
+
// qualifiers. The `table-header` section uses `@cardIndex=0` to route
|
|
3618
|
+
// the first header card's cells to `columns` and demote remaining
|
|
3619
|
+
// header cards (rows) into `data`. Per-cell `[@tableRowSpan]` /
|
|
3620
|
+
// `[@tableScope]` / `[@tableCellType]` tags are valid-but-unmapped
|
|
3621
|
+
// here (no per-cell metadata in basic shape) — declared on the cell
|
|
3622
|
+
// variant below.
|
|
3623
|
+
//
|
|
2989
3624
|
[CardSetConfigKey.table]: {
|
|
2990
|
-
jsonKey:
|
|
2991
|
-
exportJsonKey:
|
|
3625
|
+
jsonKey: null,
|
|
3626
|
+
exportJsonKey: null,
|
|
3627
|
+
sections: {
|
|
3628
|
+
"table-header": {
|
|
3629
|
+
// First header card's row of cells → `columns`. Subsequent header
|
|
3630
|
+
// cards' rows → `data` (per-card append; `[$]` shape because
|
|
3631
|
+
// per-card emission fires once per card, multiple fires deep_merge-
|
|
3632
|
+
// append). PLAN-079 + PLAN-080: predicates inside exportJsonKey
|
|
3633
|
+
// both ROUTE cards to this section (when no explicit `==== table-
|
|
3634
|
+
// header ====` qualifier) and SELECT the rule body once routed.
|
|
3635
|
+
// First rule = first card with any `[#]` → `columns`; second rule
|
|
3636
|
+
// = subsequent cards in this section → `data` (per-row append).
|
|
3637
|
+
jsonKey: "table.columns",
|
|
3638
|
+
exportJsonKey: [
|
|
3639
|
+
{
|
|
3640
|
+
predicates: [{ "@cardIndex": 0 }, { "@variantHasTag": "#" }],
|
|
3641
|
+
rule: { "@bit": { table: { columns: "$" } } }
|
|
3642
|
+
},
|
|
3643
|
+
{ "@cardIndex=0": { "@bit": { table: { columns: "$" } } } },
|
|
3644
|
+
{ "@bit": { table: { data: ["$"] } } }
|
|
3645
|
+
]
|
|
3646
|
+
},
|
|
3647
|
+
"table-body": {
|
|
3648
|
+
// Batched emission: `$` is the entire 2D array of body card rows.
|
|
3649
|
+
// This is the default section (no qualifier → cards land here).
|
|
3650
|
+
jsonKey: "table.data",
|
|
3651
|
+
exportJsonKey: { "@bit": { table: { data: "$" } } },
|
|
3652
|
+
isDefault: true
|
|
3653
|
+
},
|
|
3654
|
+
"table-footer": {
|
|
3655
|
+
// Batched emission: `$` is the entire 2D array of footer rows.
|
|
3656
|
+
jsonKey: "table.data",
|
|
3657
|
+
exportJsonKey: { "@bit": { table: { data: "$" } } }
|
|
3658
|
+
}
|
|
3659
|
+
},
|
|
2992
3660
|
sides: [
|
|
2993
3661
|
{
|
|
2994
3662
|
name: "cell",
|
|
@@ -3029,6 +3697,8 @@ var CARDSETS = {
|
|
|
3029
3697
|
},
|
|
3030
3698
|
{
|
|
3031
3699
|
key: ConfigKey.property_tableColWidth,
|
|
3700
|
+
jsonKey: "^table.columnWidths[{s}]",
|
|
3701
|
+
exportJsonKey: { "@bit": { table: { columnWidths: { $s: "$" } } } },
|
|
3032
3702
|
description: "Width for the column.",
|
|
3033
3703
|
format: TagFormat.number
|
|
3034
3704
|
}
|
|
@@ -3047,7 +3717,22 @@ var CARDSETS = {
|
|
|
3047
3717
|
sections: {
|
|
3048
3718
|
"table-header": {
|
|
3049
3719
|
jsonKey: "table.header.rows",
|
|
3050
|
-
|
|
3720
|
+
// PLAN-080: section dispatch via predicates inside exportJsonKey.
|
|
3721
|
+
// Cards with no explicit `==== table-header ====` qualifier
|
|
3722
|
+
// route here if FIRST CARD contains any `[#]` tag in any
|
|
3723
|
+
// variant. Explicit-qualifier cards fall through to the
|
|
3724
|
+
// unconditional fallback rule. Both rules use the per-card
|
|
3725
|
+
// append shape `rows: ['$']` — the runtime triggers per-card
|
|
3726
|
+
// emission whenever the pattern carries predicates, and each
|
|
3727
|
+
// fire appends a single-element array (multi-fire deep-merge
|
|
3728
|
+
// concatenates).
|
|
3729
|
+
exportJsonKey: [
|
|
3730
|
+
{
|
|
3731
|
+
predicates: [{ "@cardIndex": 0 }, { "@variantHasTag": "#" }],
|
|
3732
|
+
rule: { table: { header: { rows: ["$"] } } }
|
|
3733
|
+
},
|
|
3734
|
+
{ table: { header: { rows: ["$"] } } }
|
|
3735
|
+
],
|
|
3051
3736
|
sideJsonKey: "cells[{s}]|set(title=true)",
|
|
3052
3737
|
sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } }
|
|
3053
3738
|
},
|
|
@@ -3080,13 +3765,13 @@ var CARDSETS = {
|
|
|
3080
3765
|
},
|
|
3081
3766
|
{
|
|
3082
3767
|
key: ConfigKey.tag_title,
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
},
|
|
3089
|
-
description: "Title of the table cell."
|
|
3768
|
+
// PLAN-080: the `[#]` tag writes its text to the cell's
|
|
3769
|
+
// `content` field. When the card is in the `table-header`
|
|
3770
|
+
// section, the section's sideExportJsonKey wraps each
|
|
3771
|
+
// cell with `title: true` automatically.
|
|
3772
|
+
jsonKey: "content",
|
|
3773
|
+
exportJsonKey: { content: "$" },
|
|
3774
|
+
description: "Title text of the table cell (header rows)."
|
|
3090
3775
|
},
|
|
3091
3776
|
{
|
|
3092
3777
|
key: ConfigKey.property_tableCellType,
|
|
@@ -3118,6 +3803,9 @@ var CARDSETS = {
|
|
|
3118
3803
|
},
|
|
3119
3804
|
{
|
|
3120
3805
|
key: ConfigKey.property_tableColWidth,
|
|
3806
|
+
// PLAN-080: write to the cell's `colwidth` field.
|
|
3807
|
+
jsonKey: "colwidth",
|
|
3808
|
+
exportJsonKey: { colwidth: "$" },
|
|
3121
3809
|
description: "Width for the column.",
|
|
3122
3810
|
format: TagFormat.number
|
|
3123
3811
|
}
|
|
@@ -3155,7 +3843,8 @@ var CARDSETS = {
|
|
|
3155
3843
|
{
|
|
3156
3844
|
key: ConfigKey.resource_audio,
|
|
3157
3845
|
description: "Audio resource for the pronunciation table.",
|
|
3158
|
-
jsonKey: "audio"
|
|
3846
|
+
jsonKey: "audio",
|
|
3847
|
+
exportJsonKey: { audio: { type: "audio", audio: { src: "$" } } }
|
|
3159
3848
|
}
|
|
3160
3849
|
],
|
|
3161
3850
|
repeatCount: Count.infinity
|
|
@@ -3226,14 +3915,17 @@ var CARDSETS = {
|
|
|
3226
3915
|
format: TagFormat.plainText
|
|
3227
3916
|
},
|
|
3228
3917
|
{
|
|
3918
|
+
// ALIGN-EXAMPLE-CASCADE §3.12: `bot-action-responses` is
|
|
3919
|
+
// NOT in BPG's `pushExampleDownTree` dispatch — no bit-
|
|
3920
|
+
// header cascade.
|
|
3229
3921
|
key: ConfigKey.property_example,
|
|
3230
3922
|
exportJsonKey: [
|
|
3231
3923
|
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
3232
|
-
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
3233
3924
|
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3234
3925
|
],
|
|
3235
|
-
description: "Example text for the bot action response.",
|
|
3236
|
-
format: TagFormat.plainText
|
|
3926
|
+
description: "Example text for the bot action response (entry-local only; no bit-header cascade).",
|
|
3927
|
+
format: TagFormat.plainText,
|
|
3928
|
+
nullable: true
|
|
3237
3929
|
}
|
|
3238
3930
|
]
|
|
3239
3931
|
}
|
|
@@ -3299,6 +3991,38 @@ var CARDSETS = {
|
|
|
3299
3991
|
]
|
|
3300
3992
|
},
|
|
3301
3993
|
//
|
|
3994
|
+
// page-footer-sections — mirrors example-bit-list but emits cards under
|
|
3995
|
+
// `sections` instead of `listItems`. BPG's JsonGenerator special-cases
|
|
3996
|
+
// BitType.pageFooter in code; this dedicated cardSet expresses the same
|
|
3997
|
+
// routing as pure config so the Rust serializer can pick it up.
|
|
3998
|
+
//
|
|
3999
|
+
[CardSetConfigKey.pageFooterSections]: {
|
|
4000
|
+
jsonKey: "sections",
|
|
4001
|
+
exportJsonKey: { sections: "$" },
|
|
4002
|
+
sides: [
|
|
4003
|
+
{
|
|
4004
|
+
name: "item",
|
|
4005
|
+
variants: [
|
|
4006
|
+
{
|
|
4007
|
+
jsonKey: "body",
|
|
4008
|
+
exportJsonKey: { body: "$" },
|
|
4009
|
+
tags: [
|
|
4010
|
+
{
|
|
4011
|
+
key: ConfigKey.group_standardTags,
|
|
4012
|
+
description: "Standard tags for page-footer section bits."
|
|
4013
|
+
},
|
|
4014
|
+
{
|
|
4015
|
+
exportJsonKey: { title: "$" },
|
|
4016
|
+
key: ConfigKey.tag_title,
|
|
4017
|
+
description: "Title of the page-footer section."
|
|
4018
|
+
}
|
|
4019
|
+
]
|
|
4020
|
+
}
|
|
4021
|
+
]
|
|
4022
|
+
}
|
|
4023
|
+
]
|
|
4024
|
+
},
|
|
4025
|
+
//
|
|
3302
4026
|
// ingredients
|
|
3303
4027
|
//
|
|
3304
4028
|
[CardSetConfigKey.ingredients]: {
|
|
@@ -3629,7 +4353,11 @@ var GROUPS = {
|
|
|
3629
4353
|
{
|
|
3630
4354
|
key: ConfigKey.property_groupTag,
|
|
3631
4355
|
jsonKey: "groupTag.name",
|
|
3632
|
-
|
|
4356
|
+
// PLAN-063: starter-array shape with `@id` declares entity-merge
|
|
4357
|
+
// semantics — repeated `[@groupTag: name]` occurrences with the
|
|
4358
|
+
// same value fold into one entry; chained `@tag` children's
|
|
4359
|
+
// arrays merge as sets.
|
|
4360
|
+
exportJsonKey: { groupTag: [{ "@id": "name", name: "$" }] },
|
|
3633
4361
|
description: "The group tag(s) for the bit",
|
|
3634
4362
|
format: TagFormat.plainText,
|
|
3635
4363
|
maxCount: Count.infinity,
|
|
@@ -3802,6 +4530,24 @@ var GROUPS = {
|
|
|
3802
4530
|
}
|
|
3803
4531
|
]
|
|
3804
4532
|
},
|
|
4533
|
+
[ConfigKey.group_standardInstructionHint]: {
|
|
4534
|
+
type: GroupConfigType.standard,
|
|
4535
|
+
description: "Standard group for instruction and hint tags only (no item/lead/pageNumber/marginNumber chain). Used by sides where item/lead are owned by another side (e.g. matchPairs value-side, which BPG strips item/lead from at sideIdx > 0).",
|
|
4536
|
+
tags: [
|
|
4537
|
+
{
|
|
4538
|
+
exportJsonKey: { instruction: "$" },
|
|
4539
|
+
key: ConfigKey.tag_instruction,
|
|
4540
|
+
name: "Instruction",
|
|
4541
|
+
description: "The instruction for the bit"
|
|
4542
|
+
},
|
|
4543
|
+
{
|
|
4544
|
+
exportJsonKey: { hint: "$" },
|
|
4545
|
+
key: ConfigKey.tag_hint,
|
|
4546
|
+
name: "Hint",
|
|
4547
|
+
description: "The hint for the bit"
|
|
4548
|
+
}
|
|
4549
|
+
]
|
|
4550
|
+
},
|
|
3805
4551
|
[ConfigKey.group_standardTags]: {
|
|
3806
4552
|
type: GroupConfigType.standard,
|
|
3807
4553
|
description: "Standard tags which apply to MOST (but not all) bits",
|
|
@@ -3815,17 +4561,45 @@ var GROUPS = {
|
|
|
3815
4561
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3816
4562
|
},
|
|
3817
4563
|
{
|
|
3818
|
-
// Bit-level example tag
|
|
3819
|
-
//
|
|
3820
|
-
//
|
|
4564
|
+
// Bit-level example tag (default — non-`isTopLevelExample` bits):
|
|
4565
|
+
// - bare `[@example]`: consume only (records cascade marker, emits
|
|
4566
|
+
// nothing at bit-level — OLD parser scrubs bit-level isExample
|
|
4567
|
+
// for bits NOT in its `isTopLevelExample` allow-list).
|
|
4568
|
+
// - synthesized (descendant cascade): still emits `isExample: true`
|
|
4569
|
+
// at the descendant scope.
|
|
4570
|
+
// - valued `[@example:text]`: emit the example value only; bit-level
|
|
4571
|
+
// `isExample` is left to bubble from descendants.
|
|
4572
|
+
// Bits in the OLD parser's allow-list (flashcard, definitionList,
|
|
4573
|
+
// sequence, multipleChoice, trueFalse, cloze*, mark, interview,
|
|
4574
|
+
// matchMatrix, match, essay, etc.) override this entry with the
|
|
4575
|
+
// legacy emit-isExample shape.
|
|
3821
4576
|
key: ConfigKey.property_example,
|
|
3822
|
-
exportJsonKey: [
|
|
3823
|
-
{ "@keyonly": { isExample: true } },
|
|
3824
|
-
{ "@absent": { isExample: true } },
|
|
3825
|
-
{ isExample: true, example: "$" }
|
|
3826
|
-
],
|
|
4577
|
+
exportJsonKey: [{ "@keyonly": {} }, { "@absent": { isExample: true } }, { example: "$" }],
|
|
3827
4578
|
description: "The example(s) for the bit",
|
|
3828
|
-
format: TagFormat.bitmarkText
|
|
4579
|
+
format: TagFormat.bitmarkText,
|
|
4580
|
+
nullable: true
|
|
4581
|
+
}
|
|
4582
|
+
]
|
|
4583
|
+
},
|
|
4584
|
+
[ConfigKey.group_standardTagsNoItemLead]: {
|
|
4585
|
+
type: GroupConfigType.standard,
|
|
4586
|
+
description: "Standard tags mirror of group_standardTags but excluding the item/lead/pageNumber/marginNumber chain. Used by sides where item/lead are owned by another side (e.g. matchPairs value-side \u2014 BPG `parseMatchPairs` strips tags.item / tags.lead for sideIdx > 0).",
|
|
4587
|
+
tags: [
|
|
4588
|
+
{
|
|
4589
|
+
key: ConfigKey.group_standardAllBits,
|
|
4590
|
+
description: "All standard tags which apply to all bits"
|
|
4591
|
+
},
|
|
4592
|
+
{
|
|
4593
|
+
key: ConfigKey.group_standardInstructionHint,
|
|
4594
|
+
description: "Instruction and hint tags only (no item/lead chain)."
|
|
4595
|
+
},
|
|
4596
|
+
{
|
|
4597
|
+
// Mirror of group_standardTags property_example entry.
|
|
4598
|
+
key: ConfigKey.property_example,
|
|
4599
|
+
exportJsonKey: [{ "@keyonly": {} }, { "@absent": { isExample: true } }, { example: "$" }],
|
|
4600
|
+
description: "The example(s) for the bit",
|
|
4601
|
+
format: TagFormat.bitmarkText,
|
|
4602
|
+
nullable: true
|
|
3829
4603
|
}
|
|
3830
4604
|
]
|
|
3831
4605
|
},
|
|
@@ -3890,8 +4664,8 @@ var GROUPS = {
|
|
|
3890
4664
|
tags: [
|
|
3891
4665
|
{
|
|
3892
4666
|
key: ConfigKey.property_person,
|
|
3893
|
-
jsonKey: "
|
|
3894
|
-
exportJsonKey: {
|
|
4667
|
+
jsonKey: "person.name",
|
|
4668
|
+
exportJsonKey: { person: { name: "$" } },
|
|
3895
4669
|
description: "A person",
|
|
3896
4670
|
format: TagFormat.plainText,
|
|
3897
4671
|
chain: [
|
|
@@ -3911,8 +4685,8 @@ var GROUPS = {
|
|
|
3911
4685
|
{
|
|
3912
4686
|
// Deprecated (parter renamed to person)
|
|
3913
4687
|
key: ConfigKey.property_partner,
|
|
3914
|
-
jsonKey: "
|
|
3915
|
-
exportJsonKey: {
|
|
4688
|
+
jsonKey: "person.name",
|
|
4689
|
+
exportJsonKey: { person: { name: "$" } },
|
|
3916
4690
|
description: "A partner",
|
|
3917
4691
|
format: TagFormat.plainText,
|
|
3918
4692
|
chain: [
|
|
@@ -3936,7 +4710,9 @@ var GROUPS = {
|
|
|
3936
4710
|
description: "Gap chain",
|
|
3937
4711
|
tags: [
|
|
3938
4712
|
{
|
|
3939
|
-
exportJsonKey: {
|
|
4713
|
+
exportJsonKey: {
|
|
4714
|
+
"@body-inline": { type: "gap", attrs: { solutions: ["$"] } }
|
|
4715
|
+
},
|
|
3940
4716
|
key: ConfigKey.tag_gap,
|
|
3941
4717
|
description: "The value of a gap in the content",
|
|
3942
4718
|
maxCount: Count.infinity,
|
|
@@ -3955,27 +4731,37 @@ var GROUPS = {
|
|
|
3955
4731
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3956
4732
|
},
|
|
3957
4733
|
{
|
|
4734
|
+
// BPG ExampleTagContentProcessor.ts:91-95 reads
|
|
4735
|
+
// `__solutionsAst[length - 1]` — the solution closest to the
|
|
4736
|
+
// `[@example]` tag at parse time. Our chain accumulator is built
|
|
4737
|
+
// incrementally (scope.rs `parent.merge` after each tag), so at
|
|
4738
|
+
// the moment `[@example]` fires, `solutions` only contains the
|
|
4739
|
+
// preceding `[_x]` entries — `[-1]` resolves to the closest one.
|
|
4740
|
+
// E.g. `[_cloze][_gap][@example]` → solutions=["cloze","gap"],
|
|
4741
|
+
// `[-1]`="gap"; `[_solution][@example][_problem]` →
|
|
4742
|
+
// solutions=["solution"], `[-1]`="solution".
|
|
3958
4743
|
key: ConfigKey.property_example,
|
|
3959
4744
|
jsonKey: "example",
|
|
3960
4745
|
exportJsonKey: [
|
|
3961
4746
|
{
|
|
3962
4747
|
"@keyonly": {
|
|
3963
4748
|
isExample: true,
|
|
3964
|
-
example: "$parent.solutions[
|
|
4749
|
+
example: "$parent.solutions[-1]",
|
|
3965
4750
|
"@bit": { isExample: true }
|
|
3966
4751
|
}
|
|
3967
4752
|
},
|
|
3968
4753
|
{
|
|
3969
4754
|
"@absent": {
|
|
3970
4755
|
isExample: true,
|
|
3971
|
-
example: "$parent.solutions[
|
|
4756
|
+
example: "$parent.solutions[-1]",
|
|
3972
4757
|
"@bit": { isExample: true }
|
|
3973
4758
|
}
|
|
3974
4759
|
},
|
|
3975
4760
|
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3976
4761
|
],
|
|
3977
4762
|
description: "An example for the gap",
|
|
3978
|
-
format: TagFormat.bitmarkText
|
|
4763
|
+
format: TagFormat.bitmarkText,
|
|
4764
|
+
nullable: true
|
|
3979
4765
|
},
|
|
3980
4766
|
{
|
|
3981
4767
|
key: ConfigKey.property_isCaseSensitive,
|
|
@@ -4024,6 +4810,24 @@ var GROUPS = {
|
|
|
4024
4810
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
4025
4811
|
},
|
|
4026
4812
|
{
|
|
4813
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.2: cascade-fired
|
|
4814
|
+
// `@example` from the bit header marks EVERY choice with
|
|
4815
|
+
// `isExample: true` (matches BPG output), but only the
|
|
4816
|
+
// FIRST correct choice gets `example: true` (BPG
|
|
4817
|
+
// `fillBooleanExample(..., firstCorrectOnly=true)`).
|
|
4818
|
+
//
|
|
4819
|
+
// Two `@absent` rules, picked first-match-wins:
|
|
4820
|
+
// 1. Verbose form gated on `@parent.isCorrect=true` with
|
|
4821
|
+
// `maxEmits:1` — fires once for the first correct.
|
|
4822
|
+
// 2. Plain `@absent` — fires on every remaining entry
|
|
4823
|
+
// (subsequent corrects and all incorrects), emitting
|
|
4824
|
+
// `isExample` only.
|
|
4825
|
+
// The `serialize_cards` cascade-counter scope holds the cap
|
|
4826
|
+
// across the whole cardset.
|
|
4827
|
+
// @card scope-shift writes choice-container isExample (e.g.
|
|
4828
|
+
// `quizzes[i].isExample`) — was previously provided by the
|
|
4829
|
+
// universal `bubble_is_example` post-walk, which was removed
|
|
4830
|
+
// in favour of explicit per-tag config. SYNTAX.md §8.
|
|
4027
4831
|
key: ConfigKey.property_example,
|
|
4028
4832
|
jsonKey: "example",
|
|
4029
4833
|
exportJsonKey: [
|
|
@@ -4031,20 +4835,37 @@ var GROUPS = {
|
|
|
4031
4835
|
"@keyonly": {
|
|
4032
4836
|
isExample: true,
|
|
4033
4837
|
example: "$parent.isCorrect",
|
|
4034
|
-
"@bit": { isExample: true }
|
|
4838
|
+
"@bit": { isExample: true },
|
|
4839
|
+
"@card": { isExample: true }
|
|
4840
|
+
}
|
|
4841
|
+
},
|
|
4842
|
+
{
|
|
4843
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
4844
|
+
maxEmits: 1,
|
|
4845
|
+
rule: {
|
|
4846
|
+
isExample: true,
|
|
4847
|
+
example: true,
|
|
4848
|
+
"@bit": { isExample: true },
|
|
4849
|
+
"@card": { isExample: true }
|
|
4035
4850
|
}
|
|
4036
4851
|
},
|
|
4037
4852
|
{
|
|
4038
4853
|
"@absent": {
|
|
4039
4854
|
isExample: true,
|
|
4040
|
-
|
|
4041
|
-
"@
|
|
4855
|
+
"@bit": { isExample: true },
|
|
4856
|
+
"@card": { isExample: true }
|
|
4042
4857
|
}
|
|
4043
4858
|
},
|
|
4044
|
-
{
|
|
4859
|
+
{
|
|
4860
|
+
isExample: true,
|
|
4861
|
+
example: "$",
|
|
4862
|
+
"@bit": { isExample: true },
|
|
4863
|
+
"@card": { isExample: true }
|
|
4864
|
+
}
|
|
4045
4865
|
],
|
|
4046
4866
|
description: "An example for the true/false statement/question",
|
|
4047
|
-
format: TagFormat.
|
|
4867
|
+
format: TagFormat.boolean,
|
|
4868
|
+
nullable: true
|
|
4048
4869
|
}
|
|
4049
4870
|
]
|
|
4050
4871
|
},
|
|
@@ -4076,6 +4897,12 @@ var GROUPS = {
|
|
|
4076
4897
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
4077
4898
|
},
|
|
4078
4899
|
{
|
|
4900
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.2: cascade-fired
|
|
4901
|
+
// `@example` on a `-` (incorrect choice) emits
|
|
4902
|
+
// `isExample: true` only — no `example` (BPG fixtures show
|
|
4903
|
+
// `isExample` on every choice, but `example` only on the
|
|
4904
|
+
// first correct via firstCorrectOnly cascade).
|
|
4905
|
+
// @card scope-shift writes choice-container isExample.
|
|
4079
4906
|
key: ConfigKey.property_example,
|
|
4080
4907
|
jsonKey: "example",
|
|
4081
4908
|
exportJsonKey: [
|
|
@@ -4083,20 +4910,460 @@ var GROUPS = {
|
|
|
4083
4910
|
"@keyonly": {
|
|
4084
4911
|
isExample: true,
|
|
4085
4912
|
example: "$parent.isCorrect",
|
|
4086
|
-
"@bit": { isExample: true }
|
|
4913
|
+
"@bit": { isExample: true },
|
|
4914
|
+
"@card": { isExample: true }
|
|
4087
4915
|
}
|
|
4088
4916
|
},
|
|
4089
4917
|
{
|
|
4090
4918
|
"@absent": {
|
|
4919
|
+
isExample: true,
|
|
4920
|
+
"@bit": { isExample: true },
|
|
4921
|
+
"@card": { isExample: true }
|
|
4922
|
+
}
|
|
4923
|
+
},
|
|
4924
|
+
{
|
|
4925
|
+
isExample: true,
|
|
4926
|
+
example: "$",
|
|
4927
|
+
"@bit": { isExample: true },
|
|
4928
|
+
"@card": { isExample: true }
|
|
4929
|
+
}
|
|
4930
|
+
],
|
|
4931
|
+
description: "An example for the true/false statement/question (incorrect entry \u2014 isExample only on cascade)",
|
|
4932
|
+
format: TagFormat.boolean,
|
|
4933
|
+
nullable: true
|
|
4934
|
+
}
|
|
4935
|
+
]
|
|
4936
|
+
}
|
|
4937
|
+
]
|
|
4938
|
+
},
|
|
4939
|
+
[ConfigKey.group_trueFalseResponses]: {
|
|
4940
|
+
type: GroupConfigType.standard,
|
|
4941
|
+
description: "True/False Responses chain",
|
|
4942
|
+
tags: [
|
|
4943
|
+
{
|
|
4944
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: true }] },
|
|
4945
|
+
key: ConfigKey.tag_true,
|
|
4946
|
+
description: "True value for a true/false statement/question",
|
|
4947
|
+
maxCount: Count.infinity,
|
|
4948
|
+
format: TagFormat.plainText,
|
|
4949
|
+
chain: [
|
|
4950
|
+
{
|
|
4951
|
+
key: ConfigKey.tag_true,
|
|
4952
|
+
jsonKey: "responses[]|set(isCorrect=true)",
|
|
4953
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: true }] },
|
|
4954
|
+
description: "True values for a true/false statement/question",
|
|
4955
|
+
maxCount: Count.infinity,
|
|
4956
|
+
format: TagFormat.plainText
|
|
4957
|
+
},
|
|
4958
|
+
{
|
|
4959
|
+
key: ConfigKey.tag_false,
|
|
4960
|
+
jsonKey: "responses[]|set(isCorrect=false)",
|
|
4961
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: false }] },
|
|
4962
|
+
description: "False values for a true/false statement/question",
|
|
4963
|
+
maxCount: Count.infinity,
|
|
4964
|
+
format: TagFormat.plainText
|
|
4965
|
+
},
|
|
4966
|
+
{
|
|
4967
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
4968
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
4969
|
+
},
|
|
4970
|
+
{
|
|
4971
|
+
// @card scope-shift writes response-container isExample.
|
|
4972
|
+
key: ConfigKey.property_example,
|
|
4973
|
+
jsonKey: "example",
|
|
4974
|
+
exportJsonKey: [
|
|
4975
|
+
{
|
|
4976
|
+
"@keyonly": {
|
|
4091
4977
|
isExample: true,
|
|
4092
4978
|
example: "$parent.isCorrect",
|
|
4093
|
-
"@bit": { isExample: true }
|
|
4979
|
+
"@bit": { isExample: true },
|
|
4980
|
+
"@card": { isExample: true }
|
|
4094
4981
|
}
|
|
4095
4982
|
},
|
|
4096
|
-
{
|
|
4983
|
+
{
|
|
4984
|
+
"@absent": {
|
|
4985
|
+
isExample: "$parent.isCorrect",
|
|
4986
|
+
example: "$parent.isCorrect",
|
|
4987
|
+
"@bit": { isExample: "$parent.isCorrect" },
|
|
4988
|
+
"@card": { isExample: "$parent.isCorrect" }
|
|
4989
|
+
}
|
|
4990
|
+
},
|
|
4991
|
+
{
|
|
4992
|
+
isExample: true,
|
|
4993
|
+
example: "$",
|
|
4994
|
+
"@bit": { isExample: true },
|
|
4995
|
+
"@card": { isExample: true }
|
|
4996
|
+
}
|
|
4097
4997
|
],
|
|
4098
4998
|
description: "An example for the true/false statement/question",
|
|
4099
|
-
format: TagFormat.
|
|
4999
|
+
format: TagFormat.boolean,
|
|
5000
|
+
nullable: true
|
|
5001
|
+
}
|
|
5002
|
+
]
|
|
5003
|
+
},
|
|
5004
|
+
{
|
|
5005
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: false }] },
|
|
5006
|
+
key: ConfigKey.tag_false,
|
|
5007
|
+
description: "False value for a true/false statement/question",
|
|
5008
|
+
maxCount: Count.infinity,
|
|
5009
|
+
format: TagFormat.plainText,
|
|
5010
|
+
chain: [
|
|
5011
|
+
{
|
|
5012
|
+
key: ConfigKey.tag_true,
|
|
5013
|
+
jsonKey: "responses[]|set(isCorrect=true)",
|
|
5014
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: true }] },
|
|
5015
|
+
description: "True values for a true/false statement/question",
|
|
5016
|
+
maxCount: Count.infinity,
|
|
5017
|
+
format: TagFormat.plainText
|
|
5018
|
+
},
|
|
5019
|
+
{
|
|
5020
|
+
key: ConfigKey.tag_false,
|
|
5021
|
+
jsonKey: "responses[]|set(isCorrect=false)",
|
|
5022
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: false }] },
|
|
5023
|
+
description: "False values for a true/false statement/question",
|
|
5024
|
+
maxCount: Count.infinity,
|
|
5025
|
+
format: TagFormat.plainText
|
|
5026
|
+
},
|
|
5027
|
+
{
|
|
5028
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5029
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5030
|
+
},
|
|
5031
|
+
{
|
|
5032
|
+
// @card scope-shift writes response-container isExample.
|
|
5033
|
+
key: ConfigKey.property_example,
|
|
5034
|
+
jsonKey: "example",
|
|
5035
|
+
exportJsonKey: [
|
|
5036
|
+
{
|
|
5037
|
+
"@keyonly": {
|
|
5038
|
+
isExample: true,
|
|
5039
|
+
example: "$parent.isCorrect",
|
|
5040
|
+
"@bit": { isExample: true },
|
|
5041
|
+
"@card": { isExample: true }
|
|
5042
|
+
}
|
|
5043
|
+
},
|
|
5044
|
+
{
|
|
5045
|
+
"@absent": {
|
|
5046
|
+
isExample: true,
|
|
5047
|
+
example: "$parent.isCorrect",
|
|
5048
|
+
"@bit": { isExample: true },
|
|
5049
|
+
"@card": { isExample: true }
|
|
5050
|
+
}
|
|
5051
|
+
},
|
|
5052
|
+
{
|
|
5053
|
+
isExample: true,
|
|
5054
|
+
example: "$",
|
|
5055
|
+
"@bit": { isExample: true },
|
|
5056
|
+
"@card": { isExample: true }
|
|
5057
|
+
}
|
|
5058
|
+
],
|
|
5059
|
+
description: "An example for the true/false statement/question",
|
|
5060
|
+
format: TagFormat.boolean,
|
|
5061
|
+
nullable: true
|
|
5062
|
+
}
|
|
5063
|
+
]
|
|
5064
|
+
}
|
|
5065
|
+
]
|
|
5066
|
+
},
|
|
5067
|
+
[ConfigKey.group_trueFalseInlineSelect]: {
|
|
5068
|
+
type: GroupConfigType.standard,
|
|
5069
|
+
description: "True/False chain composed inline (select body-bit). +/- tags are consume-only at bit level.",
|
|
5070
|
+
tags: [
|
|
5071
|
+
{
|
|
5072
|
+
exportJsonKey: {
|
|
5073
|
+
"@body-inline": {
|
|
5074
|
+
type: "select",
|
|
5075
|
+
attrs: { options: [{ text: "$", isCorrect: true }] }
|
|
5076
|
+
}
|
|
5077
|
+
},
|
|
5078
|
+
key: ConfigKey.tag_true,
|
|
5079
|
+
description: "True value for an inline select body bit",
|
|
5080
|
+
maxCount: Count.infinity,
|
|
5081
|
+
format: TagFormat.plainText,
|
|
5082
|
+
chain: [
|
|
5083
|
+
{
|
|
5084
|
+
key: ConfigKey.tag_true,
|
|
5085
|
+
exportJsonKey: {},
|
|
5086
|
+
description: "True values for an inline select body bit",
|
|
5087
|
+
maxCount: Count.infinity,
|
|
5088
|
+
format: TagFormat.plainText
|
|
5089
|
+
},
|
|
5090
|
+
{
|
|
5091
|
+
key: ConfigKey.tag_false,
|
|
5092
|
+
exportJsonKey: {},
|
|
5093
|
+
description: "False values for an inline select body bit",
|
|
5094
|
+
maxCount: Count.infinity,
|
|
5095
|
+
format: TagFormat.plainText
|
|
5096
|
+
},
|
|
5097
|
+
{
|
|
5098
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5099
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5100
|
+
},
|
|
5101
|
+
{
|
|
5102
|
+
// PLAN-083: cascade-fired `@example` from bit header fires
|
|
5103
|
+
// `isExample:true, example:true` on the FIRST CORRECT option
|
|
5104
|
+
// only (BPG `fillBooleanExample(select.options,
|
|
5105
|
+
// firstCorrectOnly=true)`). Mirrors group_trueFalseInlineHighlight.
|
|
5106
|
+
// Every rule also bubbles `@bit:{isExample:true}` (idempotent
|
|
5107
|
+
// OR — any cascade ⇒ bit marked) and
|
|
5108
|
+
// `@body-inline:{attrs:{isExample:true}}` (node-level marker
|
|
5109
|
+
// on the select node).
|
|
5110
|
+
key: ConfigKey.property_example,
|
|
5111
|
+
jsonKey: "example",
|
|
5112
|
+
exportJsonKey: [
|
|
5113
|
+
{
|
|
5114
|
+
"@keyonly": {
|
|
5115
|
+
isExample: true,
|
|
5116
|
+
example: "$parent.isCorrect",
|
|
5117
|
+
"@bit": { isExample: true },
|
|
5118
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5119
|
+
}
|
|
5120
|
+
},
|
|
5121
|
+
{
|
|
5122
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5123
|
+
maxEmits: 1,
|
|
5124
|
+
rule: {
|
|
5125
|
+
isExample: true,
|
|
5126
|
+
example: true,
|
|
5127
|
+
"@bit": { isExample: true },
|
|
5128
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5129
|
+
}
|
|
5130
|
+
},
|
|
5131
|
+
{
|
|
5132
|
+
isExample: true,
|
|
5133
|
+
example: "$",
|
|
5134
|
+
"@bit": { isExample: true },
|
|
5135
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5136
|
+
}
|
|
5137
|
+
],
|
|
5138
|
+
description: "An example for the inline select option (first correct only)",
|
|
5139
|
+
format: TagFormat.boolean,
|
|
5140
|
+
nullable: true
|
|
5141
|
+
}
|
|
5142
|
+
]
|
|
5143
|
+
},
|
|
5144
|
+
{
|
|
5145
|
+
exportJsonKey: {
|
|
5146
|
+
"@body-inline": {
|
|
5147
|
+
type: "select",
|
|
5148
|
+
attrs: { options: [{ text: "$", isCorrect: false }] }
|
|
5149
|
+
}
|
|
5150
|
+
},
|
|
5151
|
+
key: ConfigKey.tag_false,
|
|
5152
|
+
description: "False value for an inline select body bit",
|
|
5153
|
+
maxCount: Count.infinity,
|
|
5154
|
+
format: TagFormat.plainText,
|
|
5155
|
+
chain: [
|
|
5156
|
+
{
|
|
5157
|
+
key: ConfigKey.tag_true,
|
|
5158
|
+
exportJsonKey: {},
|
|
5159
|
+
description: "True values for an inline select body bit",
|
|
5160
|
+
maxCount: Count.infinity,
|
|
5161
|
+
format: TagFormat.plainText
|
|
5162
|
+
},
|
|
5163
|
+
{
|
|
5164
|
+
key: ConfigKey.tag_false,
|
|
5165
|
+
exportJsonKey: {},
|
|
5166
|
+
description: "False values for an inline select body bit",
|
|
5167
|
+
maxCount: Count.infinity,
|
|
5168
|
+
format: TagFormat.plainText
|
|
5169
|
+
},
|
|
5170
|
+
{
|
|
5171
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5172
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5173
|
+
},
|
|
5174
|
+
{
|
|
5175
|
+
// PLAN-083: identical to the `+` lead's chain @example —
|
|
5176
|
+
// cascade reaches the first correct option regardless of
|
|
5177
|
+
// which lead (+/-) opens the chain. Every firing rule bubbles
|
|
5178
|
+
// `@bit:{isExample:true}` and `@body-inline:{attrs:{isExample:true}}`.
|
|
5179
|
+
key: ConfigKey.property_example,
|
|
5180
|
+
jsonKey: "example",
|
|
5181
|
+
exportJsonKey: [
|
|
5182
|
+
{
|
|
5183
|
+
"@keyonly": {
|
|
5184
|
+
isExample: true,
|
|
5185
|
+
example: "$parent.isCorrect",
|
|
5186
|
+
"@bit": { isExample: true },
|
|
5187
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5188
|
+
}
|
|
5189
|
+
},
|
|
5190
|
+
{
|
|
5191
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5192
|
+
maxEmits: 1,
|
|
5193
|
+
rule: {
|
|
5194
|
+
isExample: true,
|
|
5195
|
+
example: true,
|
|
5196
|
+
"@bit": { isExample: true },
|
|
5197
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5198
|
+
}
|
|
5199
|
+
},
|
|
5200
|
+
{
|
|
5201
|
+
isExample: true,
|
|
5202
|
+
example: "$",
|
|
5203
|
+
"@bit": { isExample: true },
|
|
5204
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5205
|
+
}
|
|
5206
|
+
],
|
|
5207
|
+
description: "An example for the inline select option (first correct only)",
|
|
5208
|
+
format: TagFormat.boolean,
|
|
5209
|
+
nullable: true
|
|
5210
|
+
}
|
|
5211
|
+
]
|
|
5212
|
+
}
|
|
5213
|
+
]
|
|
5214
|
+
},
|
|
5215
|
+
[ConfigKey.group_trueFalseInlineHighlight]: {
|
|
5216
|
+
type: GroupConfigType.standard,
|
|
5217
|
+
description: 'True/False chain composed inline (highlight body-bit). +/- tags emit `{type:"highlight", attrs:{texts:[{text,isCorrect?}]}}` inline body nodes. Used by highlight-text bit.',
|
|
5218
|
+
tags: [
|
|
5219
|
+
{
|
|
5220
|
+
exportJsonKey: {
|
|
5221
|
+
"@body-inline": {
|
|
5222
|
+
type: "highlight",
|
|
5223
|
+
attrs: { texts: [{ text: "$", isCorrect: true }] }
|
|
5224
|
+
}
|
|
5225
|
+
},
|
|
5226
|
+
key: ConfigKey.tag_true,
|
|
5227
|
+
description: "Highlighted span in the body (correct)",
|
|
5228
|
+
maxCount: Count.infinity,
|
|
5229
|
+
format: TagFormat.plainText,
|
|
5230
|
+
chain: [
|
|
5231
|
+
{
|
|
5232
|
+
key: ConfigKey.tag_true,
|
|
5233
|
+
exportJsonKey: {},
|
|
5234
|
+
description: "Highlighted span values (correct)",
|
|
5235
|
+
maxCount: Count.infinity,
|
|
5236
|
+
format: TagFormat.plainText
|
|
5237
|
+
},
|
|
5238
|
+
{
|
|
5239
|
+
key: ConfigKey.tag_false,
|
|
5240
|
+
exportJsonKey: {},
|
|
5241
|
+
description: "Highlighted span values (incorrect)",
|
|
5242
|
+
maxCount: Count.infinity,
|
|
5243
|
+
format: TagFormat.plainText
|
|
5244
|
+
},
|
|
5245
|
+
{
|
|
5246
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5247
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5248
|
+
},
|
|
5249
|
+
{
|
|
5250
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.13: cascade-fired
|
|
5251
|
+
// `@example` from the bit header fires `example: true` +
|
|
5252
|
+
// `isExample: true` on the FIRST correct highlight only
|
|
5253
|
+
// (BPG `fillBooleanExample(highlight.texts,
|
|
5254
|
+
// firstCorrectOnly=true)`). Incorrect highlights get
|
|
5255
|
+
// nothing (unlike choices, the highlight-text fixture
|
|
5256
|
+
// shows no `isExample` on incorrect entries).
|
|
5257
|
+
key: ConfigKey.property_example,
|
|
5258
|
+
jsonKey: "example",
|
|
5259
|
+
exportJsonKey: [
|
|
5260
|
+
{
|
|
5261
|
+
"@keyonly": {
|
|
5262
|
+
isExample: true,
|
|
5263
|
+
example: "$parent.isCorrect",
|
|
5264
|
+
"@bit": { isExample: true },
|
|
5265
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5266
|
+
}
|
|
5267
|
+
},
|
|
5268
|
+
{
|
|
5269
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5270
|
+
maxEmits: 1,
|
|
5271
|
+
rule: {
|
|
5272
|
+
isExample: true,
|
|
5273
|
+
example: true,
|
|
5274
|
+
"@bit": { isExample: true },
|
|
5275
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5276
|
+
}
|
|
5277
|
+
},
|
|
5278
|
+
{
|
|
5279
|
+
isExample: true,
|
|
5280
|
+
example: "$",
|
|
5281
|
+
"@bit": { isExample: true },
|
|
5282
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5283
|
+
}
|
|
5284
|
+
],
|
|
5285
|
+
description: "An example for the highlighted span (first correct only)",
|
|
5286
|
+
format: TagFormat.boolean,
|
|
5287
|
+
nullable: true
|
|
5288
|
+
}
|
|
5289
|
+
]
|
|
5290
|
+
},
|
|
5291
|
+
{
|
|
5292
|
+
// PLAN-083 follow-up (2026-05-22): mirror the select `-` lead shape
|
|
5293
|
+
// by writing `isCorrect: false`. Without it, `$parent.isCorrect` in
|
|
5294
|
+
// chain-child @example rules resolves to ParentPathMissing for `-`
|
|
5295
|
+
// entries (e.g. `[-fish][@example]`), so the @keyonly rule falls
|
|
5296
|
+
// through and nothing fires. The natural-default strip removes
|
|
5297
|
+
// `isCorrect: false` from the final texts entries (matches fixture).
|
|
5298
|
+
exportJsonKey: {
|
|
5299
|
+
"@body-inline": {
|
|
5300
|
+
type: "highlight",
|
|
5301
|
+
attrs: { texts: [{ text: "$", isCorrect: false }] }
|
|
5302
|
+
}
|
|
5303
|
+
},
|
|
5304
|
+
key: ConfigKey.tag_false,
|
|
5305
|
+
description: "Highlighted span in the body (incorrect)",
|
|
5306
|
+
maxCount: Count.infinity,
|
|
5307
|
+
format: TagFormat.plainText,
|
|
5308
|
+
chain: [
|
|
5309
|
+
{
|
|
5310
|
+
key: ConfigKey.tag_true,
|
|
5311
|
+
exportJsonKey: {},
|
|
5312
|
+
description: "Highlighted span values (correct)",
|
|
5313
|
+
maxCount: Count.infinity,
|
|
5314
|
+
format: TagFormat.plainText
|
|
5315
|
+
},
|
|
5316
|
+
{
|
|
5317
|
+
key: ConfigKey.tag_false,
|
|
5318
|
+
exportJsonKey: {},
|
|
5319
|
+
description: "Highlighted span values (incorrect)",
|
|
5320
|
+
maxCount: Count.infinity,
|
|
5321
|
+
format: TagFormat.plainText
|
|
5322
|
+
},
|
|
5323
|
+
{
|
|
5324
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5325
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5326
|
+
},
|
|
5327
|
+
{
|
|
5328
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.13: cascade-fired
|
|
5329
|
+
// `@example` on a `-` (incorrect highlight) emits nothing
|
|
5330
|
+
// (highlight-text fixture has no `isExample` on incorrect
|
|
5331
|
+
// entries; firstCorrectOnly cascade skips them entirely).
|
|
5332
|
+
// No `@absent` rule.
|
|
5333
|
+
// PLAN-083: identical to the `+` lead's chain @example —
|
|
5334
|
+
// cascade reaches the first correct option regardless of
|
|
5335
|
+
// which lead (+/-) opens the chain.
|
|
5336
|
+
key: ConfigKey.property_example,
|
|
5337
|
+
jsonKey: "example",
|
|
5338
|
+
exportJsonKey: [
|
|
5339
|
+
{
|
|
5340
|
+
"@keyonly": {
|
|
5341
|
+
isExample: true,
|
|
5342
|
+
example: "$parent.isCorrect",
|
|
5343
|
+
"@bit": { isExample: true },
|
|
5344
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5345
|
+
}
|
|
5346
|
+
},
|
|
5347
|
+
{
|
|
5348
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5349
|
+
maxEmits: 1,
|
|
5350
|
+
rule: {
|
|
5351
|
+
isExample: true,
|
|
5352
|
+
example: true,
|
|
5353
|
+
"@bit": { isExample: true },
|
|
5354
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5355
|
+
}
|
|
5356
|
+
},
|
|
5357
|
+
{
|
|
5358
|
+
isExample: true,
|
|
5359
|
+
example: "$",
|
|
5360
|
+
"@bit": { isExample: true },
|
|
5361
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5362
|
+
}
|
|
5363
|
+
],
|
|
5364
|
+
description: "An example for the highlighted span (first correct only)",
|
|
5365
|
+
format: TagFormat.boolean,
|
|
5366
|
+
nullable: true
|
|
4100
5367
|
}
|
|
4101
5368
|
]
|
|
4102
5369
|
}
|
|
@@ -4109,7 +5376,7 @@ var GROUPS = {
|
|
|
4109
5376
|
{
|
|
4110
5377
|
key: ConfigKey.property_mark,
|
|
4111
5378
|
jsonKey: "marks.mark",
|
|
4112
|
-
exportJsonKey: { marks: { mark:
|
|
5379
|
+
exportJsonKey: { marks: [{ mark: "$" }] },
|
|
4113
5380
|
description: "The mark configuration",
|
|
4114
5381
|
format: TagFormat.plainText,
|
|
4115
5382
|
maxCount: Count.infinity,
|
|
@@ -4133,7 +5400,9 @@ var GROUPS = {
|
|
|
4133
5400
|
description: "Mark chain",
|
|
4134
5401
|
tags: [
|
|
4135
5402
|
{
|
|
4136
|
-
exportJsonKey: {
|
|
5403
|
+
exportJsonKey: {
|
|
5404
|
+
"@body-inline": { type: "mark", attrs: { solution: "$" } }
|
|
5405
|
+
},
|
|
4137
5406
|
key: ConfigKey.tag_mark,
|
|
4138
5407
|
description: "The marked content",
|
|
4139
5408
|
maxCount: Count.infinity,
|
|
@@ -4142,6 +5411,7 @@ var GROUPS = {
|
|
|
4142
5411
|
{
|
|
4143
5412
|
key: ConfigKey.property_mark,
|
|
4144
5413
|
jsonKey: "mark",
|
|
5414
|
+
exportJsonKey: { mark: "$" },
|
|
4145
5415
|
description: "The mark configuration",
|
|
4146
5416
|
format: TagFormat.plainText
|
|
4147
5417
|
},
|
|
@@ -4154,7 +5424,8 @@ var GROUPS = {
|
|
|
4154
5424
|
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
4155
5425
|
],
|
|
4156
5426
|
description: "An example for the marked content",
|
|
4157
|
-
format: TagFormat.bitmarkText
|
|
5427
|
+
format: TagFormat.bitmarkText,
|
|
5428
|
+
nullable: true
|
|
4158
5429
|
}
|
|
4159
5430
|
]
|
|
4160
5431
|
}
|
|
@@ -4583,6 +5854,42 @@ var GROUPS = {
|
|
|
4583
5854
|
}
|
|
4584
5855
|
]
|
|
4585
5856
|
},
|
|
5857
|
+
[ConfigKey.group_backgroundWallpaper]: {
|
|
5858
|
+
type: GroupConfigType.standard,
|
|
5859
|
+
description: "Background wallpaper tags",
|
|
5860
|
+
tags: [
|
|
5861
|
+
{
|
|
5862
|
+
key: ConfigKey.resource_backgroundWallpaper,
|
|
5863
|
+
exportJsonKey: { backgroundWallpaper: { type: "image", image: { src: "$" } } },
|
|
5864
|
+
description: "Background wallpaper for the image, used to set a background for the image",
|
|
5865
|
+
chain: [
|
|
5866
|
+
{
|
|
5867
|
+
key: ConfigKey.group_resourceImageCommon,
|
|
5868
|
+
description: "Common resource image tags for images"
|
|
5869
|
+
}
|
|
5870
|
+
]
|
|
5871
|
+
}
|
|
5872
|
+
]
|
|
5873
|
+
},
|
|
5874
|
+
[ConfigKey.group_imageNoZoom]: {
|
|
5875
|
+
type: GroupConfigType.standard,
|
|
5876
|
+
description: "Image bit tags",
|
|
5877
|
+
tags: [
|
|
5878
|
+
{
|
|
5879
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
5880
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
5881
|
+
},
|
|
5882
|
+
{
|
|
5883
|
+
key: ConfigKey.group_resourceBitTags,
|
|
5884
|
+
description: "Resource bit tags for images, used to define additional properties for images"
|
|
5885
|
+
},
|
|
5886
|
+
{
|
|
5887
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
5888
|
+
description: "Resource image tags for images, used to attach images to the bit",
|
|
5889
|
+
minCount: 1
|
|
5890
|
+
}
|
|
5891
|
+
]
|
|
5892
|
+
},
|
|
4586
5893
|
//
|
|
4587
5894
|
// Resource groups
|
|
4588
5895
|
//
|
|
@@ -4702,6 +6009,58 @@ var GROUPS = {
|
|
|
4702
6009
|
}
|
|
4703
6010
|
]
|
|
4704
6011
|
},
|
|
6012
|
+
[ConfigKey.group_resourceImageCommonNoZoom]: {
|
|
6013
|
+
type: GroupConfigType.standard,
|
|
6014
|
+
description: "Common properties for image resources where @zoomDisabled defaults to true",
|
|
6015
|
+
tags: [
|
|
6016
|
+
{
|
|
6017
|
+
key: ConfigKey.group_resourceCommon,
|
|
6018
|
+
description: "Common resource properties"
|
|
6019
|
+
},
|
|
6020
|
+
{
|
|
6021
|
+
key: ConfigKey.property_src1x,
|
|
6022
|
+
description: "The source URL for the image at 1x resolution",
|
|
6023
|
+
format: TagFormat.plainText
|
|
6024
|
+
},
|
|
6025
|
+
{
|
|
6026
|
+
key: ConfigKey.property_src2x,
|
|
6027
|
+
description: "The source URL for the image at 2x resolution",
|
|
6028
|
+
format: TagFormat.plainText
|
|
6029
|
+
},
|
|
6030
|
+
{
|
|
6031
|
+
key: ConfigKey.property_src3x,
|
|
6032
|
+
description: "The source URL for the image at 3x resolution",
|
|
6033
|
+
format: TagFormat.plainText
|
|
6034
|
+
},
|
|
6035
|
+
{
|
|
6036
|
+
key: ConfigKey.property_src4x,
|
|
6037
|
+
description: "The source URL for the image at 4x resolution",
|
|
6038
|
+
format: TagFormat.plainText
|
|
6039
|
+
},
|
|
6040
|
+
{
|
|
6041
|
+
key: ConfigKey.property_width,
|
|
6042
|
+
description: "The width of the image",
|
|
6043
|
+
format: TagFormat.number
|
|
6044
|
+
},
|
|
6045
|
+
{
|
|
6046
|
+
key: ConfigKey.property_height,
|
|
6047
|
+
description: "The height of the image",
|
|
6048
|
+
format: TagFormat.number
|
|
6049
|
+
},
|
|
6050
|
+
{
|
|
6051
|
+
key: ConfigKey.property_alt,
|
|
6052
|
+
description: "The alternative text for the image",
|
|
6053
|
+
format: TagFormat.plainText
|
|
6054
|
+
},
|
|
6055
|
+
// @zoomDisabled with a true default
|
|
6056
|
+
{
|
|
6057
|
+
key: ConfigKey.property_zoomDisabled,
|
|
6058
|
+
description: "If true, zooming is disabled for the image (defaults to true)",
|
|
6059
|
+
format: TagFormat.boolean,
|
|
6060
|
+
defaultValue: "true"
|
|
6061
|
+
}
|
|
6062
|
+
]
|
|
6063
|
+
},
|
|
4705
6064
|
[ConfigKey.group_resourceAudioCommon]: {
|
|
4706
6065
|
type: GroupConfigType.standard,
|
|
4707
6066
|
description: "Common properties for audio resources",
|
|
@@ -4791,22 +6150,26 @@ var GROUPS = {
|
|
|
4791
6150
|
{
|
|
4792
6151
|
key: ConfigKey.property_src1x,
|
|
4793
6152
|
description: "The source URL for the video at 1x resolution",
|
|
4794
|
-
format: TagFormat.plainText
|
|
6153
|
+
format: TagFormat.plainText,
|
|
6154
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4795
6155
|
},
|
|
4796
6156
|
{
|
|
4797
6157
|
key: ConfigKey.property_src2x,
|
|
4798
6158
|
description: "The source URL for the video at 2x resolution",
|
|
4799
|
-
format: TagFormat.plainText
|
|
6159
|
+
format: TagFormat.plainText,
|
|
6160
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4800
6161
|
},
|
|
4801
6162
|
{
|
|
4802
6163
|
key: ConfigKey.property_src3x,
|
|
4803
6164
|
description: "The source URL for the video at 3x resolution",
|
|
4804
|
-
format: TagFormat.plainText
|
|
6165
|
+
format: TagFormat.plainText,
|
|
6166
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4805
6167
|
},
|
|
4806
6168
|
{
|
|
4807
6169
|
key: ConfigKey.property_src4x,
|
|
4808
6170
|
description: "The source URL for the video at 4x resolution",
|
|
4809
|
-
format: TagFormat.plainText
|
|
6171
|
+
format: TagFormat.plainText,
|
|
6172
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4810
6173
|
}
|
|
4811
6174
|
]
|
|
4812
6175
|
},
|
|
@@ -4819,6 +6182,7 @@ var GROUPS = {
|
|
|
4819
6182
|
tags: [
|
|
4820
6183
|
{
|
|
4821
6184
|
key: ConfigKey.resource_icon,
|
|
6185
|
+
exportJsonKey: { resource: { type: "icon", icon: { src: "$" } } },
|
|
4822
6186
|
description: "The icon resource",
|
|
4823
6187
|
chain: [
|
|
4824
6188
|
{
|
|
@@ -4846,12 +6210,30 @@ var GROUPS = {
|
|
|
4846
6210
|
}
|
|
4847
6211
|
]
|
|
4848
6212
|
},
|
|
6213
|
+
[ConfigKey.group_resourceImageNoZoom]: {
|
|
6214
|
+
type: GroupConfigType.resource,
|
|
6215
|
+
description: "Image resource where @zoomDisabled defaults to true",
|
|
6216
|
+
tags: [
|
|
6217
|
+
{
|
|
6218
|
+
key: ConfigKey.resource_image,
|
|
6219
|
+
exportJsonKey: { resource: { type: "image", image: { src: "$" } } },
|
|
6220
|
+
description: "The image resource (no-zoom default)",
|
|
6221
|
+
chain: [
|
|
6222
|
+
{
|
|
6223
|
+
key: ConfigKey.group_resourceImageCommonNoZoom,
|
|
6224
|
+
description: "Common image properties with @zoomDisabled defaulting to true"
|
|
6225
|
+
}
|
|
6226
|
+
]
|
|
6227
|
+
}
|
|
6228
|
+
]
|
|
6229
|
+
},
|
|
4849
6230
|
[ConfigKey.group_resourceImagePortrait]: {
|
|
4850
6231
|
type: GroupConfigType.resource,
|
|
4851
6232
|
description: "Portrait image resource",
|
|
4852
6233
|
tags: [
|
|
4853
6234
|
{
|
|
4854
6235
|
key: ConfigKey.resource_imagePortrait,
|
|
6236
|
+
exportJsonKey: { resource: { type: "image-portrait", imagePortrait: { src: "$" } } },
|
|
4855
6237
|
description: "The portrait image resource",
|
|
4856
6238
|
chain: [
|
|
4857
6239
|
{
|
|
@@ -4868,6 +6250,7 @@ var GROUPS = {
|
|
|
4868
6250
|
tags: [
|
|
4869
6251
|
{
|
|
4870
6252
|
key: ConfigKey.resource_imageLandscape,
|
|
6253
|
+
exportJsonKey: { resource: { type: "image-landscape", imageLandscape: { src: "$" } } },
|
|
4871
6254
|
description: "The landscape image resource",
|
|
4872
6255
|
chain: [
|
|
4873
6256
|
{
|
|
@@ -4884,6 +6267,7 @@ var GROUPS = {
|
|
|
4884
6267
|
tags: [
|
|
4885
6268
|
{
|
|
4886
6269
|
key: ConfigKey.resource_imageEmbed,
|
|
6270
|
+
exportJsonKey: { resource: { type: "image-embed", imageEmbed: { src: "$" } } },
|
|
4887
6271
|
description: "The embedded image resource",
|
|
4888
6272
|
chain: [
|
|
4889
6273
|
{
|
|
@@ -5057,6 +6441,7 @@ var GROUPS = {
|
|
|
5057
6441
|
tags: [
|
|
5058
6442
|
{
|
|
5059
6443
|
key: ConfigKey.resource_article,
|
|
6444
|
+
exportJsonKey: { resource: { type: "article", article: { body: "$" } } },
|
|
5060
6445
|
description: "The article resource",
|
|
5061
6446
|
chain: [
|
|
5062
6447
|
{
|
|
@@ -5073,6 +6458,7 @@ var GROUPS = {
|
|
|
5073
6458
|
tags: [
|
|
5074
6459
|
{
|
|
5075
6460
|
key: ConfigKey.resource_articleEmbed,
|
|
6461
|
+
exportJsonKey: { resource: { type: "article-embed", articleEmbed: { url: "$" } } },
|
|
5076
6462
|
description: "The embedded article resource",
|
|
5077
6463
|
chain: [
|
|
5078
6464
|
{
|
|
@@ -5089,6 +6475,7 @@ var GROUPS = {
|
|
|
5089
6475
|
tags: [
|
|
5090
6476
|
{
|
|
5091
6477
|
key: ConfigKey.resource_articleLink,
|
|
6478
|
+
exportJsonKey: { resource: { type: "article-link", articleLink: { url: "$" } } },
|
|
5092
6479
|
description: "The link to the article resource",
|
|
5093
6480
|
chain: [
|
|
5094
6481
|
{
|
|
@@ -5359,7 +6746,12 @@ var ConfigHydrator = class {
|
|
|
5359
6746
|
isDefault: v.isDefault,
|
|
5360
6747
|
sideJsonKey: v.sideJsonKey,
|
|
5361
6748
|
sideExportJsonKey: v.sideExportJsonKey,
|
|
5362
|
-
hasSideExportJsonKey: Object.prototype.hasOwnProperty.call(v, "sideExportJsonKey")
|
|
6749
|
+
hasSideExportJsonKey: Object.prototype.hasOwnProperty.call(v, "sideExportJsonKey"),
|
|
6750
|
+
// PLAN-085: cardinality fields pass through; defaults applied
|
|
6751
|
+
// downstream by the config consumer (Rust treats `0` / undefined
|
|
6752
|
+
// as unbounded).
|
|
6753
|
+
minCount: v.minCount,
|
|
6754
|
+
maxCount: v.maxCount
|
|
5363
6755
|
};
|
|
5364
6756
|
}
|
|
5365
6757
|
return out;
|
|
@@ -5574,7 +6966,8 @@ var BITS = {
|
|
|
5574
6966
|
{ isExample: true, example: "$" }
|
|
5575
6967
|
],
|
|
5576
6968
|
description: "The example text for the bit",
|
|
5577
|
-
format: TagFormat.plainText
|
|
6969
|
+
format: TagFormat.plainText,
|
|
6970
|
+
nullable: true
|
|
5578
6971
|
}
|
|
5579
6972
|
],
|
|
5580
6973
|
rootExampleType: ExampleType.string
|
|
@@ -5913,7 +7306,8 @@ var BITS = {
|
|
|
5913
7306
|
{ isExample: true, example: "$" }
|
|
5914
7307
|
],
|
|
5915
7308
|
description: "The example text for the bit",
|
|
5916
|
-
format: TagFormat.plainText
|
|
7309
|
+
format: TagFormat.plainText,
|
|
7310
|
+
nullable: true
|
|
5917
7311
|
}
|
|
5918
7312
|
],
|
|
5919
7313
|
rootExampleType: ExampleType.string
|
|
@@ -6076,7 +7470,8 @@ var BITS = {
|
|
|
6076
7470
|
{ isExample: true, example: "$" }
|
|
6077
7471
|
],
|
|
6078
7472
|
description: "The example text for the bit",
|
|
6079
|
-
format: TagFormat.plainText
|
|
7473
|
+
format: TagFormat.plainText,
|
|
7474
|
+
nullable: true
|
|
6080
7475
|
}
|
|
6081
7476
|
],
|
|
6082
7477
|
rootExampleType: ExampleType.string
|
|
@@ -6227,7 +7622,8 @@ var BITS = {
|
|
|
6227
7622
|
{ isExample: true, example: "$" }
|
|
6228
7623
|
],
|
|
6229
7624
|
description: "The example text for the bit",
|
|
6230
|
-
format: TagFormat.plainText
|
|
7625
|
+
format: TagFormat.plainText,
|
|
7626
|
+
nullable: true
|
|
6231
7627
|
}
|
|
6232
7628
|
],
|
|
6233
7629
|
rootExampleType: ExampleType.string
|
|
@@ -6822,8 +8218,31 @@ var BITS = {
|
|
|
6822
8218
|
description: "Tags for gaps in cloze and multiple choice text bits"
|
|
6823
8219
|
},
|
|
6824
8220
|
{
|
|
6825
|
-
key: ConfigKey.
|
|
8221
|
+
key: ConfigKey.group_trueFalseInlineSelect,
|
|
6826
8222
|
description: "Tags for true/false questions in cloze and multiple choice text bits"
|
|
8223
|
+
},
|
|
8224
|
+
{
|
|
8225
|
+
// Bit-level @isCaseSensitive — empty exportJsonKey (no bit-level emission);
|
|
8226
|
+
// defaultValue 'true' phantom-fires onto the ancestor stack so the gap chain's
|
|
8227
|
+
// `@absent: $ancestor` rule resolves to true. Mirrors BPG Builder.ts:1643-1652
|
|
8228
|
+
// `pushDownTree(... 'isCaseSensitive', data.isCaseSensitive ?? true)` for cloze bits.
|
|
8229
|
+
key: ConfigKey.property_isCaseSensitive,
|
|
8230
|
+
exportJsonKey: {},
|
|
8231
|
+
description: "If the cloze answers are case sensitive",
|
|
8232
|
+
format: TagFormat.boolean,
|
|
8233
|
+
defaultValue: "true"
|
|
8234
|
+
},
|
|
8235
|
+
{
|
|
8236
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
8237
|
+
key: ConfigKey.property_example,
|
|
8238
|
+
exportJsonKey: [
|
|
8239
|
+
{ "@keyonly": { isExample: true } },
|
|
8240
|
+
{ "@absent": { isExample: true } },
|
|
8241
|
+
{ isExample: true, example: "$" }
|
|
8242
|
+
],
|
|
8243
|
+
description: "The example(s) for the bit",
|
|
8244
|
+
format: TagFormat.bitmarkText,
|
|
8245
|
+
nullable: true
|
|
6827
8246
|
}
|
|
6828
8247
|
]
|
|
6829
8248
|
},
|
|
@@ -6862,18 +8281,56 @@ var BITS = {
|
|
|
6862
8281
|
{
|
|
6863
8282
|
key: ConfigKey.group_gap,
|
|
6864
8283
|
description: "Tags for gaps in cloze bits"
|
|
8284
|
+
},
|
|
8285
|
+
{
|
|
8286
|
+
// Override inherited @example: cloze is in OLD parser's
|
|
8287
|
+
// `isTopLevelExample` allow-list, so [@example] at bit-header
|
|
8288
|
+
// emits `isExample: true`.
|
|
8289
|
+
key: ConfigKey.property_example,
|
|
8290
|
+
exportJsonKey: [
|
|
8291
|
+
{ "@keyonly": { isExample: true } },
|
|
8292
|
+
{ "@absent": { isExample: true } },
|
|
8293
|
+
{ isExample: true, example: "$" }
|
|
8294
|
+
],
|
|
8295
|
+
description: "The example(s) for the bit",
|
|
8296
|
+
format: TagFormat.bitmarkText,
|
|
8297
|
+
nullable: true
|
|
6865
8298
|
}
|
|
6866
8299
|
]
|
|
6867
8300
|
},
|
|
6868
8301
|
[BitType.clozeInstructionGrouped]: {
|
|
6869
8302
|
since: "1.3.0",
|
|
6870
8303
|
baseBitType: BitType.cloze,
|
|
6871
|
-
description: "Cloze instruction grouped bit, used for cloze questions with grouped instructions"
|
|
8304
|
+
description: "Cloze instruction grouped bit, used for cloze questions with grouped instructions",
|
|
8305
|
+
tags: [
|
|
8306
|
+
{
|
|
8307
|
+
key: ConfigKey.property_quizCountItems,
|
|
8308
|
+
description: "The number of items in the cloze quiz (instruction-grouped default: true)",
|
|
8309
|
+
format: TagFormat.boolean,
|
|
8310
|
+
defaultValue: "true"
|
|
8311
|
+
}
|
|
8312
|
+
// Note: quizStrikethroughSolutions defaults to false for instruction-grouped per OLD
|
|
8313
|
+
// JsonGenerator.ts:1689-1690, which equals the Boolean natural default → no override needed.
|
|
8314
|
+
]
|
|
6872
8315
|
},
|
|
6873
8316
|
[BitType.clozeSolutionGrouped]: {
|
|
6874
8317
|
since: "1.3.0",
|
|
6875
8318
|
baseBitType: BitType.cloze,
|
|
6876
|
-
description: "Cloze solution grouped bit, used for cloze questions with grouped solutions"
|
|
8319
|
+
description: "Cloze solution grouped bit, used for cloze questions with grouped solutions",
|
|
8320
|
+
tags: [
|
|
8321
|
+
{
|
|
8322
|
+
key: ConfigKey.property_quizCountItems,
|
|
8323
|
+
description: "The number of items in the cloze quiz (solution-grouped default: true)",
|
|
8324
|
+
format: TagFormat.boolean,
|
|
8325
|
+
defaultValue: "true"
|
|
8326
|
+
},
|
|
8327
|
+
{
|
|
8328
|
+
key: ConfigKey.property_quizStrikethroughSolutions,
|
|
8329
|
+
description: "If the cloze solutions should be strikethrough (solution-grouped default: true)",
|
|
8330
|
+
format: TagFormat.boolean,
|
|
8331
|
+
defaultValue: "true"
|
|
8332
|
+
}
|
|
8333
|
+
]
|
|
6877
8334
|
},
|
|
6878
8335
|
[BitType.clozeSeveral]: {
|
|
6879
8336
|
since: "3.5.0",
|
|
@@ -6909,6 +8366,17 @@ var BITS = {
|
|
|
6909
8366
|
{
|
|
6910
8367
|
key: ConfigKey.group_quizCommon,
|
|
6911
8368
|
description: "Common tags for quiz bits"
|
|
8369
|
+
},
|
|
8370
|
+
{
|
|
8371
|
+
// PLAN-084 (R12): bit-level @isCaseSensitive — empty exportJsonKey
|
|
8372
|
+
// (no bit-level emission); defaultValue 'true' phantom-fires onto
|
|
8373
|
+
// the ancestor stack so each listItem's gap chain `@absent: $ancestor`
|
|
8374
|
+
// rule resolves to true. Mirrors the cloze bit (bits.ts:1326-1336).
|
|
8375
|
+
key: ConfigKey.property_isCaseSensitive,
|
|
8376
|
+
exportJsonKey: {},
|
|
8377
|
+
description: "If the cloze answers are case sensitive",
|
|
8378
|
+
format: TagFormat.boolean,
|
|
8379
|
+
defaultValue: "true"
|
|
6912
8380
|
}
|
|
6913
8381
|
],
|
|
6914
8382
|
cardSet: CardSetConfigKey.clozeList
|
|
@@ -7075,6 +8543,7 @@ var BITS = {
|
|
|
7075
8543
|
tags: [
|
|
7076
8544
|
{
|
|
7077
8545
|
key: ConfigKey.group_person,
|
|
8546
|
+
exportJsonKey: { partner: { name: "$" } },
|
|
7078
8547
|
description: "Tags for the person in the conversation"
|
|
7079
8548
|
}
|
|
7080
8549
|
]
|
|
@@ -7513,7 +8982,8 @@ var BITS = {
|
|
|
7513
8982
|
{ isExample: true, example: "$" }
|
|
7514
8983
|
],
|
|
7515
8984
|
description: "The example text for the essay bit",
|
|
7516
|
-
format: TagFormat.plainText
|
|
8985
|
+
format: TagFormat.plainText,
|
|
8986
|
+
nullable: true
|
|
7517
8987
|
}
|
|
7518
8988
|
],
|
|
7519
8989
|
rootExampleType: ExampleType.string
|
|
@@ -7547,7 +9017,8 @@ var BITS = {
|
|
|
7547
9017
|
{ isExample: true, example: "$" }
|
|
7548
9018
|
],
|
|
7549
9019
|
description: "The example text for the example bit",
|
|
7550
|
-
format: TagFormat.plainText
|
|
9020
|
+
format: TagFormat.plainText,
|
|
9021
|
+
nullable: true
|
|
7551
9022
|
}
|
|
7552
9023
|
],
|
|
7553
9024
|
rootExampleType: ExampleType.string
|
|
@@ -7633,7 +9104,19 @@ var BITS = {
|
|
|
7633
9104
|
[BitType.articleAi]: {
|
|
7634
9105
|
since: "1.3.0",
|
|
7635
9106
|
baseBitType: BitType.article,
|
|
7636
|
-
description: "Article AI bit, used to create AI-generated articles"
|
|
9107
|
+
description: "Article AI bit, used to create AI-generated articles",
|
|
9108
|
+
tags: [
|
|
9109
|
+
{
|
|
9110
|
+
// Shadows the inherited @aiGenerated from the standard group: this
|
|
9111
|
+
// bit type forces aiGenerated:true regardless of source value or
|
|
9112
|
+
// absence. Literal `true` in the export pattern ignores `$`.
|
|
9113
|
+
key: ConfigKey.property_aiGenerated,
|
|
9114
|
+
description: "AI-generated flag, forced true for article-ai bits",
|
|
9115
|
+
format: TagFormat.boolean,
|
|
9116
|
+
defaultValue: "true",
|
|
9117
|
+
exportJsonKey: { aiGenerated: true }
|
|
9118
|
+
}
|
|
9119
|
+
]
|
|
7637
9120
|
},
|
|
7638
9121
|
[BitType.articleAttachment]: {
|
|
7639
9122
|
since: "1.3.0",
|
|
@@ -7958,7 +9441,19 @@ var BITS = {
|
|
|
7958
9441
|
[BitType.noteAi]: {
|
|
7959
9442
|
since: "1.3.0",
|
|
7960
9443
|
baseBitType: BitType.note,
|
|
7961
|
-
description: "Note AI bit, used to create AI-generated notes in articles or books"
|
|
9444
|
+
description: "Note AI bit, used to create AI-generated notes in articles or books",
|
|
9445
|
+
tags: [
|
|
9446
|
+
{
|
|
9447
|
+
// Shadows the inherited @aiGenerated from the standard group: this
|
|
9448
|
+
// bit type forces aiGenerated:true regardless of source value or
|
|
9449
|
+
// absence. Literal `true` in the export pattern ignores `$`.
|
|
9450
|
+
key: ConfigKey.property_aiGenerated,
|
|
9451
|
+
description: "AI-generated flag, forced true for article-ai bits",
|
|
9452
|
+
format: TagFormat.boolean,
|
|
9453
|
+
defaultValue: "true",
|
|
9454
|
+
exportJsonKey: { aiGenerated: true }
|
|
9455
|
+
}
|
|
9456
|
+
]
|
|
7962
9457
|
},
|
|
7963
9458
|
[BitType.notebookArticle]: {
|
|
7964
9459
|
since: "1.3.0",
|
|
@@ -8083,7 +9578,19 @@ var BITS = {
|
|
|
8083
9578
|
[BitType.summaryAi]: {
|
|
8084
9579
|
since: "1.3.0",
|
|
8085
9580
|
baseBitType: BitType.summary,
|
|
8086
|
-
description: "AI-generated summary bit"
|
|
9581
|
+
description: "AI-generated summary bit",
|
|
9582
|
+
tags: [
|
|
9583
|
+
{
|
|
9584
|
+
// Shadows the inherited @aiGenerated from the standard group: this
|
|
9585
|
+
// bit type forces aiGenerated:true regardless of source value or
|
|
9586
|
+
// absence. Literal `true` in the export pattern ignores `$`.
|
|
9587
|
+
key: ConfigKey.property_aiGenerated,
|
|
9588
|
+
description: "AI-generated flag, forced true for article-ai bits",
|
|
9589
|
+
format: TagFormat.boolean,
|
|
9590
|
+
defaultValue: "true",
|
|
9591
|
+
exportJsonKey: { aiGenerated: true }
|
|
9592
|
+
}
|
|
9593
|
+
]
|
|
8087
9594
|
},
|
|
8088
9595
|
[BitType.videoTranscript]: {
|
|
8089
9596
|
since: "1.3.0",
|
|
@@ -8357,7 +9864,7 @@ var BITS = {
|
|
|
8357
9864
|
description: "Product ID for the module product, used to link to a specific product",
|
|
8358
9865
|
format: TagFormat.plainText,
|
|
8359
9866
|
minCount: 1,
|
|
8360
|
-
maxCount:
|
|
9867
|
+
maxCount: 1
|
|
8361
9868
|
}
|
|
8362
9869
|
]
|
|
8363
9870
|
},
|
|
@@ -8410,10 +9917,13 @@ var BITS = {
|
|
|
8410
9917
|
description: "Resource bit tags for logo grave images, used to define additional properties"
|
|
8411
9918
|
},
|
|
8412
9919
|
{
|
|
8413
|
-
// Image resource
|
|
8414
|
-
|
|
9920
|
+
// Image resource — fully-expanded shape so each `&image` emission
|
|
9921
|
+
// produces a complete `{type, image: {src}}` object inside the
|
|
9922
|
+
// `images[]` array. Chain attrs like `[@zoomDisabled]` fold under
|
|
9923
|
+
// `images[].image` via the `[]` last-element-merge semantic.
|
|
9924
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
8415
9925
|
description: "Resource image tags for logo grave images, used to attach images",
|
|
8416
|
-
exportJsonKey: { images: "$" },
|
|
9926
|
+
exportJsonKey: { images: [{ type: "image", image: { src: "$" } }] },
|
|
8417
9927
|
minCount: 1,
|
|
8418
9928
|
maxCount: Count.infinity
|
|
8419
9929
|
}
|
|
@@ -8703,6 +10213,10 @@ var BITS = {
|
|
|
8703
10213
|
tags: [
|
|
8704
10214
|
{
|
|
8705
10215
|
key: ConfigKey.property_book,
|
|
10216
|
+
// Starter-array shape: each `[@book:value]` chain appends a fresh
|
|
10217
|
+
// `{ book, reference }` entry. The chained `►` (tag_reference) lands
|
|
10218
|
+
// inside the most-recently-appended entry as `reference: $`.
|
|
10219
|
+
exportJsonKey: { book: [{ book: "$" }] },
|
|
8706
10220
|
description: "Book reference for the page, used to link to a specific book",
|
|
8707
10221
|
maxCount: Count.infinity,
|
|
8708
10222
|
chain: [
|
|
@@ -8770,7 +10284,9 @@ var BITS = {
|
|
|
8770
10284
|
format: TagFormat.plainText
|
|
8771
10285
|
}
|
|
8772
10286
|
],
|
|
8773
|
-
|
|
10287
|
+
// page-footer emits cards under `sections` (vs `listItems` for the
|
|
10288
|
+
// sibling exampleList / assignmentList bits) — see JsonGenerator.ts.
|
|
10289
|
+
cardSet: CardSetConfigKey.pageFooterSections
|
|
8774
10290
|
},
|
|
8775
10291
|
[BitType.legend]: {
|
|
8776
10292
|
since: "3.12.0",
|
|
@@ -8812,6 +10328,20 @@ var BITS = {
|
|
|
8812
10328
|
since: "1.34.0",
|
|
8813
10329
|
baseBitType: BitType._standard,
|
|
8814
10330
|
description: "Definition list bit, used to create lists of definitions in articles or books",
|
|
10331
|
+
tags: [
|
|
10332
|
+
{
|
|
10333
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10334
|
+
key: ConfigKey.property_example,
|
|
10335
|
+
exportJsonKey: [
|
|
10336
|
+
{ "@keyonly": { isExample: true } },
|
|
10337
|
+
{ "@absent": { isExample: true } },
|
|
10338
|
+
{ isExample: true, example: "$" }
|
|
10339
|
+
],
|
|
10340
|
+
description: "The example(s) for the bit",
|
|
10341
|
+
format: TagFormat.bitmarkText,
|
|
10342
|
+
nullable: true
|
|
10343
|
+
}
|
|
10344
|
+
],
|
|
8815
10345
|
cardSet: CardSetConfigKey.definitionList
|
|
8816
10346
|
},
|
|
8817
10347
|
[BitType.metaSearchDefaultTerms]: {
|
|
@@ -8834,6 +10364,18 @@ var BITS = {
|
|
|
8834
10364
|
{
|
|
8835
10365
|
key: ConfigKey.group_quizCommon,
|
|
8836
10366
|
description: "Common quiz tags for flashcards"
|
|
10367
|
+
},
|
|
10368
|
+
{
|
|
10369
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10370
|
+
key: ConfigKey.property_example,
|
|
10371
|
+
exportJsonKey: [
|
|
10372
|
+
{ "@keyonly": { isExample: true } },
|
|
10373
|
+
{ "@absent": { isExample: true } },
|
|
10374
|
+
{ isExample: true, example: "$" }
|
|
10375
|
+
],
|
|
10376
|
+
description: "The example(s) for the bit",
|
|
10377
|
+
format: TagFormat.bitmarkText,
|
|
10378
|
+
nullable: true
|
|
8837
10379
|
}
|
|
8838
10380
|
],
|
|
8839
10381
|
cardSet: CardSetConfigKey.flashcard
|
|
@@ -8841,7 +10383,11 @@ var BITS = {
|
|
|
8841
10383
|
[BitType.flashcard1]: {
|
|
8842
10384
|
since: "1.3.0",
|
|
8843
10385
|
baseBitType: BitType.flashcard,
|
|
8844
|
-
description: "Flashcard 1 bit"
|
|
10386
|
+
description: "Flashcard 1 bit",
|
|
10387
|
+
// PLAN-085: use the flashcard1 cardset (sections.default.maxCount=1)
|
|
10388
|
+
// instead of inheriting `flashcard`'s unbounded cardset, since this
|
|
10389
|
+
// bit type structurally allows only a single card.
|
|
10390
|
+
cardSet: CardSetConfigKey.flashcard1
|
|
8845
10391
|
},
|
|
8846
10392
|
[BitType.qAndACard]: {
|
|
8847
10393
|
since: "3.25.0",
|
|
@@ -8876,8 +10422,24 @@ var BITS = {
|
|
|
8876
10422
|
description: "Common quiz tags for highlighted text"
|
|
8877
10423
|
},
|
|
8878
10424
|
{
|
|
8879
|
-
|
|
8880
|
-
|
|
10425
|
+
// Dedicated highlight inline-select chain: tag_true / tag_false
|
|
10426
|
+
// emit `{type:"highlight", attrs:{texts:[{text,isCorrect?}]}}`
|
|
10427
|
+
// inline body nodes via @body-inline. Bit shares no tag IDs with
|
|
10428
|
+
// multiple-choice / multiple-choice-1 (which use group_trueFalse).
|
|
10429
|
+
key: ConfigKey.group_trueFalseInlineHighlight,
|
|
10430
|
+
description: "True/False quiz tags for highlighted text (inline body nodes)"
|
|
10431
|
+
},
|
|
10432
|
+
{
|
|
10433
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10434
|
+
key: ConfigKey.property_example,
|
|
10435
|
+
exportJsonKey: [
|
|
10436
|
+
{ "@keyonly": { isExample: true } },
|
|
10437
|
+
{ "@absent": { isExample: true } },
|
|
10438
|
+
{ isExample: true, example: "$" }
|
|
10439
|
+
],
|
|
10440
|
+
description: "The example(s) for the bit",
|
|
10441
|
+
format: TagFormat.bitmarkText,
|
|
10442
|
+
nullable: true
|
|
8881
10443
|
}
|
|
8882
10444
|
]
|
|
8883
10445
|
},
|
|
@@ -8887,15 +10449,8 @@ var BITS = {
|
|
|
8887
10449
|
description: "Image bit, used to create images in articles or books",
|
|
8888
10450
|
tags: [
|
|
8889
10451
|
{
|
|
8890
|
-
key: ConfigKey.
|
|
8891
|
-
|
|
8892
|
-
description: "Background wallpaper for the image, used to set a background for the image",
|
|
8893
|
-
chain: [
|
|
8894
|
-
{
|
|
8895
|
-
key: ConfigKey.group_resourceImageCommon,
|
|
8896
|
-
description: "Common resource image tags for images"
|
|
8897
|
-
}
|
|
8898
|
-
]
|
|
10452
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
10453
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
8899
10454
|
},
|
|
8900
10455
|
{
|
|
8901
10456
|
key: ConfigKey.group_resourceBitTags,
|
|
@@ -8998,8 +10553,15 @@ var BITS = {
|
|
|
8998
10553
|
},
|
|
8999
10554
|
[BitType.imageSeparator]: {
|
|
9000
10555
|
since: "1.4.15",
|
|
9001
|
-
baseBitType: BitType.
|
|
9002
|
-
description: "Image separator bit, used to create separators in articles or books"
|
|
10556
|
+
baseBitType: BitType._standard,
|
|
10557
|
+
description: "Image separator bit, used to create separators in articles or books",
|
|
10558
|
+
tags: [
|
|
10559
|
+
{
|
|
10560
|
+
key: ConfigKey.group_imageNoZoom,
|
|
10561
|
+
description: "Image no zoom tags for images, used to define whether images should have zoom functionality"
|
|
10562
|
+
}
|
|
10563
|
+
],
|
|
10564
|
+
resourceAttachmentAllowed: false
|
|
9003
10565
|
},
|
|
9004
10566
|
[BitType.imageSeparatorAlt]: {
|
|
9005
10567
|
since: "1.16.0",
|
|
@@ -9038,15 +10600,20 @@ var BITS = {
|
|
|
9038
10600
|
},
|
|
9039
10601
|
[BitType.pageBanner]: {
|
|
9040
10602
|
since: "1.4.3",
|
|
9041
|
-
baseBitType: BitType.
|
|
10603
|
+
baseBitType: BitType._standard,
|
|
9042
10604
|
description: "Page banner bit, used to create banners for pages in articles or books",
|
|
9043
10605
|
tags: [
|
|
9044
10606
|
{
|
|
9045
10607
|
key: ConfigKey.property_slug,
|
|
9046
10608
|
description: "Slug for the page banner, used to identify the banner in the system",
|
|
9047
10609
|
format: TagFormat.plainText
|
|
10610
|
+
},
|
|
10611
|
+
{
|
|
10612
|
+
key: ConfigKey.group_imageNoZoom,
|
|
10613
|
+
description: "Image no zoom tags for images, used to define whether images should have zoom functionality"
|
|
9048
10614
|
}
|
|
9049
|
-
]
|
|
10615
|
+
],
|
|
10616
|
+
resourceAttachmentAllowed: false
|
|
9050
10617
|
},
|
|
9051
10618
|
[BitType.pageHero]: {
|
|
9052
10619
|
since: "1.11.0",
|
|
@@ -9061,7 +10628,7 @@ var BITS = {
|
|
|
9061
10628
|
},
|
|
9062
10629
|
[BitType.tableImage]: {
|
|
9063
10630
|
since: "1.5.15",
|
|
9064
|
-
baseBitType: BitType.
|
|
10631
|
+
baseBitType: BitType.tableExtended,
|
|
9065
10632
|
description: "Table image bit, used to create images in tables in articles or books",
|
|
9066
10633
|
tags: [
|
|
9067
10634
|
{
|
|
@@ -9070,15 +10637,8 @@ var BITS = {
|
|
|
9070
10637
|
format: TagFormat.bitmarkText
|
|
9071
10638
|
},
|
|
9072
10639
|
{
|
|
9073
|
-
key: ConfigKey.
|
|
9074
|
-
|
|
9075
|
-
description: "Background wallpaper for the image, used to set a background for the image",
|
|
9076
|
-
chain: [
|
|
9077
|
-
{
|
|
9078
|
-
key: ConfigKey.group_resourceImageCommon,
|
|
9079
|
-
description: "Common resource image tags for images"
|
|
9080
|
-
}
|
|
9081
|
-
]
|
|
10640
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
10641
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
9082
10642
|
},
|
|
9083
10643
|
{
|
|
9084
10644
|
key: ConfigKey.group_resourceBitTags,
|
|
@@ -9221,10 +10781,10 @@ var BITS = {
|
|
|
9221
10781
|
description: "Resource bit tags for logo grave images, used to define additional properties"
|
|
9222
10782
|
},
|
|
9223
10783
|
{
|
|
9224
|
-
// Image resource
|
|
9225
|
-
key: ConfigKey.
|
|
10784
|
+
// Image resource — fully-expanded shape (see BitType.extractorImage).
|
|
10785
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
9226
10786
|
description: "Resource image tags for logo grave images, used to attach images",
|
|
9227
|
-
exportJsonKey: { logos: "$" },
|
|
10787
|
+
exportJsonKey: { logos: [{ type: "image", image: { src: "$" } }] },
|
|
9228
10788
|
minCount: 1,
|
|
9229
10789
|
maxCount: Count.infinity
|
|
9230
10790
|
}
|
|
@@ -9234,7 +10794,17 @@ var BITS = {
|
|
|
9234
10794
|
[BitType.prototypeImages]: {
|
|
9235
10795
|
since: "1.6.1",
|
|
9236
10796
|
baseBitType: BitType.imagesLogoGrave,
|
|
9237
|
-
description: "Prototype images bit, used to create prototype images in articles or books"
|
|
10797
|
+
description: "Prototype images bit, used to create prototype images in articles or books",
|
|
10798
|
+
tags: [
|
|
10799
|
+
{
|
|
10800
|
+
// Override inherited `logos` wrapper with `images` for this bit type.
|
|
10801
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
10802
|
+
description: "Resource image tags for prototype images",
|
|
10803
|
+
exportJsonKey: { images: [{ type: "image", image: { src: "$" } }] },
|
|
10804
|
+
minCount: 1,
|
|
10805
|
+
maxCount: Count.infinity
|
|
10806
|
+
}
|
|
10807
|
+
]
|
|
9238
10808
|
},
|
|
9239
10809
|
[BitType.internalLink]: {
|
|
9240
10810
|
since: "1.3.0",
|
|
@@ -9264,6 +10834,18 @@ var BITS = {
|
|
|
9264
10834
|
exportJsonKey: {},
|
|
9265
10835
|
description: "Reasonable number of characters for the interview, used to limit input size",
|
|
9266
10836
|
format: TagFormat.number
|
|
10837
|
+
},
|
|
10838
|
+
{
|
|
10839
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10840
|
+
key: ConfigKey.property_example,
|
|
10841
|
+
exportJsonKey: [
|
|
10842
|
+
{ "@keyonly": { isExample: true } },
|
|
10843
|
+
{ "@absent": { isExample: true } },
|
|
10844
|
+
{ isExample: true, example: "$" }
|
|
10845
|
+
],
|
|
10846
|
+
description: "The example(s) for the bit",
|
|
10847
|
+
format: TagFormat.bitmarkText,
|
|
10848
|
+
nullable: true
|
|
9267
10849
|
}
|
|
9268
10850
|
],
|
|
9269
10851
|
cardSet: CardSetConfigKey.questions
|
|
@@ -9622,6 +11204,18 @@ var BITS = {
|
|
|
9622
11204
|
{
|
|
9623
11205
|
key: ConfigKey.group_mark,
|
|
9624
11206
|
description: "Mark tags, used to define the content of marks"
|
|
11207
|
+
},
|
|
11208
|
+
{
|
|
11209
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11210
|
+
key: ConfigKey.property_example,
|
|
11211
|
+
exportJsonKey: [
|
|
11212
|
+
{ "@keyonly": { isExample: true } },
|
|
11213
|
+
{ "@absent": { isExample: true } },
|
|
11214
|
+
{ isExample: true, example: "$" }
|
|
11215
|
+
],
|
|
11216
|
+
description: "The example(s) for the bit",
|
|
11217
|
+
format: TagFormat.bitmarkText,
|
|
11218
|
+
nullable: true
|
|
9625
11219
|
}
|
|
9626
11220
|
]
|
|
9627
11221
|
},
|
|
@@ -9641,6 +11235,23 @@ var BITS = {
|
|
|
9641
11235
|
description: "Case sensitivity for matching pairs, used to define if matches are case-sensitive",
|
|
9642
11236
|
format: TagFormat.boolean,
|
|
9643
11237
|
defaultValue: "true"
|
|
11238
|
+
},
|
|
11239
|
+
{
|
|
11240
|
+
// Override inherited @example: in `isTopLevelExample` allow-list
|
|
11241
|
+
// (covers match, matchAll, matchReverse, matchAllReverse,
|
|
11242
|
+
// matchSolutionGrouped, matchMatrix, matchAudio, matchPicture).
|
|
11243
|
+
// Bit-level fires emit only `isExample`; the @example value (when
|
|
11244
|
+
// provided) is recorded in the ancestor stack and consumed by
|
|
11245
|
+
// per-pair/per-cell variant overrides — not surfaced at bit scope.
|
|
11246
|
+
key: ConfigKey.property_example,
|
|
11247
|
+
exportJsonKey: [
|
|
11248
|
+
{ "@keyonly": { isExample: true } },
|
|
11249
|
+
{ "@absent": { isExample: true } },
|
|
11250
|
+
{ isExample: true }
|
|
11251
|
+
],
|
|
11252
|
+
description: "The example(s) for the bit",
|
|
11253
|
+
format: TagFormat.bitmarkText,
|
|
11254
|
+
nullable: true
|
|
9644
11255
|
}
|
|
9645
11256
|
],
|
|
9646
11257
|
cardSet: CardSetConfigKey.matchPairs
|
|
@@ -9725,6 +11336,18 @@ var BITS = {
|
|
|
9725
11336
|
{
|
|
9726
11337
|
key: ConfigKey.group_trueFalse,
|
|
9727
11338
|
description: "True/False tags for multiple choice 1 questions"
|
|
11339
|
+
},
|
|
11340
|
+
{
|
|
11341
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11342
|
+
key: ConfigKey.property_example,
|
|
11343
|
+
exportJsonKey: [
|
|
11344
|
+
{ "@keyonly": { isExample: true } },
|
|
11345
|
+
{ "@absent": { isExample: true } },
|
|
11346
|
+
{ isExample: true, example: "$" }
|
|
11347
|
+
],
|
|
11348
|
+
description: "The example(s) for the bit",
|
|
11349
|
+
format: TagFormat.bitmarkText,
|
|
11350
|
+
nullable: true
|
|
9728
11351
|
}
|
|
9729
11352
|
]
|
|
9730
11353
|
},
|
|
@@ -9746,8 +11369,20 @@ var BITS = {
|
|
|
9746
11369
|
{
|
|
9747
11370
|
key: ConfigKey.group_trueFalse,
|
|
9748
11371
|
description: "True/False tags for multiple choice questions"
|
|
9749
|
-
}
|
|
11372
|
+
},
|
|
9750
11373
|
// This is actually for multiple-choice-1, but we support it here as well (as many bits are wrong)
|
|
11374
|
+
{
|
|
11375
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11376
|
+
key: ConfigKey.property_example,
|
|
11377
|
+
exportJsonKey: [
|
|
11378
|
+
{ "@keyonly": { isExample: true } },
|
|
11379
|
+
{ "@absent": { isExample: true } },
|
|
11380
|
+
{ isExample: true, example: "$" }
|
|
11381
|
+
],
|
|
11382
|
+
description: "The example(s) for the bit",
|
|
11383
|
+
format: TagFormat.bitmarkText,
|
|
11384
|
+
nullable: true
|
|
11385
|
+
}
|
|
9751
11386
|
],
|
|
9752
11387
|
cardSet: CardSetConfigKey.quiz
|
|
9753
11388
|
},
|
|
@@ -9767,8 +11402,20 @@ var BITS = {
|
|
|
9767
11402
|
description: "Common quiz tags for multiple choice text questions"
|
|
9768
11403
|
},
|
|
9769
11404
|
{
|
|
9770
|
-
key: ConfigKey.
|
|
11405
|
+
key: ConfigKey.group_trueFalseInlineSelect,
|
|
9771
11406
|
description: "True/False tags for multiple choice text questions"
|
|
11407
|
+
},
|
|
11408
|
+
{
|
|
11409
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11410
|
+
key: ConfigKey.property_example,
|
|
11411
|
+
exportJsonKey: [
|
|
11412
|
+
{ "@keyonly": { isExample: true } },
|
|
11413
|
+
{ "@absent": { isExample: true } },
|
|
11414
|
+
{ isExample: true, example: "$" }
|
|
11415
|
+
],
|
|
11416
|
+
description: "The example(s) for the bit",
|
|
11417
|
+
format: TagFormat.bitmarkText,
|
|
11418
|
+
nullable: true
|
|
9772
11419
|
}
|
|
9773
11420
|
]
|
|
9774
11421
|
},
|
|
@@ -9793,8 +11440,20 @@ var BITS = {
|
|
|
9793
11440
|
description: "Common quiz tags for multiple response 1 questions"
|
|
9794
11441
|
},
|
|
9795
11442
|
{
|
|
9796
|
-
key: ConfigKey.
|
|
11443
|
+
key: ConfigKey.group_trueFalseResponses,
|
|
9797
11444
|
description: "True/False tags for multiple response 1 questions"
|
|
11445
|
+
},
|
|
11446
|
+
{
|
|
11447
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11448
|
+
key: ConfigKey.property_example,
|
|
11449
|
+
exportJsonKey: [
|
|
11450
|
+
{ "@keyonly": { isExample: true } },
|
|
11451
|
+
{ "@absent": { isExample: true } },
|
|
11452
|
+
{ isExample: true, example: "$" }
|
|
11453
|
+
],
|
|
11454
|
+
description: "The example(s) for the bit",
|
|
11455
|
+
format: TagFormat.bitmarkText,
|
|
11456
|
+
nullable: true
|
|
9798
11457
|
}
|
|
9799
11458
|
]
|
|
9800
11459
|
},
|
|
@@ -9814,12 +11473,24 @@ var BITS = {
|
|
|
9814
11473
|
description: "Common quiz tags for multiple response questions"
|
|
9815
11474
|
},
|
|
9816
11475
|
{
|
|
9817
|
-
key: ConfigKey.
|
|
11476
|
+
key: ConfigKey.group_trueFalseResponses,
|
|
9818
11477
|
description: "True/False tags for multiple response questions"
|
|
9819
|
-
}
|
|
11478
|
+
},
|
|
9820
11479
|
// This is actually for multiple-response-1, but we support it here as well (as many bits are wrong)
|
|
11480
|
+
{
|
|
11481
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11482
|
+
key: ConfigKey.property_example,
|
|
11483
|
+
exportJsonKey: [
|
|
11484
|
+
{ "@keyonly": { isExample: true } },
|
|
11485
|
+
{ "@absent": { isExample: true } },
|
|
11486
|
+
{ isExample: true, example: "$" }
|
|
11487
|
+
],
|
|
11488
|
+
description: "The example(s) for the bit",
|
|
11489
|
+
format: TagFormat.bitmarkText,
|
|
11490
|
+
nullable: true
|
|
11491
|
+
}
|
|
9821
11492
|
],
|
|
9822
|
-
cardSet: CardSetConfigKey.
|
|
11493
|
+
cardSet: CardSetConfigKey.quizResponses
|
|
9823
11494
|
},
|
|
9824
11495
|
[BitType.coachSelfReflectionMultipleResponse]: {
|
|
9825
11496
|
since: "1.3.0",
|
|
@@ -10069,6 +11740,8 @@ var BITS = {
|
|
|
10069
11740
|
},
|
|
10070
11741
|
{
|
|
10071
11742
|
key: ConfigKey.resource_platformIcon,
|
|
11743
|
+
jsonKey: "platformIcon|resource(type=image, key=image)",
|
|
11744
|
+
exportJsonKey: { platformIcon: { type: "image", image: { src: "$" } } },
|
|
10072
11745
|
description: "The platform icon",
|
|
10073
11746
|
chain: [
|
|
10074
11747
|
{
|
|
@@ -10104,6 +11777,8 @@ var BITS = {
|
|
|
10104
11777
|
tags: [
|
|
10105
11778
|
{
|
|
10106
11779
|
key: ConfigKey.resource_platformLogo,
|
|
11780
|
+
jsonKey: "platformLogo|resource(type=image, key=image)",
|
|
11781
|
+
exportJsonKey: { platformLogo: { type: "image", image: { src: "$" } } },
|
|
10107
11782
|
description: "The platform logo",
|
|
10108
11783
|
chain: [
|
|
10109
11784
|
{
|
|
@@ -10315,7 +11990,8 @@ var BITS = {
|
|
|
10315
11990
|
{ isExample: true, example: "$" }
|
|
10316
11991
|
],
|
|
10317
11992
|
description: "The example text for the review note bit",
|
|
10318
|
-
format: TagFormat.plainText
|
|
11993
|
+
format: TagFormat.plainText,
|
|
11994
|
+
nullable: true
|
|
10319
11995
|
}
|
|
10320
11996
|
],
|
|
10321
11997
|
rootExampleType: ExampleType.string
|
|
@@ -10402,7 +12078,8 @@ var BITS = {
|
|
|
10402
12078
|
{ isExample: true, example: "$" }
|
|
10403
12079
|
],
|
|
10404
12080
|
description: "The example flag for the bit (boolean)",
|
|
10405
|
-
format: TagFormat.
|
|
12081
|
+
format: TagFormat.boolean,
|
|
12082
|
+
nullable: true
|
|
10406
12083
|
}
|
|
10407
12084
|
],
|
|
10408
12085
|
cardSet: CardSetConfigKey.elements,
|
|
@@ -10676,15 +12353,8 @@ var BITS = {
|
|
|
10676
12353
|
format: TagFormat.bitmarkText
|
|
10677
12354
|
},
|
|
10678
12355
|
{
|
|
10679
|
-
key: ConfigKey.
|
|
10680
|
-
|
|
10681
|
-
description: "Background wallpaper for the image, used to set a background for the image",
|
|
10682
|
-
chain: [
|
|
10683
|
-
{
|
|
10684
|
-
key: ConfigKey.group_resourceImageCommon,
|
|
10685
|
-
description: "Common resource image tags for images"
|
|
10686
|
-
}
|
|
10687
|
-
]
|
|
12356
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
12357
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
10688
12358
|
},
|
|
10689
12359
|
{
|
|
10690
12360
|
key: ConfigKey.group_resourceBitTags,
|
|
@@ -11061,16 +12731,20 @@ var BITS = {
|
|
|
11061
12731
|
format: TagFormat.plainText
|
|
11062
12732
|
},
|
|
11063
12733
|
{
|
|
11064
|
-
|
|
12734
|
+
// PLAN-067 Edit #1: true-false-1's `+` / `-` emit a flat
|
|
12735
|
+
// `{ statement, isCorrect }` at bit root (single-statement bit),
|
|
12736
|
+
// not a `choices[]` array. Format is bitmarkText so the statement
|
|
12737
|
+
// body renders as a ProseMirror tree, matching reference fixtures.
|
|
12738
|
+
exportJsonKey: { statement: "$", isCorrect: true },
|
|
11065
12739
|
key: ConfigKey.tag_true,
|
|
11066
12740
|
description: "Tag for the true option in the true/false question",
|
|
11067
|
-
format: TagFormat.
|
|
12741
|
+
format: TagFormat.bitmarkText
|
|
11068
12742
|
},
|
|
11069
12743
|
{
|
|
11070
|
-
exportJsonKey: {
|
|
12744
|
+
exportJsonKey: { statement: "$", isCorrect: false },
|
|
11071
12745
|
key: ConfigKey.tag_false,
|
|
11072
12746
|
description: "Tag for the false option in the true/false question",
|
|
11073
|
-
format: TagFormat.
|
|
12747
|
+
format: TagFormat.bitmarkText
|
|
11074
12748
|
},
|
|
11075
12749
|
{
|
|
11076
12750
|
// Override inherited @example from group_standardTags: boolean root
|
|
@@ -11081,14 +12755,24 @@ var BITS = {
|
|
|
11081
12755
|
// sufficient for `[+...]` (correct) statements which dominate the
|
|
11082
12756
|
// fixtures; `[-...]` (incorrect) bits with bare `[@example]` would
|
|
11083
12757
|
// need either a runtime extension or an explicit `[@example:false]`.
|
|
12758
|
+
//
|
|
12759
|
+
// Format is `boolean` so `[@example:false]` coerces to JSON `false`
|
|
12760
|
+
// (a natural default that gets stripped in optimised mode, matching
|
|
12761
|
+
// BPG's `rootExampleType: boolean`). PlainText would emit the
|
|
12762
|
+
// STRING `"false"` which doesn't strip.
|
|
11084
12763
|
key: ConfigKey.property_example,
|
|
11085
12764
|
exportJsonKey: [
|
|
11086
12765
|
{ "@keyonly": { isExample: true, example: true } },
|
|
11087
12766
|
{ "@absent": { isExample: true, example: true } },
|
|
12767
|
+
// `[@example:false]`: emit `isExample: true` only — `example: false`
|
|
12768
|
+
// is the natural default for boolean, stripped in optimised mode.
|
|
12769
|
+
// Mirrors BPG `removeUnwantedProperties` `ignoreAllFalse: true`.
|
|
12770
|
+
{ "@value=false": { isExample: true } },
|
|
11088
12771
|
{ isExample: true, example: "$" }
|
|
11089
12772
|
],
|
|
11090
12773
|
description: "The example flag for the bit (boolean)",
|
|
11091
|
-
format: TagFormat.
|
|
12774
|
+
format: TagFormat.boolean,
|
|
12775
|
+
nullable: true
|
|
11092
12776
|
}
|
|
11093
12777
|
],
|
|
11094
12778
|
rootExampleType: ExampleType.boolean
|
|
@@ -11112,6 +12796,18 @@ var BITS = {
|
|
|
11112
12796
|
key: ConfigKey.property_labelFalse,
|
|
11113
12797
|
description: "Label for the false option in the true/false question",
|
|
11114
12798
|
format: TagFormat.plainText
|
|
12799
|
+
},
|
|
12800
|
+
{
|
|
12801
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
12802
|
+
key: ConfigKey.property_example,
|
|
12803
|
+
exportJsonKey: [
|
|
12804
|
+
{ "@keyonly": { isExample: true } },
|
|
12805
|
+
{ "@absent": { isExample: true } },
|
|
12806
|
+
{ isExample: true, example: "$" }
|
|
12807
|
+
],
|
|
12808
|
+
description: "The example(s) for the bit",
|
|
12809
|
+
format: TagFormat.bitmarkText,
|
|
12810
|
+
nullable: true
|
|
11115
12811
|
}
|
|
11116
12812
|
],
|
|
11117
12813
|
cardSet: CardSetConfigKey.statements
|
|
@@ -11301,6 +12997,11 @@ var BITS = {
|
|
|
11301
12997
|
baseBitType: BitType.vendorStripePricingTable,
|
|
11302
12998
|
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
12999
|
tags: [
|
|
13000
|
+
{
|
|
13001
|
+
key: ConfigKey.property_stripePricingTableDescriptiveName,
|
|
13002
|
+
description: "Descriptive name for the Stripe pricing table",
|
|
13003
|
+
format: TagFormat.plainText
|
|
13004
|
+
},
|
|
11304
13005
|
{
|
|
11305
13006
|
key: ConfigKey.property_printOnRequestCustomerId,
|
|
11306
13007
|
description: "Print-on-request customer ID, used to identify the customer for the print-on-request flow",
|
|
@@ -11777,7 +13478,7 @@ var instance2 = new Config();
|
|
|
11777
13478
|
// src/generated/package_info.ts
|
|
11778
13479
|
var PACKAGE_INFO = {
|
|
11779
13480
|
"name": "@gmb/bitmark-parser-generator",
|
|
11780
|
-
"version": "5.
|
|
13481
|
+
"version": "5.24.0",
|
|
11781
13482
|
"author": "Get More Brain Ltd",
|
|
11782
13483
|
"license": "ISC",
|
|
11783
13484
|
"description": "A bitmark parser and generator using Peggy.js"
|
|
@@ -12742,6 +14443,8 @@ var NodeType = {
|
|
|
12742
14443
|
stillImageFilmLink: "stillImageFilmLink",
|
|
12743
14444
|
stripePricingTableId: "stripePricingTableId",
|
|
12744
14445
|
stripePricingTableIdValue: "stripePricingTableIdValue",
|
|
14446
|
+
stripePricingTableDescriptiveName: "stripePricingTableDescriptiveName",
|
|
14447
|
+
stripePricingTableDescriptiveNameValue: "stripePricingTableDescriptiveNameValue",
|
|
12745
14448
|
stripePublishableKey: "stripePublishableKey",
|
|
12746
14449
|
stripePublishableKeyValue: "stripePublishableKeyValue",
|
|
12747
14450
|
subject: "subject",
|
|
@@ -26167,6 +27870,12 @@ var Builder = class extends BaseBuilder {
|
|
|
26167
27870
|
data.stripePricingTableId,
|
|
26168
27871
|
options
|
|
26169
27872
|
),
|
|
27873
|
+
stripePricingTableDescriptiveName: this.toAstProperty(
|
|
27874
|
+
bitType,
|
|
27875
|
+
ConfigKey.property_stripePricingTableDescriptiveName,
|
|
27876
|
+
data.stripePricingTableDescriptiveName,
|
|
27877
|
+
options
|
|
27878
|
+
),
|
|
26170
27879
|
stripePublishableKey: this.toAstProperty(
|
|
26171
27880
|
bitType,
|
|
26172
27881
|
ConfigKey.property_stripePublishableKey,
|
|
@@ -34412,6 +36121,7 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
34412
36121
|
const cardSetType = bitConfig.cardSet?.configKey;
|
|
34413
36122
|
switch (cardSetType) {
|
|
34414
36123
|
case CardSetConfigKey.flashcard:
|
|
36124
|
+
case CardSetConfigKey.flashcard1:
|
|
34415
36125
|
case CardSetConfigKey.definitionList:
|
|
34416
36126
|
result = parseFlashcardOrDefinitionList(context, bitType, processedCardSet);
|
|
34417
36127
|
break;
|
|
@@ -34425,6 +36135,7 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
34425
36135
|
result = parseFeedback(context, bitType, processedCardSet);
|
|
34426
36136
|
break;
|
|
34427
36137
|
case CardSetConfigKey.quiz:
|
|
36138
|
+
case CardSetConfigKey.quizResponses:
|
|
34428
36139
|
result = parseQuiz(context, bitType, processedCardSet, choicesV1, responsesV1);
|
|
34429
36140
|
break;
|
|
34430
36141
|
case CardSetConfigKey.questions:
|
|
@@ -34451,6 +36162,7 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
34451
36162
|
break;
|
|
34452
36163
|
case CardSetConfigKey.clozeList:
|
|
34453
36164
|
case CardSetConfigKey.exampleBitList:
|
|
36165
|
+
case CardSetConfigKey.pageFooterSections:
|
|
34454
36166
|
case CardSetConfigKey.bookReferenceList:
|
|
34455
36167
|
result = parseCardBits(context, bitType, textFormat, processedCardSet);
|
|
34456
36168
|
break;
|
|
@@ -41245,6 +42957,13 @@ var ConfigBuilder = class {
|
|
|
41245
42957
|
const cardSetConfig = CARDSETS[cardSetKey];
|
|
41246
42958
|
if (!cardSetConfig) return void 0;
|
|
41247
42959
|
const normalizedKey = normalizeCardKey(cardSetKey);
|
|
42960
|
+
const variantTagEntriesTypeOrder = [
|
|
42961
|
+
BitTagConfigKeyType.group,
|
|
42962
|
+
BitTagConfigKeyType.tag,
|
|
42963
|
+
BitTagConfigKeyType.property,
|
|
42964
|
+
BitTagConfigKeyType.resource,
|
|
42965
|
+
BitTagConfigKeyType.unknown
|
|
42966
|
+
];
|
|
41248
42967
|
const sides = cardSetConfig.sides.map((side, sideIdx) => {
|
|
41249
42968
|
const sidePath = `cardSets.${normalizedKey} / sides.${side.name ?? `[${sideIdx}]`}`;
|
|
41250
42969
|
const variants = side.variants.map((variant, variantIdx) => {
|
|
@@ -41255,7 +42974,7 @@ var ConfigBuilder = class {
|
|
|
41255
42974
|
const tagB = b[1];
|
|
41256
42975
|
const typeA = typeFromConfigKey(tagA.key);
|
|
41257
42976
|
const typeB = typeFromConfigKey(tagB.key);
|
|
41258
|
-
const typeOrder =
|
|
42977
|
+
const typeOrder = variantTagEntriesTypeOrder.indexOf(typeA) - variantTagEntriesTypeOrder.indexOf(typeB);
|
|
41259
42978
|
return typeOrder;
|
|
41260
42979
|
});
|
|
41261
42980
|
for (const [, variantTag] of variantTagEntries) {
|
|
@@ -41295,6 +43014,10 @@ var ConfigBuilder = class {
|
|
|
41295
43014
|
name: sectionName,
|
|
41296
43015
|
...section.isDefault ? { isDefault: true } : {},
|
|
41297
43016
|
...cardJsonKeyField(section, "jsonKey", "exportJsonKey", sectionPath),
|
|
43017
|
+
// PLAN-085: per-section cardinality. Emit only when non-default
|
|
43018
|
+
// (treat `0` / undefined as "unbounded — omit").
|
|
43019
|
+
...section.minCount != null && section.minCount !== 0 ? { min: section.minCount } : {},
|
|
43020
|
+
...section.maxCount != null && section.maxCount !== 0 ? { max: section.maxCount } : {},
|
|
41298
43021
|
sides: cardSides
|
|
41299
43022
|
};
|
|
41300
43023
|
});
|
|
@@ -41364,10 +43087,20 @@ var ConfigBuilder = class {
|
|
|
41364
43087
|
return typeOrder;
|
|
41365
43088
|
});
|
|
41366
43089
|
const isInheritedFrom = bitGroupConfigKeys.has(b.bitType);
|
|
43090
|
+
const indexByKey = /* @__PURE__ */ new Map();
|
|
43091
|
+
const pushOrReplace = (entry) => {
|
|
43092
|
+
const existing = indexByKey.get(entry.key);
|
|
43093
|
+
if (existing !== void 0) {
|
|
43094
|
+
tags2[existing] = entry;
|
|
43095
|
+
} else {
|
|
43096
|
+
indexByKey.set(entry.key, tags2.length);
|
|
43097
|
+
tags2.push(entry);
|
|
43098
|
+
}
|
|
43099
|
+
};
|
|
41367
43100
|
if (isInheritedFrom) {
|
|
41368
43101
|
const resolvedGroups = resolveGroupReferences(`group-${b.bitType}`);
|
|
41369
43102
|
for (const ref of resolvedGroups) {
|
|
41370
|
-
|
|
43103
|
+
pushOrReplace({
|
|
41371
43104
|
type: "group",
|
|
41372
43105
|
key: ref.key,
|
|
41373
43106
|
...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
|
|
@@ -41380,7 +43113,7 @@ var ConfigBuilder = class {
|
|
|
41380
43113
|
if (b.baseBitType) {
|
|
41381
43114
|
const resolvedGroups = resolveGroupReferences(`group-${b.baseBitType}`);
|
|
41382
43115
|
for (const ref of resolvedGroups) {
|
|
41383
|
-
|
|
43116
|
+
pushOrReplace({
|
|
41384
43117
|
type: "group",
|
|
41385
43118
|
key: ref.key,
|
|
41386
43119
|
...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
|
|
@@ -41391,7 +43124,9 @@ var ConfigBuilder = class {
|
|
|
41391
43124
|
}
|
|
41392
43125
|
}
|
|
41393
43126
|
for (const [_tagKey, tag] of tagEntries) {
|
|
41394
|
-
|
|
43127
|
+
for (const entry of processTagEntries(tag, [])) {
|
|
43128
|
+
pushOrReplace(entry);
|
|
43129
|
+
}
|
|
41395
43130
|
}
|
|
41396
43131
|
}
|
|
41397
43132
|
let cardRef;
|