@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/cli/main.js
CHANGED
|
@@ -709,10 +709,12 @@ var TextFormat = {
|
|
|
709
709
|
};
|
|
710
710
|
var CardSetConfigKey = {
|
|
711
711
|
flashcard: "flashcard",
|
|
712
|
+
flashcard1: "flashcard1",
|
|
712
713
|
definitionList: "definitionList",
|
|
713
714
|
elements: "elements",
|
|
714
715
|
statements: "statements",
|
|
715
716
|
quiz: "quiz",
|
|
717
|
+
quizResponses: "quizResponses",
|
|
716
718
|
feedback: "feedback",
|
|
717
719
|
questions: "questions",
|
|
718
720
|
matchPairs: "matchPairs",
|
|
@@ -724,6 +726,7 @@ var CardSetConfigKey = {
|
|
|
724
726
|
pronunciationTable: "pronunciationTable",
|
|
725
727
|
botActionResponses: "botActionResponses",
|
|
726
728
|
exampleBitList: "exampleBitList",
|
|
729
|
+
pageFooterSections: "pageFooterSections",
|
|
727
730
|
clozeList: "clozeList",
|
|
728
731
|
ingredients: "ingredients",
|
|
729
732
|
// DEPRECATED - TO BE REMOVED IN THE FUTURE
|
|
@@ -1128,12 +1131,17 @@ var groupKeys = {
|
|
|
1128
1131
|
group_standardAllBits: "group_standardAllBits",
|
|
1129
1132
|
group_standardItemLead: "group_standardItemLead",
|
|
1130
1133
|
group_standardItemLeadInstructionHint: "group_standardItemLeadInstructionHint",
|
|
1134
|
+
group_standardInstructionHint: "group_standardInstructionHint",
|
|
1131
1135
|
group_standardTags: "group_standardTags",
|
|
1136
|
+
group_standardTagsNoItemLead: "group_standardTagsNoItemLead",
|
|
1132
1137
|
group_imageSource: "group_imageSource",
|
|
1133
1138
|
group_technicalTerm: "group_technicalTerm",
|
|
1134
1139
|
group_person: "group_person",
|
|
1135
1140
|
group_gap: "group_gap",
|
|
1136
1141
|
group_trueFalse: "group_trueFalse",
|
|
1142
|
+
group_trueFalseInlineHighlight: "group_trueFalseInlineHighlight",
|
|
1143
|
+
group_trueFalseInlineSelect: "group_trueFalseInlineSelect",
|
|
1144
|
+
group_trueFalseResponses: "group_trueFalseResponses",
|
|
1137
1145
|
group_markConfig: "group_markConfig",
|
|
1138
1146
|
group_mark: "group_mark",
|
|
1139
1147
|
group_bookCommon: "group_bookCommon",
|
|
@@ -1141,14 +1149,18 @@ var groupKeys = {
|
|
|
1141
1149
|
group_advertisingCommon: "group_advertisingCommon",
|
|
1142
1150
|
group_platformStylesCommon: "group_platformStylesCommon",
|
|
1143
1151
|
group_quizCommon: "group_quizCommon",
|
|
1152
|
+
group_backgroundWallpaper: "group_backgroundWallpaper",
|
|
1153
|
+
group_imageNoZoom: "group_imageNoZoom",
|
|
1144
1154
|
group_resourceBitTags: "group_resourceBitTags",
|
|
1145
1155
|
group_resourceCommon: "group_resourceCommon",
|
|
1146
1156
|
group_resourceImageCommon: "group_resourceImageCommon",
|
|
1157
|
+
group_resourceImageCommonNoZoom: "group_resourceImageCommonNoZoom",
|
|
1147
1158
|
group_resourceAudioCommon: "group_resourceAudioCommon",
|
|
1148
1159
|
group_resourceVideoCommon: "group_resourceVideoCommon",
|
|
1149
1160
|
group_resourceIcon: "group_resourceIcon",
|
|
1150
1161
|
// Alias for image
|
|
1151
1162
|
group_resourceImage: "group_resourceImage",
|
|
1163
|
+
group_resourceImageNoZoom: "group_resourceImageNoZoom",
|
|
1152
1164
|
group_resourceImageEmbed: "group_resourceImageEmbed",
|
|
1153
1165
|
group_resourceImageLink: "group_resourceImageLink",
|
|
1154
1166
|
group_resourceImageResponsive: "group_resourceImageResponsive",
|
|
@@ -1422,6 +1434,7 @@ var propertyKeys = {
|
|
|
1422
1434
|
property_src4x: "@src4x",
|
|
1423
1435
|
property_srcAlt: "@srcAlt",
|
|
1424
1436
|
property_stripePricingTableId: "@stripePricingTableId",
|
|
1437
|
+
property_stripePricingTableDescriptiveName: "@stripePricingTableDescriptiveName",
|
|
1425
1438
|
property_stripePublishableKey: "@stripePublishableKey",
|
|
1426
1439
|
property_subject: "@subject",
|
|
1427
1440
|
property_subtype: "@subtype",
|
|
@@ -2164,7 +2177,7 @@ var CARDSETS = {
|
|
|
2164
2177
|
variants: [
|
|
2165
2178
|
{
|
|
2166
2179
|
jsonKey: "question.text",
|
|
2167
|
-
exportJsonKey: { question: { text: "$" } },
|
|
2180
|
+
exportJsonKey: [{ "@absent": { question: {} } }, { question: { text: "$" } }],
|
|
2168
2181
|
tags: [
|
|
2169
2182
|
{
|
|
2170
2183
|
key: ConfigKey.group_standardTags,
|
|
@@ -2180,6 +2193,136 @@ var CARDSETS = {
|
|
|
2180
2193
|
description: "Icon resource for the flashcard.",
|
|
2181
2194
|
jsonKey: "question.icon|resource(type=image, key=image)",
|
|
2182
2195
|
exportJsonKey: { question: { icon: { type: "image", image: { src: "$" } } } }
|
|
2196
|
+
},
|
|
2197
|
+
{
|
|
2198
|
+
key: ConfigKey.property_example,
|
|
2199
|
+
exportJsonKey: [
|
|
2200
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2201
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2202
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2203
|
+
],
|
|
2204
|
+
description: "Example marker for the flashcard question.",
|
|
2205
|
+
format: TagFormat.bitmarkText,
|
|
2206
|
+
nullable: true
|
|
2207
|
+
}
|
|
2208
|
+
]
|
|
2209
|
+
}
|
|
2210
|
+
]
|
|
2211
|
+
},
|
|
2212
|
+
{
|
|
2213
|
+
name: "answer",
|
|
2214
|
+
variants: [
|
|
2215
|
+
{
|
|
2216
|
+
jsonKey: "answer.text",
|
|
2217
|
+
exportJsonKey: [{ "@absent": { answer: {} } }, { answer: { text: "$" } }],
|
|
2218
|
+
tags: [
|
|
2219
|
+
{
|
|
2220
|
+
key: ConfigKey.group_standardTags,
|
|
2221
|
+
description: "Standard tags for the flashcard."
|
|
2222
|
+
},
|
|
2223
|
+
{
|
|
2224
|
+
exportJsonKey: { title: "$" },
|
|
2225
|
+
key: ConfigKey.tag_title,
|
|
2226
|
+
description: "Title of the flashcard."
|
|
2227
|
+
},
|
|
2228
|
+
{
|
|
2229
|
+
key: ConfigKey.group_resourceIcon,
|
|
2230
|
+
description: "Icon resource for the flashcard.",
|
|
2231
|
+
jsonKey: "answer.icon|resource(type=image, key=image)",
|
|
2232
|
+
exportJsonKey: { answer: { icon: { type: "image", image: { src: "$" } } } }
|
|
2233
|
+
},
|
|
2234
|
+
{
|
|
2235
|
+
key: ConfigKey.property_example,
|
|
2236
|
+
exportJsonKey: [
|
|
2237
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2238
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2239
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2240
|
+
],
|
|
2241
|
+
description: "Example marker for the flashcard answer.",
|
|
2242
|
+
format: TagFormat.bitmarkText,
|
|
2243
|
+
nullable: true
|
|
2244
|
+
}
|
|
2245
|
+
]
|
|
2246
|
+
},
|
|
2247
|
+
{
|
|
2248
|
+
jsonKey: "alternativeAnswers[].text",
|
|
2249
|
+
exportJsonKey: { alternativeAnswers: [{ text: "$" }] },
|
|
2250
|
+
tags: [
|
|
2251
|
+
{
|
|
2252
|
+
key: ConfigKey.group_standardTags,
|
|
2253
|
+
description: "Standard tags for the flashcard."
|
|
2254
|
+
},
|
|
2255
|
+
{
|
|
2256
|
+
exportJsonKey: { title: "$" },
|
|
2257
|
+
key: ConfigKey.tag_title,
|
|
2258
|
+
description: "Title of the flashcard."
|
|
2259
|
+
},
|
|
2260
|
+
{
|
|
2261
|
+
key: ConfigKey.group_resourceIcon,
|
|
2262
|
+
description: "Icon resource for the flashcard.",
|
|
2263
|
+
jsonKey: "alternativeAnswers[].icon|resource(type=image, key=image)",
|
|
2264
|
+
exportJsonKey: {
|
|
2265
|
+
alternativeAnswers: [{ icon: { type: "image", image: { src: "$" } } }]
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
],
|
|
2269
|
+
repeatCount: Count.infinity
|
|
2270
|
+
}
|
|
2271
|
+
]
|
|
2272
|
+
}
|
|
2273
|
+
]
|
|
2274
|
+
},
|
|
2275
|
+
//
|
|
2276
|
+
// flashcard1 — single-card variant of flashcard. Same shape, but capped
|
|
2277
|
+
// at one card via `sections.default.maxCount = 1` (PLAN-085). Used by
|
|
2278
|
+
// the `flashcard-1` bit type; the multi-card `flashcard` and
|
|
2279
|
+
// `q-and-a-card` bit types continue to use the unbounded `flashcard`
|
|
2280
|
+
// cardset.
|
|
2281
|
+
//
|
|
2282
|
+
[CardSetConfigKey.flashcard1]: {
|
|
2283
|
+
jsonKey: "cards",
|
|
2284
|
+
exportJsonKey: { cards: "$" },
|
|
2285
|
+
sections: {
|
|
2286
|
+
default: {
|
|
2287
|
+
jsonKey: "cards",
|
|
2288
|
+
exportJsonKey: { cards: "$" },
|
|
2289
|
+
isDefault: true,
|
|
2290
|
+
maxCount: 1
|
|
2291
|
+
}
|
|
2292
|
+
},
|
|
2293
|
+
sides: [
|
|
2294
|
+
{
|
|
2295
|
+
name: "question",
|
|
2296
|
+
variants: [
|
|
2297
|
+
{
|
|
2298
|
+
jsonKey: "question.text",
|
|
2299
|
+
exportJsonKey: [{ "@absent": { question: {} } }, { question: { text: "$" } }],
|
|
2300
|
+
tags: [
|
|
2301
|
+
{
|
|
2302
|
+
key: ConfigKey.group_standardTags,
|
|
2303
|
+
description: "Standard tags for the flashcard."
|
|
2304
|
+
},
|
|
2305
|
+
{
|
|
2306
|
+
exportJsonKey: { title: "$" },
|
|
2307
|
+
key: ConfigKey.tag_title,
|
|
2308
|
+
description: "Title of the flashcard."
|
|
2309
|
+
},
|
|
2310
|
+
{
|
|
2311
|
+
key: ConfigKey.group_resourceIcon,
|
|
2312
|
+
description: "Icon resource for the flashcard.",
|
|
2313
|
+
jsonKey: "question.icon|resource(type=image, key=image)",
|
|
2314
|
+
exportJsonKey: { question: { icon: { type: "image", image: { src: "$" } } } }
|
|
2315
|
+
},
|
|
2316
|
+
{
|
|
2317
|
+
key: ConfigKey.property_example,
|
|
2318
|
+
exportJsonKey: [
|
|
2319
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2320
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2321
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2322
|
+
],
|
|
2323
|
+
description: "Example marker for the flashcard question.",
|
|
2324
|
+
format: TagFormat.bitmarkText,
|
|
2325
|
+
nullable: true
|
|
2183
2326
|
}
|
|
2184
2327
|
]
|
|
2185
2328
|
}
|
|
@@ -2190,7 +2333,7 @@ var CARDSETS = {
|
|
|
2190
2333
|
variants: [
|
|
2191
2334
|
{
|
|
2192
2335
|
jsonKey: "answer.text",
|
|
2193
|
-
exportJsonKey: { answer: { text: "$" } },
|
|
2336
|
+
exportJsonKey: [{ "@absent": { answer: {} } }, { answer: { text: "$" } }],
|
|
2194
2337
|
tags: [
|
|
2195
2338
|
{
|
|
2196
2339
|
key: ConfigKey.group_standardTags,
|
|
@@ -2206,6 +2349,17 @@ var CARDSETS = {
|
|
|
2206
2349
|
description: "Icon resource for the flashcard.",
|
|
2207
2350
|
jsonKey: "answer.icon|resource(type=image, key=image)",
|
|
2208
2351
|
exportJsonKey: { answer: { icon: { type: "image", image: { src: "$" } } } }
|
|
2352
|
+
},
|
|
2353
|
+
{
|
|
2354
|
+
key: ConfigKey.property_example,
|
|
2355
|
+
exportJsonKey: [
|
|
2356
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2357
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2358
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2359
|
+
],
|
|
2360
|
+
description: "Example marker for the flashcard answer.",
|
|
2361
|
+
format: TagFormat.bitmarkText,
|
|
2362
|
+
nullable: true
|
|
2209
2363
|
}
|
|
2210
2364
|
]
|
|
2211
2365
|
},
|
|
@@ -2249,7 +2403,7 @@ var CARDSETS = {
|
|
|
2249
2403
|
variants: [
|
|
2250
2404
|
{
|
|
2251
2405
|
jsonKey: "term.text",
|
|
2252
|
-
exportJsonKey: { term: { text: "$" } },
|
|
2406
|
+
exportJsonKey: [{ "@absent": { term: {} } }, { term: { text: "$" } }],
|
|
2253
2407
|
tags: [
|
|
2254
2408
|
{
|
|
2255
2409
|
key: ConfigKey.group_standardTags,
|
|
@@ -2268,6 +2422,17 @@ var CARDSETS = {
|
|
|
2268
2422
|
format: TagFormat.plainText,
|
|
2269
2423
|
jsonKey: "term.icon|resource(type=image, key=image)",
|
|
2270
2424
|
exportJsonKey: { term: { icon: { type: "image", image: { src: "$" } } } }
|
|
2425
|
+
},
|
|
2426
|
+
{
|
|
2427
|
+
key: ConfigKey.property_example,
|
|
2428
|
+
exportJsonKey: [
|
|
2429
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2430
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2431
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2432
|
+
],
|
|
2433
|
+
description: "Example marker for the definition term.",
|
|
2434
|
+
format: TagFormat.bitmarkText,
|
|
2435
|
+
nullable: true
|
|
2271
2436
|
}
|
|
2272
2437
|
]
|
|
2273
2438
|
}
|
|
@@ -2278,7 +2443,7 @@ var CARDSETS = {
|
|
|
2278
2443
|
variants: [
|
|
2279
2444
|
{
|
|
2280
2445
|
jsonKey: "definition.text",
|
|
2281
|
-
exportJsonKey: { definition: { text: "$" } },
|
|
2446
|
+
exportJsonKey: [{ "@absent": { definition: {} } }, { definition: { text: "$" } }],
|
|
2282
2447
|
tags: [
|
|
2283
2448
|
{
|
|
2284
2449
|
key: ConfigKey.group_standardTags,
|
|
@@ -2296,6 +2461,17 @@ var CARDSETS = {
|
|
|
2296
2461
|
description: "Icon resource for the definition.",
|
|
2297
2462
|
jsonKey: "definition.icon|resource(type=image, key=image)",
|
|
2298
2463
|
exportJsonKey: { definition: { icon: { type: "image", image: { src: "$" } } } }
|
|
2464
|
+
},
|
|
2465
|
+
{
|
|
2466
|
+
key: ConfigKey.property_example,
|
|
2467
|
+
exportJsonKey: [
|
|
2468
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2469
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2470
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2471
|
+
],
|
|
2472
|
+
description: "Example marker for the definition.",
|
|
2473
|
+
format: TagFormat.bitmarkText,
|
|
2474
|
+
nullable: true
|
|
2299
2475
|
}
|
|
2300
2476
|
]
|
|
2301
2477
|
},
|
|
@@ -2340,11 +2516,51 @@ var CARDSETS = {
|
|
|
2340
2516
|
{
|
|
2341
2517
|
jsonKey: "key",
|
|
2342
2518
|
exportJsonKey: { key: "$" },
|
|
2519
|
+
format: TextFormat.plainText,
|
|
2343
2520
|
tags: [
|
|
2344
2521
|
{
|
|
2345
2522
|
key: ConfigKey.group_standardTags,
|
|
2346
2523
|
description: "Standard tags for the match pair."
|
|
2347
2524
|
},
|
|
2525
|
+
{
|
|
2526
|
+
// Pair-level example: emit `isExample` alongside `example`
|
|
2527
|
+
// (matches OLD parser's per-pair allow-list behaviour).
|
|
2528
|
+
//
|
|
2529
|
+
// PLAN-074: a valued cascade source (`[@example:V]` anywhere
|
|
2530
|
+
// in the cardset) fills each pair's `example` with `V`
|
|
2531
|
+
// once per pair from the keys-side cascade fire (single
|
|
2532
|
+
// parsed_variant per pair — no per-value duplication).
|
|
2533
|
+
//
|
|
2534
|
+
// PLAN-076 NOTE: matchPairs (TAG 415) KEEPS `example: '$'`
|
|
2535
|
+
// at the pair-object level. BPG `parseMatchPairs`
|
|
2536
|
+
// (`CardContentProcessor.ts:714-723`) emits ONE example
|
|
2537
|
+
// per PAIR (the `exampleCard` accumulator), placed at the
|
|
2538
|
+
// pair object. Unlike matchMatrix (per-cell example),
|
|
2539
|
+
// matchPairs has no nested per-cell layer, so the pair-key
|
|
2540
|
+
// `[@example:V]` must double-emit as the visible field.
|
|
2541
|
+
// Confirmed via `chaining` fixture: `match-solution-grouped`
|
|
2542
|
+
// expects `example: "packen"` at pair-object level from
|
|
2543
|
+
// `die Koffer[%1][@example:packen]`. Original PLAN-076
|
|
2544
|
+
// draft applied to both keys-side tags; the matchPairs
|
|
2545
|
+
// half was reverted after fixture parity testing.
|
|
2546
|
+
key: ConfigKey.property_example,
|
|
2547
|
+
exportJsonKey: [
|
|
2548
|
+
{ "@keyonly": { isExample: true, "@bit": { isExample: true } } },
|
|
2549
|
+
{
|
|
2550
|
+
predicates: ["@absent", { $cascade: "*" }],
|
|
2551
|
+
rule: {
|
|
2552
|
+
isExample: true,
|
|
2553
|
+
example: "$cascade",
|
|
2554
|
+
"@bit": { isExample: true }
|
|
2555
|
+
}
|
|
2556
|
+
},
|
|
2557
|
+
{ "@absent": { isExample: true } },
|
|
2558
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2559
|
+
],
|
|
2560
|
+
description: "Example marker / value on the match pair.",
|
|
2561
|
+
format: TagFormat.bitmarkText,
|
|
2562
|
+
nullable: true
|
|
2563
|
+
},
|
|
2348
2564
|
{
|
|
2349
2565
|
key: ConfigKey.tag_title,
|
|
2350
2566
|
description: "Title of the match pair.",
|
|
@@ -2353,9 +2569,19 @@ var CARDSETS = {
|
|
|
2353
2569
|
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2354
2570
|
},
|
|
2355
2571
|
{
|
|
2572
|
+
// PLAN-084: gate the key-side `@absent → $ancestor` cascade
|
|
2573
|
+
// synth with `@variantLacksTag=isCaseSensitive` so the rule
|
|
2574
|
+
// only fires when NO variant in the active card explicitly
|
|
2575
|
+
// carries `[@isCaseSensitive]`. When a value-side variant
|
|
2576
|
+
// carries the tag (e.g. `[@isCaseSensitive:false]`), the
|
|
2577
|
+
// synth is skipped here; the value-side explicit fire owns
|
|
2578
|
+
// the pair-level emission.
|
|
2356
2579
|
key: ConfigKey.property_isCaseSensitive,
|
|
2357
2580
|
exportJsonKey: [
|
|
2358
|
-
{
|
|
2581
|
+
{
|
|
2582
|
+
predicates: ["@absent", { "@variantLacksTag": "@isCaseSensitive" }],
|
|
2583
|
+
rule: { isCaseSensitive: "$ancestor" }
|
|
2584
|
+
},
|
|
2359
2585
|
{ isCaseSensitive: "$" }
|
|
2360
2586
|
],
|
|
2361
2587
|
description: "Property to indicate if the match is case sensitive.",
|
|
@@ -2384,10 +2610,85 @@ var CARDSETS = {
|
|
|
2384
2610
|
{
|
|
2385
2611
|
jsonKey: "values[]",
|
|
2386
2612
|
exportJsonKey: { values: ["$"] },
|
|
2613
|
+
format: TextFormat.plainText,
|
|
2387
2614
|
tags: [
|
|
2388
2615
|
{
|
|
2389
|
-
|
|
2390
|
-
|
|
2616
|
+
// PLAN-084: value-side excludes item/lead/pageNumber/marginNumber.
|
|
2617
|
+
// BPG `parseMatchPairs` does `delete tags.item; delete tags.lead;`
|
|
2618
|
+
// for sideIdx > 0; the schema-side equivalent is to use a
|
|
2619
|
+
// group_standardTags variant that omits group_standardItemLead.
|
|
2620
|
+
key: ConfigKey.group_standardTagsNoItemLead,
|
|
2621
|
+
description: "Standard tags for the match pair (values side, no item/lead)."
|
|
2622
|
+
},
|
|
2623
|
+
{
|
|
2624
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.6: cascade-fired
|
|
2625
|
+
// `@example` from the bit header fills each pair's
|
|
2626
|
+
// `example` with the pair's first value (mirrors BPG's
|
|
2627
|
+
// `fillStringExample(pairs, __defaultExample=values[0])`).
|
|
2628
|
+
//
|
|
2629
|
+
// PLAN-074: the cascade-source-VALUE branch is handled by
|
|
2630
|
+
// TAG 415 (keys side) which fires once per pair — keeping
|
|
2631
|
+
// it here would emit `example` twice per pair (one per
|
|
2632
|
+
// values-side parsed_variant) and merge them into a
|
|
2633
|
+
// multi-paragraph array.
|
|
2634
|
+
//
|
|
2635
|
+
// PLAN-075: bare `$parent` reads the parent variant fire's
|
|
2636
|
+
// source `$` value (the current `++`-iteration's value
|
|
2637
|
+
// text). For single-value pairs this matches the old
|
|
2638
|
+
// `$parent.values[0]`; for multi-value pairs with
|
|
2639
|
+
// `[@example]` attached to a non-first value, it correctly
|
|
2640
|
+
// resolves to that value.
|
|
2641
|
+
//
|
|
2642
|
+
// PLAN-077: dual `[@absent, { '$cascade': '*' }]` rule
|
|
2643
|
+
// routes pair-key `[@example:V]` (a per-pair cascade
|
|
2644
|
+
// source, bound via per-card CascadeCounters scope) and
|
|
2645
|
+
// bit-header `[@example:V]` (cardset cascade) into the
|
|
2646
|
+
// pair-level `example` via `$cascade`. The aggregator in
|
|
2647
|
+
// `populate_variants` fires this rule ONCE per pair (BPG
|
|
2648
|
+
// `parseMatchPairs` `exampleCard` precedence), avoiding
|
|
2649
|
+
// per-iter pollution.
|
|
2650
|
+
key: ConfigKey.property_example,
|
|
2651
|
+
exportJsonKey: [
|
|
2652
|
+
// PLAN-084: bare `[@example]` on a values-side variant fires
|
|
2653
|
+
// once per pair (first-wins, mirrors BPG `parseMatchPairs`
|
|
2654
|
+
// `exampleCard` + `pushDownTree` set-if-null semantic).
|
|
2655
|
+
// `maxEmits: 1` enforced inside the per-pair cascade-counter
|
|
2656
|
+
// scope opened by `build_card_item`.
|
|
2657
|
+
{
|
|
2658
|
+
predicates: ["@keyonly"],
|
|
2659
|
+
maxEmits: 1,
|
|
2660
|
+
rule: {
|
|
2661
|
+
isExample: true,
|
|
2662
|
+
example: "$parent",
|
|
2663
|
+
"@bit": { isExample: true }
|
|
2664
|
+
}
|
|
2665
|
+
},
|
|
2666
|
+
{
|
|
2667
|
+
predicates: ["@absent", { $cascade: "*" }],
|
|
2668
|
+
rule: {
|
|
2669
|
+
isExample: true,
|
|
2670
|
+
example: "$cascade",
|
|
2671
|
+
"@bit": { isExample: true }
|
|
2672
|
+
}
|
|
2673
|
+
},
|
|
2674
|
+
{
|
|
2675
|
+
"@absent": {
|
|
2676
|
+
isExample: true,
|
|
2677
|
+
example: "$parent",
|
|
2678
|
+
"@bit": { isExample: true }
|
|
2679
|
+
}
|
|
2680
|
+
},
|
|
2681
|
+
// PLAN-084: same cap applies to the explicit-value `[@example:V]`
|
|
2682
|
+
// form so per-`++`-iter values-side fires also first-win.
|
|
2683
|
+
{
|
|
2684
|
+
predicates: [],
|
|
2685
|
+
maxEmits: 1,
|
|
2686
|
+
rule: { isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2687
|
+
}
|
|
2688
|
+
],
|
|
2689
|
+
description: "Example marker / value on the match pair (values side).",
|
|
2690
|
+
format: TagFormat.bitmarkText,
|
|
2691
|
+
nullable: true
|
|
2391
2692
|
},
|
|
2392
2693
|
{
|
|
2393
2694
|
key: ConfigKey.tag_title,
|
|
@@ -2397,9 +2698,13 @@ var CARDSETS = {
|
|
|
2397
2698
|
exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
|
|
2398
2699
|
},
|
|
2399
2700
|
{
|
|
2701
|
+
// PLAN-084: symmetric @variantLacksTag gating with the key-side.
|
|
2400
2702
|
key: ConfigKey.property_isCaseSensitive,
|
|
2401
2703
|
exportJsonKey: [
|
|
2402
|
-
{
|
|
2704
|
+
{
|
|
2705
|
+
predicates: ["@absent", { "@variantLacksTag": "@isCaseSensitive" }],
|
|
2706
|
+
rule: { isCaseSensitive: "$ancestor" }
|
|
2707
|
+
},
|
|
2403
2708
|
{ isCaseSensitive: "$" }
|
|
2404
2709
|
],
|
|
2405
2710
|
description: "Property to indicate if the match is case sensitive.",
|
|
@@ -2425,6 +2730,7 @@ var CARDSETS = {
|
|
|
2425
2730
|
{
|
|
2426
2731
|
jsonKey: "key",
|
|
2427
2732
|
exportJsonKey: { key: "$" },
|
|
2733
|
+
format: TextFormat.plainText,
|
|
2428
2734
|
tags: [
|
|
2429
2735
|
{
|
|
2430
2736
|
key: ConfigKey.group_standardTags,
|
|
@@ -2454,10 +2760,12 @@ var CARDSETS = {
|
|
|
2454
2760
|
{
|
|
2455
2761
|
jsonKey: "values[]",
|
|
2456
2762
|
exportJsonKey: { values: ["$"] },
|
|
2763
|
+
format: TextFormat.plainText,
|
|
2457
2764
|
tags: [
|
|
2458
2765
|
{
|
|
2459
|
-
|
|
2460
|
-
|
|
2766
|
+
// PLAN-084: value-side excludes item/lead/pageNumber/marginNumber.
|
|
2767
|
+
key: ConfigKey.group_standardTagsNoItemLead,
|
|
2768
|
+
description: "Standard tags for the audio match pair (values side, no item/lead)."
|
|
2461
2769
|
},
|
|
2462
2770
|
{
|
|
2463
2771
|
key: ConfigKey.tag_title,
|
|
@@ -2490,6 +2798,7 @@ var CARDSETS = {
|
|
|
2490
2798
|
{
|
|
2491
2799
|
jsonKey: "key",
|
|
2492
2800
|
exportJsonKey: { key: "$" },
|
|
2801
|
+
format: TextFormat.plainText,
|
|
2493
2802
|
tags: [
|
|
2494
2803
|
{
|
|
2495
2804
|
key: ConfigKey.group_standardTags,
|
|
@@ -2519,10 +2828,12 @@ var CARDSETS = {
|
|
|
2519
2828
|
{
|
|
2520
2829
|
jsonKey: "values[]",
|
|
2521
2830
|
exportJsonKey: { values: ["$"] },
|
|
2831
|
+
format: TextFormat.plainText,
|
|
2522
2832
|
tags: [
|
|
2523
2833
|
{
|
|
2524
|
-
|
|
2525
|
-
|
|
2834
|
+
// PLAN-084: value-side excludes item/lead/pageNumber/marginNumber.
|
|
2835
|
+
key: ConfigKey.group_standardTagsNoItemLead,
|
|
2836
|
+
description: "Standard tags for the image match pair (values side, no item/lead)."
|
|
2526
2837
|
},
|
|
2527
2838
|
{
|
|
2528
2839
|
key: ConfigKey.tag_title,
|
|
@@ -2555,20 +2866,49 @@ var CARDSETS = {
|
|
|
2555
2866
|
{
|
|
2556
2867
|
jsonKey: "key",
|
|
2557
2868
|
exportJsonKey: { key: "$" },
|
|
2869
|
+
format: TextFormat.plainText,
|
|
2558
2870
|
tags: [
|
|
2559
2871
|
{
|
|
2560
2872
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2561
2873
|
description: "Standard tags for lead, instruction, and hint."
|
|
2562
2874
|
},
|
|
2563
2875
|
{
|
|
2876
|
+
// PLAN-076: drop `example: '$'` from valued rule — pair-key
|
|
2877
|
+
// `[@example:V]` is consumed as the per-pair cascade source.
|
|
2878
|
+
// PLAN-077 R14 follow-up: investigation showed the fixture
|
|
2879
|
+
// reference is INCONSISTENT — bits without a cardset-level
|
|
2880
|
+
// cascade (e.g. bit 3 `[@example:Y]should be...`) expect
|
|
2881
|
+
// pair-level `example: V` at pair scope, but bits WITH a
|
|
2882
|
+
// cardset cascade (e.g. bit 8 `[@example:99]` in title-row
|
|
2883
|
+
// PLUS pair-key `[@example:Y]`) expect NO pair-level
|
|
2884
|
+
// example. Emitting `example: $` here satisfies bit 3 but
|
|
2885
|
+
// breaks bit 8; dropping it satisfies bit 8 but breaks bit
|
|
2886
|
+
// 3. Conditional emission would require runtime gating on
|
|
2887
|
+
// the cardset cascade scope state. Left dropped pending a
|
|
2888
|
+
// dedicated plan — accepted divergence on bit 3's pair-
|
|
2889
|
+
// level emission (cells still get the per-cell `example`
|
|
2890
|
+
// correctly via PLAN-077 §4.2 + §4.3).
|
|
2564
2891
|
key: ConfigKey.property_example,
|
|
2565
2892
|
exportJsonKey: [
|
|
2566
|
-
{
|
|
2567
|
-
|
|
2568
|
-
|
|
2893
|
+
{
|
|
2894
|
+
"@keyonly": {
|
|
2895
|
+
isExample: true,
|
|
2896
|
+
"@bit": { isExample: true },
|
|
2897
|
+
"@card": { isExample: true }
|
|
2898
|
+
}
|
|
2899
|
+
},
|
|
2900
|
+
{
|
|
2901
|
+
"@absent": {
|
|
2902
|
+
isExample: true,
|
|
2903
|
+
"@bit": { isExample: true },
|
|
2904
|
+
"@card": { isExample: true }
|
|
2905
|
+
}
|
|
2906
|
+
},
|
|
2907
|
+
{ isExample: true, "@bit": { isExample: true }, "@card": { isExample: true } }
|
|
2569
2908
|
],
|
|
2570
2909
|
description: "Example text for the match matrix.",
|
|
2571
|
-
format: TagFormat.plainText
|
|
2910
|
+
format: TagFormat.plainText,
|
|
2911
|
+
nullable: true
|
|
2572
2912
|
},
|
|
2573
2913
|
{
|
|
2574
2914
|
key: ConfigKey.tag_title,
|
|
@@ -2596,35 +2936,96 @@ var CARDSETS = {
|
|
|
2596
2936
|
variants: [
|
|
2597
2937
|
{
|
|
2598
2938
|
jsonKey: "cells[{s}].values[]",
|
|
2599
|
-
exportJsonKey:
|
|
2939
|
+
exportJsonKey: [
|
|
2940
|
+
// PLAN-085 / R14: the positional-blank emission for an
|
|
2941
|
+
// effectively-absent cell side fires ONLY when the active
|
|
2942
|
+
// card has at least one `[#]` variant fire. This matches
|
|
2943
|
+
// BPG `extractHeadingCard`'s `isHeading` gate: when no
|
|
2944
|
+
// `[#]` exists anywhere in the title card, BPG returns
|
|
2945
|
+
// undefined and no `heading` is emitted. The phantom
|
|
2946
|
+
// `forValues:['']` placeholder is appropriate only when
|
|
2947
|
+
// the card is being treated as a title-row.
|
|
2948
|
+
{
|
|
2949
|
+
predicates: ["@absent", { "@variantHasTag": "#" }],
|
|
2950
|
+
rule: { "@bit": { heading: { forValues: [""] } } }
|
|
2951
|
+
},
|
|
2952
|
+
{ cells: { $s: { values: ["$"] } } }
|
|
2953
|
+
],
|
|
2954
|
+
format: TextFormat.plainText,
|
|
2600
2955
|
tags: [
|
|
2601
2956
|
{
|
|
2602
2957
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2603
2958
|
description: "Standard tags for lead, instruction, and hint."
|
|
2604
2959
|
},
|
|
2605
2960
|
{
|
|
2961
|
+
// PLAN-075: bare `$parent` reads the parent variant fire's
|
|
2962
|
+
// source `$` value (the current `++`-iteration's cell text).
|
|
2963
|
+
// Replaces `$parent.values[0]` which pinned to position 0
|
|
2964
|
+
// regardless of which `++`-value `[@example]` was on.
|
|
2965
|
+
//
|
|
2966
|
+
// PLAN-077: dual `[@absent, { '$cascade': '*' }]` rule
|
|
2967
|
+
// routes pair-key `[@example:V]` (a per-pair cascade
|
|
2968
|
+
// source, bound via per-card CascadeCounters scope) and
|
|
2969
|
+
// bit-header `[@example:V]` (cardset cascade) into the
|
|
2970
|
+
// per-cell `example` via `$cascade`. The aggregator in
|
|
2971
|
+
// `populate_variants` fires this rule ONCE per cell (BPG
|
|
2972
|
+
// `parseMatchMatrix` `exampleSide` precedence), avoiding
|
|
2973
|
+
// per-iter pollution.
|
|
2974
|
+
// @card scope-shift writes matrix-row container isExample.
|
|
2606
2975
|
key: ConfigKey.property_example,
|
|
2607
2976
|
exportJsonKey: [
|
|
2608
2977
|
{
|
|
2609
2978
|
"@keyonly": {
|
|
2610
|
-
cells: { $s: { isExample: true, example: "$parent
|
|
2611
|
-
"@bit": { isExample: true }
|
|
2979
|
+
cells: { $s: { isExample: true, example: "$parent" } },
|
|
2980
|
+
"@bit": { isExample: true },
|
|
2981
|
+
"@card": { isExample: true }
|
|
2612
2982
|
}
|
|
2613
2983
|
},
|
|
2614
2984
|
{
|
|
2615
|
-
"@absent"
|
|
2985
|
+
predicates: ["@absent", { $cascade: "*" }],
|
|
2986
|
+
rule: {
|
|
2987
|
+
cells: { $s: { isExample: true, example: "$cascade" } },
|
|
2988
|
+
"@bit": { isExample: true },
|
|
2989
|
+
"@card": { isExample: true }
|
|
2990
|
+
}
|
|
2616
2991
|
},
|
|
2617
|
-
{
|
|
2992
|
+
{
|
|
2993
|
+
"@absent": {
|
|
2994
|
+
cells: { $s: { isExample: true, example: "$parent" } },
|
|
2995
|
+
"@bit": { isExample: true },
|
|
2996
|
+
"@card": { isExample: true }
|
|
2997
|
+
}
|
|
2998
|
+
},
|
|
2999
|
+
{
|
|
3000
|
+
cells: { $s: { isExample: true, example: "$" } },
|
|
3001
|
+
"@bit": { isExample: true },
|
|
3002
|
+
"@card": { isExample: true }
|
|
3003
|
+
}
|
|
2618
3004
|
],
|
|
2619
3005
|
description: "Example text for the match matrix.",
|
|
2620
|
-
format: TagFormat.
|
|
3006
|
+
format: TagFormat.bitmarkText,
|
|
3007
|
+
nullable: true
|
|
2621
3008
|
},
|
|
2622
3009
|
{
|
|
3010
|
+
// PLAN-085 / R14: bare `[#]` on a value-side emits the
|
|
3011
|
+
// empty-string positional blank into `forValues` so the
|
|
3012
|
+
// array stays aligned with the cell positions (matches BPG
|
|
3013
|
+
// `extractHeadingCard`'s "all value-side headings present"
|
|
3014
|
+
// shape). The `@keyonly` rule is required for two reasons:
|
|
3015
|
+
// 1) it provides an emission for bare `[#]` (the `$` sigil
|
|
3016
|
+
// in the unconditional rule has no source for bare); and
|
|
3017
|
+
// 2) the presence of any `@keyonly` rule disables the
|
|
3018
|
+
// optimised-mode `should_suppress_outcome` strip (see
|
|
3019
|
+
// `forward_emit.rs`) so the resulting `forValues: [""]`
|
|
3020
|
+
// survives the all-natural-defaults check.
|
|
2623
3021
|
key: ConfigKey.tag_title,
|
|
2624
3022
|
description: "Title of the match matrix.",
|
|
2625
3023
|
format: TagFormat.plainText,
|
|
2626
3024
|
jsonKey: "^heading.forValues",
|
|
2627
|
-
exportJsonKey:
|
|
3025
|
+
exportJsonKey: [
|
|
3026
|
+
{ "@keyonly": { "@bit": { heading: { forValues: [""] } } } },
|
|
3027
|
+
{ "@bit": { heading: { forValues: ["$"] } } }
|
|
3028
|
+
]
|
|
2628
3029
|
},
|
|
2629
3030
|
{
|
|
2630
3031
|
key: ConfigKey.property_isCaseSensitive,
|
|
@@ -2673,6 +3074,35 @@ var CARDSETS = {
|
|
|
2673
3074
|
{
|
|
2674
3075
|
key: ConfigKey.group_standardTags,
|
|
2675
3076
|
description: "Standard tags for the statement."
|
|
3077
|
+
},
|
|
3078
|
+
{
|
|
3079
|
+
// PLAN-072: cascade-fired `@example` from the bit header
|
|
3080
|
+
// fills each statement entry's `example` with the entry's
|
|
3081
|
+
// own `isCorrect`, mirroring BPG's `pushExampleDownTree`
|
|
3082
|
+
// for the statements cardset. Per-array-item strip removes
|
|
3083
|
+
// `example: false` from incorrect entries so only correct
|
|
3084
|
+
// entries retain `example: true`.
|
|
3085
|
+
key: ConfigKey.property_example,
|
|
3086
|
+
exportJsonKey: [
|
|
3087
|
+
{
|
|
3088
|
+
"@keyonly": {
|
|
3089
|
+
isExample: true,
|
|
3090
|
+
example: true,
|
|
3091
|
+
"@bit": { isExample: true }
|
|
3092
|
+
}
|
|
3093
|
+
},
|
|
3094
|
+
{
|
|
3095
|
+
"@absent": {
|
|
3096
|
+
isExample: true,
|
|
3097
|
+
example: "$parent.isCorrect",
|
|
3098
|
+
"@bit": { isExample: true }
|
|
3099
|
+
}
|
|
3100
|
+
},
|
|
3101
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3102
|
+
],
|
|
3103
|
+
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`.",
|
|
3104
|
+
format: TagFormat.boolean,
|
|
3105
|
+
nullable: true
|
|
2676
3106
|
}
|
|
2677
3107
|
],
|
|
2678
3108
|
bodyAllowed: false
|
|
@@ -2701,6 +3131,71 @@ var CARDSETS = {
|
|
|
2701
3131
|
{
|
|
2702
3132
|
key: ConfigKey.group_standardTags,
|
|
2703
3133
|
description: "Standard tags for the quiz."
|
|
3134
|
+
},
|
|
3135
|
+
{
|
|
3136
|
+
// ALIGN-EXAMPLE-CASCADE §3.2: variant-level cascade for
|
|
3137
|
+
// quiz choices is delegated to group_trueFalse's
|
|
3138
|
+
// chain-child `@example` (`+` chain with maxEmits:1 +
|
|
3139
|
+
// `@parent.isCorrect=true`). Variant-level `@absent`
|
|
3140
|
+
// would over-fire on subsequent correct choices and on
|
|
3141
|
+
// incorrect ones — drop it.
|
|
3142
|
+
key: ConfigKey.property_example,
|
|
3143
|
+
exportJsonKey: [
|
|
3144
|
+
{ "@keyonly": { isExample: true, "@bit": { isExample: true } } },
|
|
3145
|
+
{ isExample: true, "@bit": { isExample: true } }
|
|
3146
|
+
],
|
|
3147
|
+
description: "Example marker on the quiz choice (entry-local only; cascade handled by group_trueFalse chain-children).",
|
|
3148
|
+
format: TagFormat.boolean,
|
|
3149
|
+
nullable: true
|
|
3150
|
+
}
|
|
3151
|
+
],
|
|
3152
|
+
bodyAllowed: false
|
|
3153
|
+
}
|
|
3154
|
+
]
|
|
3155
|
+
}
|
|
3156
|
+
]
|
|
3157
|
+
},
|
|
3158
|
+
//
|
|
3159
|
+
// quiz (responses)
|
|
3160
|
+
//
|
|
3161
|
+
[CardSetConfigKey.quizResponses]: {
|
|
3162
|
+
jsonKey: "quizzes",
|
|
3163
|
+
exportJsonKey: { quizzes: "$" },
|
|
3164
|
+
sides: [
|
|
3165
|
+
{
|
|
3166
|
+
name: "responses",
|
|
3167
|
+
variants: [
|
|
3168
|
+
{
|
|
3169
|
+
jsonKey: null,
|
|
3170
|
+
tags: [
|
|
3171
|
+
{
|
|
3172
|
+
key: ConfigKey.group_trueFalseResponses,
|
|
3173
|
+
description: "Group for true/false questions."
|
|
3174
|
+
},
|
|
3175
|
+
{
|
|
3176
|
+
key: ConfigKey.group_standardTags,
|
|
3177
|
+
description: "Standard tags for the quiz."
|
|
3178
|
+
},
|
|
3179
|
+
{
|
|
3180
|
+
// PLAN-072: cascade-fired `@example` from the bit header
|
|
3181
|
+
// fills each response entry's `example` with the entry's
|
|
3182
|
+
// own `isCorrect`, mirroring BPG's `pushExampleDownTree`
|
|
3183
|
+
// for the quiz-responses cardset (statements-style).
|
|
3184
|
+
key: ConfigKey.property_example,
|
|
3185
|
+
exportJsonKey: [
|
|
3186
|
+
{ "@keyonly": { isExample: true, "@bit": { isExample: true } } },
|
|
3187
|
+
{
|
|
3188
|
+
"@absent": {
|
|
3189
|
+
isExample: true,
|
|
3190
|
+
example: "$parent.isCorrect",
|
|
3191
|
+
"@bit": { isExample: true }
|
|
3192
|
+
}
|
|
3193
|
+
},
|
|
3194
|
+
{ isExample: true, "@bit": { isExample: true } }
|
|
3195
|
+
],
|
|
3196
|
+
description: "Example marker on the quiz response; cascade from bit-header fills `example` with the entry\u2019s own `isCorrect`.",
|
|
3197
|
+
format: TagFormat.boolean,
|
|
3198
|
+
nullable: true
|
|
2704
3199
|
}
|
|
2705
3200
|
],
|
|
2706
3201
|
bodyAllowed: false
|
|
@@ -2726,6 +3221,73 @@ var CARDSETS = {
|
|
|
2726
3221
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2727
3222
|
description: "Standard tags for lead, instruction, and hint."
|
|
2728
3223
|
},
|
|
3224
|
+
{
|
|
3225
|
+
// Feedback choices: `[+]` / `[-]` map to choice + `requireReason`
|
|
3226
|
+
// (NOT `isCorrect` like trueFalse). Shadow the inherited
|
|
3227
|
+
// `tag_true` / `tag_false` from `group_trueFalse` to emit the
|
|
3228
|
+
// feedback-specific shape.
|
|
3229
|
+
//
|
|
3230
|
+
// Chain @example: `[+ X][@example]` writes
|
|
3231
|
+
// `isExample/example` onto the X choice only. BPG's
|
|
3232
|
+
// `setIsExampleFlags` (Builder.ts:4041-4172) does NOT
|
|
3233
|
+
// iterate `cardNode.feedbacks` — so unlike multipleChoice,
|
|
3234
|
+
// there is no bubble to bit-level or feedbacks-level
|
|
3235
|
+
// isExample. Pattern omits `@bit` scope-shift accordingly.
|
|
3236
|
+
// No `@absent`/`@parent.isCorrect` cascade rules either:
|
|
3237
|
+
// BPG's `pushExampleDownTree` (Builder.ts:3777-3849) has
|
|
3238
|
+
// no feedback dispatch, so bit-header `[@example]` does
|
|
3239
|
+
// not flow into feedback choices.
|
|
3240
|
+
key: ConfigKey.tag_true,
|
|
3241
|
+
exportJsonKey: { choices: [{ choice: "$", requireReason: true }] },
|
|
3242
|
+
description: "Reason-required choice for feedback (`[+]`).",
|
|
3243
|
+
maxCount: Count.infinity,
|
|
3244
|
+
format: TagFormat.plainText,
|
|
3245
|
+
chain: [
|
|
3246
|
+
{
|
|
3247
|
+
key: ConfigKey.property_example,
|
|
3248
|
+
exportJsonKey: [
|
|
3249
|
+
{ "@keyonly": { isExample: true, example: true } },
|
|
3250
|
+
{ isExample: true, example: "$" }
|
|
3251
|
+
],
|
|
3252
|
+
description: "Per-choice example marker for feedback `[+]`.",
|
|
3253
|
+
format: TagFormat.boolean,
|
|
3254
|
+
maxCount: 1,
|
|
3255
|
+
nullable: true
|
|
3256
|
+
},
|
|
3257
|
+
{
|
|
3258
|
+
// `[+ X][! foo]` chains `!` (instruction) onto the
|
|
3259
|
+
// choice; same for `[?]` (hint), `[%]` (item),
|
|
3260
|
+
// `[%2]`/`[%3]`/`[%4]` (lead/pageNumber/marginNumber).
|
|
3261
|
+
// Mirrors group_trueFalse's `+` chain shape.
|
|
3262
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3263
|
+
description: "Item, lead, page number, margin number, instruction and hint chained onto the feedback choice."
|
|
3264
|
+
}
|
|
3265
|
+
]
|
|
3266
|
+
},
|
|
3267
|
+
{
|
|
3268
|
+
key: ConfigKey.tag_false,
|
|
3269
|
+
exportJsonKey: { choices: [{ choice: "$", requireReason: false }] },
|
|
3270
|
+
description: "Reason-not-required choice for feedback (`[-]`).",
|
|
3271
|
+
maxCount: Count.infinity,
|
|
3272
|
+
format: TagFormat.plainText,
|
|
3273
|
+
chain: [
|
|
3274
|
+
{
|
|
3275
|
+
key: ConfigKey.property_example,
|
|
3276
|
+
exportJsonKey: [
|
|
3277
|
+
{ "@keyonly": { isExample: true, example: true } },
|
|
3278
|
+
{ isExample: true, example: "$" }
|
|
3279
|
+
],
|
|
3280
|
+
description: "Per-choice example marker for feedback `[-]`.",
|
|
3281
|
+
format: TagFormat.boolean,
|
|
3282
|
+
maxCount: 1,
|
|
3283
|
+
nullable: true
|
|
3284
|
+
},
|
|
3285
|
+
{
|
|
3286
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3287
|
+
description: "Item, lead, page number, margin number, instruction and hint chained onto the feedback choice."
|
|
3288
|
+
}
|
|
3289
|
+
]
|
|
3290
|
+
},
|
|
2729
3291
|
{
|
|
2730
3292
|
key: ConfigKey.group_trueFalse,
|
|
2731
3293
|
description: "Group for true/false feedback."
|
|
@@ -2746,31 +3308,71 @@ var CARDSETS = {
|
|
|
2746
3308
|
name: "reason",
|
|
2747
3309
|
variants: [
|
|
2748
3310
|
{
|
|
3311
|
+
// PLAN: feedback.reason — Object-only variant pattern. Per
|
|
3312
|
+
// SYNTAX.md §8.1, sibling tag emissions do NOT auto-wrap
|
|
3313
|
+
// under `reason.*`; each tag here spells out the full path.
|
|
3314
|
+
// Body is a plain string (BPG `parseFeedback` uses
|
|
3315
|
+
// `cardBodyStr ?? ''` for `reason.text`).
|
|
2749
3316
|
jsonKey: "reason.text",
|
|
2750
3317
|
exportJsonKey: { reason: { text: "$" } },
|
|
3318
|
+
format: TextFormat.plainText,
|
|
2751
3319
|
tags: [
|
|
2752
3320
|
{
|
|
2753
|
-
|
|
2754
|
-
|
|
3321
|
+
// Instruction lands under reason. Hint/item/lead/etc.
|
|
3322
|
+
// omitted: not exercised by any fixture and BPG's
|
|
3323
|
+
// `parseFeedback` spreads only the tags actually present
|
|
3324
|
+
// — adding the rest can be done lazily as fixtures
|
|
3325
|
+
// require them, with the same `{reason: {…}}` wrapper.
|
|
3326
|
+
key: ConfigKey.tag_instruction,
|
|
3327
|
+
exportJsonKey: { reason: { instruction: "$" } },
|
|
3328
|
+
description: "Instruction for the feedback reason.",
|
|
3329
|
+
format: TagFormat.bitmarkText
|
|
2755
3330
|
},
|
|
2756
3331
|
{
|
|
2757
3332
|
key: ConfigKey.property_reasonableNumOfChars,
|
|
2758
3333
|
exportJsonKey: [
|
|
2759
|
-
{ "@absent": { reasonableNumOfChars: "$ancestor" } },
|
|
2760
|
-
{ reasonableNumOfChars: "$" }
|
|
3334
|
+
{ "@absent": { reason: { reasonableNumOfChars: "$ancestor" } } },
|
|
3335
|
+
{ reason: { reasonableNumOfChars: "$" } }
|
|
2761
3336
|
],
|
|
2762
3337
|
description: "Property for reasonable number of characters.",
|
|
2763
3338
|
format: TagFormat.number
|
|
2764
3339
|
},
|
|
2765
3340
|
{
|
|
3341
|
+
// ALIGN-EXAMPLE-CASCADE §3.9: `feedback.reason` is NOT in
|
|
3342
|
+
// BPG's `pushExampleDownTree` dispatch — no bit-header
|
|
3343
|
+
// cascade. Local emission only.
|
|
3344
|
+
//
|
|
3345
|
+
// Both `reason.example` and `feedbacks[].example` are
|
|
3346
|
+
// `TextAst` per BPG's schema — paragraph arrays. Format
|
|
3347
|
+
// here is `bitmarkText` so `$` coerces to a paragraph
|
|
3348
|
+
// array at both write sites.
|
|
2766
3349
|
key: ConfigKey.property_example,
|
|
2767
3350
|
exportJsonKey: [
|
|
2768
|
-
{
|
|
2769
|
-
|
|
2770
|
-
|
|
3351
|
+
{
|
|
3352
|
+
// Bare `[@example]`: reason.example is TextAst — BPG
|
|
3353
|
+
// coerces the boolean default to a paragraph
|
|
3354
|
+
// containing the string "true". feedbacks[].example
|
|
3355
|
+
// is not TextAst, stays a boolean. Two literal writes.
|
|
3356
|
+
"@keyonly": {
|
|
3357
|
+
reason: {
|
|
3358
|
+
isExample: true,
|
|
3359
|
+
example: [{ type: "paragraph", content: [{ text: "true", type: "text" }] }]
|
|
3360
|
+
},
|
|
3361
|
+
isExample: true,
|
|
3362
|
+
example: true,
|
|
3363
|
+
"@bit": { isExample: true }
|
|
3364
|
+
}
|
|
3365
|
+
},
|
|
3366
|
+
{
|
|
3367
|
+
reason: { isExample: true, example: "$" },
|
|
3368
|
+
isExample: true,
|
|
3369
|
+
example: "$",
|
|
3370
|
+
"@bit": { isExample: true }
|
|
3371
|
+
}
|
|
2771
3372
|
],
|
|
2772
|
-
description: "Example text for the feedback.",
|
|
2773
|
-
format: TagFormat.
|
|
3373
|
+
description: "Example text for the feedback reason (entry-local only; no bit-header cascade).",
|
|
3374
|
+
format: TagFormat.bitmarkText,
|
|
3375
|
+
nullable: true
|
|
2774
3376
|
},
|
|
2775
3377
|
{
|
|
2776
3378
|
key: ConfigKey.tag_title,
|
|
@@ -2834,6 +3436,22 @@ var CARDSETS = {
|
|
|
2834
3436
|
{
|
|
2835
3437
|
key: ConfigKey.group_standardTags,
|
|
2836
3438
|
description: "Standard tags for the question."
|
|
3439
|
+
},
|
|
3440
|
+
{
|
|
3441
|
+
// ALIGN-EXAMPLE-CASCADE §3.10: `questions` is NOT in BPG's
|
|
3442
|
+
// `pushExampleDownTree` dispatch — bit-header `[@example]`
|
|
3443
|
+
// does not propagate `example`/`isExample` onto question
|
|
3444
|
+
// entries. Only entry-local `[@example]` fires (handled by
|
|
3445
|
+
// `@keyonly` and the unconditional fallback). No `@absent`
|
|
3446
|
+
// rule.
|
|
3447
|
+
key: ConfigKey.property_example,
|
|
3448
|
+
exportJsonKey: [
|
|
3449
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
3450
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3451
|
+
],
|
|
3452
|
+
description: "Example marker for the question (entry-local only; no bit-header cascade).",
|
|
3453
|
+
format: TagFormat.bitmarkText,
|
|
3454
|
+
nullable: true
|
|
2837
3455
|
}
|
|
2838
3456
|
]
|
|
2839
3457
|
}
|
|
@@ -2860,14 +3478,16 @@ var CARDSETS = {
|
|
|
2860
3478
|
description: "Standard tags for lead, instruction, and hint."
|
|
2861
3479
|
},
|
|
2862
3480
|
{
|
|
3481
|
+
// ALIGN-EXAMPLE-CASCADE §3.11: `elements` is NOT in BPG's
|
|
3482
|
+
// `pushExampleDownTree` dispatch — no bit-header cascade.
|
|
2863
3483
|
key: ConfigKey.property_example,
|
|
2864
3484
|
exportJsonKey: [
|
|
2865
3485
|
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2866
|
-
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2867
3486
|
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2868
3487
|
],
|
|
2869
|
-
description: "Example text for the element.",
|
|
2870
|
-
format: TagFormat.plainText
|
|
3488
|
+
description: "Example text for the element (entry-local only; no bit-header cascade).",
|
|
3489
|
+
format: TagFormat.plainText,
|
|
3490
|
+
nullable: true
|
|
2871
3491
|
}
|
|
2872
3492
|
],
|
|
2873
3493
|
repeatCount: Count.infinity
|
|
@@ -2879,9 +3499,57 @@ var CARDSETS = {
|
|
|
2879
3499
|
//
|
|
2880
3500
|
// table
|
|
2881
3501
|
//
|
|
3502
|
+
// PLAN-079: supports BOTH source formats and collapses to the same basic
|
|
3503
|
+
// output (`{ columns?, data, columnWidths? }`):
|
|
3504
|
+
//
|
|
3505
|
+
// 1. Basic format — first card carries `[#X]` markers (fire `tag_title`
|
|
3506
|
+
// → `^table.columns[]`); subsequent cards are body rows. Cards have
|
|
3507
|
+
// no qualifier, so they route to the `table-body` (default) section.
|
|
3508
|
+
//
|
|
3509
|
+
// 2. Extended format — `==== table-header ====` / `==== table-footer ====`
|
|
3510
|
+
// qualifiers. The `table-header` section uses `@cardIndex=0` to route
|
|
3511
|
+
// the first header card's cells to `columns` and demote remaining
|
|
3512
|
+
// header cards (rows) into `data`. Per-cell `[@tableRowSpan]` /
|
|
3513
|
+
// `[@tableScope]` / `[@tableCellType]` tags are valid-but-unmapped
|
|
3514
|
+
// here (no per-cell metadata in basic shape) — declared on the cell
|
|
3515
|
+
// variant below.
|
|
3516
|
+
//
|
|
2882
3517
|
[CardSetConfigKey.table]: {
|
|
2883
|
-
jsonKey:
|
|
2884
|
-
exportJsonKey:
|
|
3518
|
+
jsonKey: null,
|
|
3519
|
+
exportJsonKey: null,
|
|
3520
|
+
sections: {
|
|
3521
|
+
"table-header": {
|
|
3522
|
+
// First header card's row of cells → `columns`. Subsequent header
|
|
3523
|
+
// cards' rows → `data` (per-card append; `[$]` shape because
|
|
3524
|
+
// per-card emission fires once per card, multiple fires deep_merge-
|
|
3525
|
+
// append). PLAN-079 + PLAN-080: predicates inside exportJsonKey
|
|
3526
|
+
// both ROUTE cards to this section (when no explicit `==== table-
|
|
3527
|
+
// header ====` qualifier) and SELECT the rule body once routed.
|
|
3528
|
+
// First rule = first card with any `[#]` → `columns`; second rule
|
|
3529
|
+
// = subsequent cards in this section → `data` (per-row append).
|
|
3530
|
+
jsonKey: "table.columns",
|
|
3531
|
+
exportJsonKey: [
|
|
3532
|
+
{
|
|
3533
|
+
predicates: [{ "@cardIndex": 0 }, { "@variantHasTag": "#" }],
|
|
3534
|
+
rule: { "@bit": { table: { columns: "$" } } }
|
|
3535
|
+
},
|
|
3536
|
+
{ "@cardIndex=0": { "@bit": { table: { columns: "$" } } } },
|
|
3537
|
+
{ "@bit": { table: { data: ["$"] } } }
|
|
3538
|
+
]
|
|
3539
|
+
},
|
|
3540
|
+
"table-body": {
|
|
3541
|
+
// Batched emission: `$` is the entire 2D array of body card rows.
|
|
3542
|
+
// This is the default section (no qualifier → cards land here).
|
|
3543
|
+
jsonKey: "table.data",
|
|
3544
|
+
exportJsonKey: { "@bit": { table: { data: "$" } } },
|
|
3545
|
+
isDefault: true
|
|
3546
|
+
},
|
|
3547
|
+
"table-footer": {
|
|
3548
|
+
// Batched emission: `$` is the entire 2D array of footer rows.
|
|
3549
|
+
jsonKey: "table.data",
|
|
3550
|
+
exportJsonKey: { "@bit": { table: { data: "$" } } }
|
|
3551
|
+
}
|
|
3552
|
+
},
|
|
2885
3553
|
sides: [
|
|
2886
3554
|
{
|
|
2887
3555
|
name: "cell",
|
|
@@ -2922,6 +3590,8 @@ var CARDSETS = {
|
|
|
2922
3590
|
},
|
|
2923
3591
|
{
|
|
2924
3592
|
key: ConfigKey.property_tableColWidth,
|
|
3593
|
+
jsonKey: "^table.columnWidths[{s}]",
|
|
3594
|
+
exportJsonKey: { "@bit": { table: { columnWidths: { $s: "$" } } } },
|
|
2925
3595
|
description: "Width for the column.",
|
|
2926
3596
|
format: TagFormat.number
|
|
2927
3597
|
}
|
|
@@ -2940,7 +3610,22 @@ var CARDSETS = {
|
|
|
2940
3610
|
sections: {
|
|
2941
3611
|
"table-header": {
|
|
2942
3612
|
jsonKey: "table.header.rows",
|
|
2943
|
-
|
|
3613
|
+
// PLAN-080: section dispatch via predicates inside exportJsonKey.
|
|
3614
|
+
// Cards with no explicit `==== table-header ====` qualifier
|
|
3615
|
+
// route here if FIRST CARD contains any `[#]` tag in any
|
|
3616
|
+
// variant. Explicit-qualifier cards fall through to the
|
|
3617
|
+
// unconditional fallback rule. Both rules use the per-card
|
|
3618
|
+
// append shape `rows: ['$']` — the runtime triggers per-card
|
|
3619
|
+
// emission whenever the pattern carries predicates, and each
|
|
3620
|
+
// fire appends a single-element array (multi-fire deep-merge
|
|
3621
|
+
// concatenates).
|
|
3622
|
+
exportJsonKey: [
|
|
3623
|
+
{
|
|
3624
|
+
predicates: [{ "@cardIndex": 0 }, { "@variantHasTag": "#" }],
|
|
3625
|
+
rule: { table: { header: { rows: ["$"] } } }
|
|
3626
|
+
},
|
|
3627
|
+
{ table: { header: { rows: ["$"] } } }
|
|
3628
|
+
],
|
|
2944
3629
|
sideJsonKey: "cells[{s}]|set(title=true)",
|
|
2945
3630
|
sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } }
|
|
2946
3631
|
},
|
|
@@ -2973,13 +3658,13 @@ var CARDSETS = {
|
|
|
2973
3658
|
},
|
|
2974
3659
|
{
|
|
2975
3660
|
key: ConfigKey.tag_title,
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
},
|
|
2982
|
-
description: "Title of the table cell."
|
|
3661
|
+
// PLAN-080: the `[#]` tag writes its text to the cell's
|
|
3662
|
+
// `content` field. When the card is in the `table-header`
|
|
3663
|
+
// section, the section's sideExportJsonKey wraps each
|
|
3664
|
+
// cell with `title: true` automatically.
|
|
3665
|
+
jsonKey: "content",
|
|
3666
|
+
exportJsonKey: { content: "$" },
|
|
3667
|
+
description: "Title text of the table cell (header rows)."
|
|
2983
3668
|
},
|
|
2984
3669
|
{
|
|
2985
3670
|
key: ConfigKey.property_tableCellType,
|
|
@@ -3011,6 +3696,9 @@ var CARDSETS = {
|
|
|
3011
3696
|
},
|
|
3012
3697
|
{
|
|
3013
3698
|
key: ConfigKey.property_tableColWidth,
|
|
3699
|
+
// PLAN-080: write to the cell's `colwidth` field.
|
|
3700
|
+
jsonKey: "colwidth",
|
|
3701
|
+
exportJsonKey: { colwidth: "$" },
|
|
3014
3702
|
description: "Width for the column.",
|
|
3015
3703
|
format: TagFormat.number
|
|
3016
3704
|
}
|
|
@@ -3048,7 +3736,8 @@ var CARDSETS = {
|
|
|
3048
3736
|
{
|
|
3049
3737
|
key: ConfigKey.resource_audio,
|
|
3050
3738
|
description: "Audio resource for the pronunciation table.",
|
|
3051
|
-
jsonKey: "audio"
|
|
3739
|
+
jsonKey: "audio",
|
|
3740
|
+
exportJsonKey: { audio: { type: "audio", audio: { src: "$" } } }
|
|
3052
3741
|
}
|
|
3053
3742
|
],
|
|
3054
3743
|
repeatCount: Count.infinity
|
|
@@ -3119,14 +3808,17 @@ var CARDSETS = {
|
|
|
3119
3808
|
format: TagFormat.plainText
|
|
3120
3809
|
},
|
|
3121
3810
|
{
|
|
3811
|
+
// ALIGN-EXAMPLE-CASCADE §3.12: `bot-action-responses` is
|
|
3812
|
+
// NOT in BPG's `pushExampleDownTree` dispatch — no bit-
|
|
3813
|
+
// header cascade.
|
|
3122
3814
|
key: ConfigKey.property_example,
|
|
3123
3815
|
exportJsonKey: [
|
|
3124
3816
|
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
3125
|
-
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
3126
3817
|
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3127
3818
|
],
|
|
3128
|
-
description: "Example text for the bot action response.",
|
|
3129
|
-
format: TagFormat.plainText
|
|
3819
|
+
description: "Example text for the bot action response (entry-local only; no bit-header cascade).",
|
|
3820
|
+
format: TagFormat.plainText,
|
|
3821
|
+
nullable: true
|
|
3130
3822
|
}
|
|
3131
3823
|
]
|
|
3132
3824
|
}
|
|
@@ -3192,6 +3884,38 @@ var CARDSETS = {
|
|
|
3192
3884
|
]
|
|
3193
3885
|
},
|
|
3194
3886
|
//
|
|
3887
|
+
// page-footer-sections — mirrors example-bit-list but emits cards under
|
|
3888
|
+
// `sections` instead of `listItems`. BPG's JsonGenerator special-cases
|
|
3889
|
+
// BitType.pageFooter in code; this dedicated cardSet expresses the same
|
|
3890
|
+
// routing as pure config so the Rust serializer can pick it up.
|
|
3891
|
+
//
|
|
3892
|
+
[CardSetConfigKey.pageFooterSections]: {
|
|
3893
|
+
jsonKey: "sections",
|
|
3894
|
+
exportJsonKey: { sections: "$" },
|
|
3895
|
+
sides: [
|
|
3896
|
+
{
|
|
3897
|
+
name: "item",
|
|
3898
|
+
variants: [
|
|
3899
|
+
{
|
|
3900
|
+
jsonKey: "body",
|
|
3901
|
+
exportJsonKey: { body: "$" },
|
|
3902
|
+
tags: [
|
|
3903
|
+
{
|
|
3904
|
+
key: ConfigKey.group_standardTags,
|
|
3905
|
+
description: "Standard tags for page-footer section bits."
|
|
3906
|
+
},
|
|
3907
|
+
{
|
|
3908
|
+
exportJsonKey: { title: "$" },
|
|
3909
|
+
key: ConfigKey.tag_title,
|
|
3910
|
+
description: "Title of the page-footer section."
|
|
3911
|
+
}
|
|
3912
|
+
]
|
|
3913
|
+
}
|
|
3914
|
+
]
|
|
3915
|
+
}
|
|
3916
|
+
]
|
|
3917
|
+
},
|
|
3918
|
+
//
|
|
3195
3919
|
// ingredients
|
|
3196
3920
|
//
|
|
3197
3921
|
[CardSetConfigKey.ingredients]: {
|
|
@@ -3522,7 +4246,11 @@ var GROUPS = {
|
|
|
3522
4246
|
{
|
|
3523
4247
|
key: ConfigKey.property_groupTag,
|
|
3524
4248
|
jsonKey: "groupTag.name",
|
|
3525
|
-
|
|
4249
|
+
// PLAN-063: starter-array shape with `@id` declares entity-merge
|
|
4250
|
+
// semantics — repeated `[@groupTag: name]` occurrences with the
|
|
4251
|
+
// same value fold into one entry; chained `@tag` children's
|
|
4252
|
+
// arrays merge as sets.
|
|
4253
|
+
exportJsonKey: { groupTag: [{ "@id": "name", name: "$" }] },
|
|
3526
4254
|
description: "The group tag(s) for the bit",
|
|
3527
4255
|
format: TagFormat.plainText,
|
|
3528
4256
|
maxCount: Count.infinity,
|
|
@@ -3695,6 +4423,24 @@ var GROUPS = {
|
|
|
3695
4423
|
}
|
|
3696
4424
|
]
|
|
3697
4425
|
},
|
|
4426
|
+
[ConfigKey.group_standardInstructionHint]: {
|
|
4427
|
+
type: GroupConfigType.standard,
|
|
4428
|
+
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).",
|
|
4429
|
+
tags: [
|
|
4430
|
+
{
|
|
4431
|
+
exportJsonKey: { instruction: "$" },
|
|
4432
|
+
key: ConfigKey.tag_instruction,
|
|
4433
|
+
name: "Instruction",
|
|
4434
|
+
description: "The instruction for the bit"
|
|
4435
|
+
},
|
|
4436
|
+
{
|
|
4437
|
+
exportJsonKey: { hint: "$" },
|
|
4438
|
+
key: ConfigKey.tag_hint,
|
|
4439
|
+
name: "Hint",
|
|
4440
|
+
description: "The hint for the bit"
|
|
4441
|
+
}
|
|
4442
|
+
]
|
|
4443
|
+
},
|
|
3698
4444
|
[ConfigKey.group_standardTags]: {
|
|
3699
4445
|
type: GroupConfigType.standard,
|
|
3700
4446
|
description: "Standard tags which apply to MOST (but not all) bits",
|
|
@@ -3708,17 +4454,45 @@ var GROUPS = {
|
|
|
3708
4454
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3709
4455
|
},
|
|
3710
4456
|
{
|
|
3711
|
-
// Bit-level example tag
|
|
3712
|
-
//
|
|
3713
|
-
//
|
|
4457
|
+
// Bit-level example tag (default — non-`isTopLevelExample` bits):
|
|
4458
|
+
// - bare `[@example]`: consume only (records cascade marker, emits
|
|
4459
|
+
// nothing at bit-level — OLD parser scrubs bit-level isExample
|
|
4460
|
+
// for bits NOT in its `isTopLevelExample` allow-list).
|
|
4461
|
+
// - synthesized (descendant cascade): still emits `isExample: true`
|
|
4462
|
+
// at the descendant scope.
|
|
4463
|
+
// - valued `[@example:text]`: emit the example value only; bit-level
|
|
4464
|
+
// `isExample` is left to bubble from descendants.
|
|
4465
|
+
// Bits in the OLD parser's allow-list (flashcard, definitionList,
|
|
4466
|
+
// sequence, multipleChoice, trueFalse, cloze*, mark, interview,
|
|
4467
|
+
// matchMatrix, match, essay, etc.) override this entry with the
|
|
4468
|
+
// legacy emit-isExample shape.
|
|
3714
4469
|
key: ConfigKey.property_example,
|
|
3715
|
-
exportJsonKey: [
|
|
3716
|
-
{ "@keyonly": { isExample: true } },
|
|
3717
|
-
{ "@absent": { isExample: true } },
|
|
3718
|
-
{ isExample: true, example: "$" }
|
|
3719
|
-
],
|
|
4470
|
+
exportJsonKey: [{ "@keyonly": {} }, { "@absent": { isExample: true } }, { example: "$" }],
|
|
3720
4471
|
description: "The example(s) for the bit",
|
|
3721
|
-
format: TagFormat.bitmarkText
|
|
4472
|
+
format: TagFormat.bitmarkText,
|
|
4473
|
+
nullable: true
|
|
4474
|
+
}
|
|
4475
|
+
]
|
|
4476
|
+
},
|
|
4477
|
+
[ConfigKey.group_standardTagsNoItemLead]: {
|
|
4478
|
+
type: GroupConfigType.standard,
|
|
4479
|
+
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).",
|
|
4480
|
+
tags: [
|
|
4481
|
+
{
|
|
4482
|
+
key: ConfigKey.group_standardAllBits,
|
|
4483
|
+
description: "All standard tags which apply to all bits"
|
|
4484
|
+
},
|
|
4485
|
+
{
|
|
4486
|
+
key: ConfigKey.group_standardInstructionHint,
|
|
4487
|
+
description: "Instruction and hint tags only (no item/lead chain)."
|
|
4488
|
+
},
|
|
4489
|
+
{
|
|
4490
|
+
// Mirror of group_standardTags property_example entry.
|
|
4491
|
+
key: ConfigKey.property_example,
|
|
4492
|
+
exportJsonKey: [{ "@keyonly": {} }, { "@absent": { isExample: true } }, { example: "$" }],
|
|
4493
|
+
description: "The example(s) for the bit",
|
|
4494
|
+
format: TagFormat.bitmarkText,
|
|
4495
|
+
nullable: true
|
|
3722
4496
|
}
|
|
3723
4497
|
]
|
|
3724
4498
|
},
|
|
@@ -3783,8 +4557,8 @@ var GROUPS = {
|
|
|
3783
4557
|
tags: [
|
|
3784
4558
|
{
|
|
3785
4559
|
key: ConfigKey.property_person,
|
|
3786
|
-
jsonKey: "
|
|
3787
|
-
exportJsonKey: {
|
|
4560
|
+
jsonKey: "person.name",
|
|
4561
|
+
exportJsonKey: { person: { name: "$" } },
|
|
3788
4562
|
description: "A person",
|
|
3789
4563
|
format: TagFormat.plainText,
|
|
3790
4564
|
chain: [
|
|
@@ -3804,8 +4578,8 @@ var GROUPS = {
|
|
|
3804
4578
|
{
|
|
3805
4579
|
// Deprecated (parter renamed to person)
|
|
3806
4580
|
key: ConfigKey.property_partner,
|
|
3807
|
-
jsonKey: "
|
|
3808
|
-
exportJsonKey: {
|
|
4581
|
+
jsonKey: "person.name",
|
|
4582
|
+
exportJsonKey: { person: { name: "$" } },
|
|
3809
4583
|
description: "A partner",
|
|
3810
4584
|
format: TagFormat.plainText,
|
|
3811
4585
|
chain: [
|
|
@@ -3829,7 +4603,9 @@ var GROUPS = {
|
|
|
3829
4603
|
description: "Gap chain",
|
|
3830
4604
|
tags: [
|
|
3831
4605
|
{
|
|
3832
|
-
exportJsonKey: {
|
|
4606
|
+
exportJsonKey: {
|
|
4607
|
+
"@body-inline": { type: "gap", attrs: { solutions: ["$"] } }
|
|
4608
|
+
},
|
|
3833
4609
|
key: ConfigKey.tag_gap,
|
|
3834
4610
|
description: "The value of a gap in the content",
|
|
3835
4611
|
maxCount: Count.infinity,
|
|
@@ -3848,27 +4624,37 @@ var GROUPS = {
|
|
|
3848
4624
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3849
4625
|
},
|
|
3850
4626
|
{
|
|
4627
|
+
// BPG ExampleTagContentProcessor.ts:91-95 reads
|
|
4628
|
+
// `__solutionsAst[length - 1]` — the solution closest to the
|
|
4629
|
+
// `[@example]` tag at parse time. Our chain accumulator is built
|
|
4630
|
+
// incrementally (scope.rs `parent.merge` after each tag), so at
|
|
4631
|
+
// the moment `[@example]` fires, `solutions` only contains the
|
|
4632
|
+
// preceding `[_x]` entries — `[-1]` resolves to the closest one.
|
|
4633
|
+
// E.g. `[_cloze][_gap][@example]` → solutions=["cloze","gap"],
|
|
4634
|
+
// `[-1]`="gap"; `[_solution][@example][_problem]` →
|
|
4635
|
+
// solutions=["solution"], `[-1]`="solution".
|
|
3851
4636
|
key: ConfigKey.property_example,
|
|
3852
4637
|
jsonKey: "example",
|
|
3853
4638
|
exportJsonKey: [
|
|
3854
4639
|
{
|
|
3855
4640
|
"@keyonly": {
|
|
3856
4641
|
isExample: true,
|
|
3857
|
-
example: "$parent.solutions[
|
|
4642
|
+
example: "$parent.solutions[-1]",
|
|
3858
4643
|
"@bit": { isExample: true }
|
|
3859
4644
|
}
|
|
3860
4645
|
},
|
|
3861
4646
|
{
|
|
3862
4647
|
"@absent": {
|
|
3863
4648
|
isExample: true,
|
|
3864
|
-
example: "$parent.solutions[
|
|
4649
|
+
example: "$parent.solutions[-1]",
|
|
3865
4650
|
"@bit": { isExample: true }
|
|
3866
4651
|
}
|
|
3867
4652
|
},
|
|
3868
4653
|
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3869
4654
|
],
|
|
3870
4655
|
description: "An example for the gap",
|
|
3871
|
-
format: TagFormat.bitmarkText
|
|
4656
|
+
format: TagFormat.bitmarkText,
|
|
4657
|
+
nullable: true
|
|
3872
4658
|
},
|
|
3873
4659
|
{
|
|
3874
4660
|
key: ConfigKey.property_isCaseSensitive,
|
|
@@ -3917,6 +4703,24 @@ var GROUPS = {
|
|
|
3917
4703
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3918
4704
|
},
|
|
3919
4705
|
{
|
|
4706
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.2: cascade-fired
|
|
4707
|
+
// `@example` from the bit header marks EVERY choice with
|
|
4708
|
+
// `isExample: true` (matches BPG output), but only the
|
|
4709
|
+
// FIRST correct choice gets `example: true` (BPG
|
|
4710
|
+
// `fillBooleanExample(..., firstCorrectOnly=true)`).
|
|
4711
|
+
//
|
|
4712
|
+
// Two `@absent` rules, picked first-match-wins:
|
|
4713
|
+
// 1. Verbose form gated on `@parent.isCorrect=true` with
|
|
4714
|
+
// `maxEmits:1` — fires once for the first correct.
|
|
4715
|
+
// 2. Plain `@absent` — fires on every remaining entry
|
|
4716
|
+
// (subsequent corrects and all incorrects), emitting
|
|
4717
|
+
// `isExample` only.
|
|
4718
|
+
// The `serialize_cards` cascade-counter scope holds the cap
|
|
4719
|
+
// across the whole cardset.
|
|
4720
|
+
// @card scope-shift writes choice-container isExample (e.g.
|
|
4721
|
+
// `quizzes[i].isExample`) — was previously provided by the
|
|
4722
|
+
// universal `bubble_is_example` post-walk, which was removed
|
|
4723
|
+
// in favour of explicit per-tag config. SYNTAX.md §8.
|
|
3920
4724
|
key: ConfigKey.property_example,
|
|
3921
4725
|
jsonKey: "example",
|
|
3922
4726
|
exportJsonKey: [
|
|
@@ -3924,20 +4728,37 @@ var GROUPS = {
|
|
|
3924
4728
|
"@keyonly": {
|
|
3925
4729
|
isExample: true,
|
|
3926
4730
|
example: "$parent.isCorrect",
|
|
3927
|
-
"@bit": { isExample: true }
|
|
4731
|
+
"@bit": { isExample: true },
|
|
4732
|
+
"@card": { isExample: true }
|
|
4733
|
+
}
|
|
4734
|
+
},
|
|
4735
|
+
{
|
|
4736
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
4737
|
+
maxEmits: 1,
|
|
4738
|
+
rule: {
|
|
4739
|
+
isExample: true,
|
|
4740
|
+
example: true,
|
|
4741
|
+
"@bit": { isExample: true },
|
|
4742
|
+
"@card": { isExample: true }
|
|
3928
4743
|
}
|
|
3929
4744
|
},
|
|
3930
4745
|
{
|
|
3931
4746
|
"@absent": {
|
|
3932
4747
|
isExample: true,
|
|
3933
|
-
|
|
3934
|
-
"@
|
|
4748
|
+
"@bit": { isExample: true },
|
|
4749
|
+
"@card": { isExample: true }
|
|
3935
4750
|
}
|
|
3936
4751
|
},
|
|
3937
|
-
{
|
|
4752
|
+
{
|
|
4753
|
+
isExample: true,
|
|
4754
|
+
example: "$",
|
|
4755
|
+
"@bit": { isExample: true },
|
|
4756
|
+
"@card": { isExample: true }
|
|
4757
|
+
}
|
|
3938
4758
|
],
|
|
3939
4759
|
description: "An example for the true/false statement/question",
|
|
3940
|
-
format: TagFormat.
|
|
4760
|
+
format: TagFormat.boolean,
|
|
4761
|
+
nullable: true
|
|
3941
4762
|
}
|
|
3942
4763
|
]
|
|
3943
4764
|
},
|
|
@@ -3969,6 +4790,12 @@ var GROUPS = {
|
|
|
3969
4790
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3970
4791
|
},
|
|
3971
4792
|
{
|
|
4793
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.2: cascade-fired
|
|
4794
|
+
// `@example` on a `-` (incorrect choice) emits
|
|
4795
|
+
// `isExample: true` only — no `example` (BPG fixtures show
|
|
4796
|
+
// `isExample` on every choice, but `example` only on the
|
|
4797
|
+
// first correct via firstCorrectOnly cascade).
|
|
4798
|
+
// @card scope-shift writes choice-container isExample.
|
|
3972
4799
|
key: ConfigKey.property_example,
|
|
3973
4800
|
jsonKey: "example",
|
|
3974
4801
|
exportJsonKey: [
|
|
@@ -3976,20 +4803,460 @@ var GROUPS = {
|
|
|
3976
4803
|
"@keyonly": {
|
|
3977
4804
|
isExample: true,
|
|
3978
4805
|
example: "$parent.isCorrect",
|
|
3979
|
-
"@bit": { isExample: true }
|
|
4806
|
+
"@bit": { isExample: true },
|
|
4807
|
+
"@card": { isExample: true }
|
|
3980
4808
|
}
|
|
3981
4809
|
},
|
|
3982
4810
|
{
|
|
3983
4811
|
"@absent": {
|
|
4812
|
+
isExample: true,
|
|
4813
|
+
"@bit": { isExample: true },
|
|
4814
|
+
"@card": { isExample: true }
|
|
4815
|
+
}
|
|
4816
|
+
},
|
|
4817
|
+
{
|
|
4818
|
+
isExample: true,
|
|
4819
|
+
example: "$",
|
|
4820
|
+
"@bit": { isExample: true },
|
|
4821
|
+
"@card": { isExample: true }
|
|
4822
|
+
}
|
|
4823
|
+
],
|
|
4824
|
+
description: "An example for the true/false statement/question (incorrect entry \u2014 isExample only on cascade)",
|
|
4825
|
+
format: TagFormat.boolean,
|
|
4826
|
+
nullable: true
|
|
4827
|
+
}
|
|
4828
|
+
]
|
|
4829
|
+
}
|
|
4830
|
+
]
|
|
4831
|
+
},
|
|
4832
|
+
[ConfigKey.group_trueFalseResponses]: {
|
|
4833
|
+
type: GroupConfigType.standard,
|
|
4834
|
+
description: "True/False Responses chain",
|
|
4835
|
+
tags: [
|
|
4836
|
+
{
|
|
4837
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: true }] },
|
|
4838
|
+
key: ConfigKey.tag_true,
|
|
4839
|
+
description: "True value for a true/false statement/question",
|
|
4840
|
+
maxCount: Count.infinity,
|
|
4841
|
+
format: TagFormat.plainText,
|
|
4842
|
+
chain: [
|
|
4843
|
+
{
|
|
4844
|
+
key: ConfigKey.tag_true,
|
|
4845
|
+
jsonKey: "responses[]|set(isCorrect=true)",
|
|
4846
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: true }] },
|
|
4847
|
+
description: "True values for a true/false statement/question",
|
|
4848
|
+
maxCount: Count.infinity,
|
|
4849
|
+
format: TagFormat.plainText
|
|
4850
|
+
},
|
|
4851
|
+
{
|
|
4852
|
+
key: ConfigKey.tag_false,
|
|
4853
|
+
jsonKey: "responses[]|set(isCorrect=false)",
|
|
4854
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: false }] },
|
|
4855
|
+
description: "False values for a true/false statement/question",
|
|
4856
|
+
maxCount: Count.infinity,
|
|
4857
|
+
format: TagFormat.plainText
|
|
4858
|
+
},
|
|
4859
|
+
{
|
|
4860
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
4861
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
4862
|
+
},
|
|
4863
|
+
{
|
|
4864
|
+
// @card scope-shift writes response-container isExample.
|
|
4865
|
+
key: ConfigKey.property_example,
|
|
4866
|
+
jsonKey: "example",
|
|
4867
|
+
exportJsonKey: [
|
|
4868
|
+
{
|
|
4869
|
+
"@keyonly": {
|
|
3984
4870
|
isExample: true,
|
|
3985
4871
|
example: "$parent.isCorrect",
|
|
3986
|
-
"@bit": { isExample: true }
|
|
4872
|
+
"@bit": { isExample: true },
|
|
4873
|
+
"@card": { isExample: true }
|
|
3987
4874
|
}
|
|
3988
4875
|
},
|
|
3989
|
-
{
|
|
4876
|
+
{
|
|
4877
|
+
"@absent": {
|
|
4878
|
+
isExample: "$parent.isCorrect",
|
|
4879
|
+
example: "$parent.isCorrect",
|
|
4880
|
+
"@bit": { isExample: "$parent.isCorrect" },
|
|
4881
|
+
"@card": { isExample: "$parent.isCorrect" }
|
|
4882
|
+
}
|
|
4883
|
+
},
|
|
4884
|
+
{
|
|
4885
|
+
isExample: true,
|
|
4886
|
+
example: "$",
|
|
4887
|
+
"@bit": { isExample: true },
|
|
4888
|
+
"@card": { isExample: true }
|
|
4889
|
+
}
|
|
3990
4890
|
],
|
|
3991
4891
|
description: "An example for the true/false statement/question",
|
|
3992
|
-
format: TagFormat.
|
|
4892
|
+
format: TagFormat.boolean,
|
|
4893
|
+
nullable: true
|
|
4894
|
+
}
|
|
4895
|
+
]
|
|
4896
|
+
},
|
|
4897
|
+
{
|
|
4898
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: false }] },
|
|
4899
|
+
key: ConfigKey.tag_false,
|
|
4900
|
+
description: "False value for a true/false statement/question",
|
|
4901
|
+
maxCount: Count.infinity,
|
|
4902
|
+
format: TagFormat.plainText,
|
|
4903
|
+
chain: [
|
|
4904
|
+
{
|
|
4905
|
+
key: ConfigKey.tag_true,
|
|
4906
|
+
jsonKey: "responses[]|set(isCorrect=true)",
|
|
4907
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: true }] },
|
|
4908
|
+
description: "True values for a true/false statement/question",
|
|
4909
|
+
maxCount: Count.infinity,
|
|
4910
|
+
format: TagFormat.plainText
|
|
4911
|
+
},
|
|
4912
|
+
{
|
|
4913
|
+
key: ConfigKey.tag_false,
|
|
4914
|
+
jsonKey: "responses[]|set(isCorrect=false)",
|
|
4915
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: false }] },
|
|
4916
|
+
description: "False values for a true/false statement/question",
|
|
4917
|
+
maxCount: Count.infinity,
|
|
4918
|
+
format: TagFormat.plainText
|
|
4919
|
+
},
|
|
4920
|
+
{
|
|
4921
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
4922
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
4923
|
+
},
|
|
4924
|
+
{
|
|
4925
|
+
// @card scope-shift writes response-container isExample.
|
|
4926
|
+
key: ConfigKey.property_example,
|
|
4927
|
+
jsonKey: "example",
|
|
4928
|
+
exportJsonKey: [
|
|
4929
|
+
{
|
|
4930
|
+
"@keyonly": {
|
|
4931
|
+
isExample: true,
|
|
4932
|
+
example: "$parent.isCorrect",
|
|
4933
|
+
"@bit": { isExample: true },
|
|
4934
|
+
"@card": { isExample: true }
|
|
4935
|
+
}
|
|
4936
|
+
},
|
|
4937
|
+
{
|
|
4938
|
+
"@absent": {
|
|
4939
|
+
isExample: true,
|
|
4940
|
+
example: "$parent.isCorrect",
|
|
4941
|
+
"@bit": { isExample: true },
|
|
4942
|
+
"@card": { isExample: true }
|
|
4943
|
+
}
|
|
4944
|
+
},
|
|
4945
|
+
{
|
|
4946
|
+
isExample: true,
|
|
4947
|
+
example: "$",
|
|
4948
|
+
"@bit": { isExample: true },
|
|
4949
|
+
"@card": { isExample: true }
|
|
4950
|
+
}
|
|
4951
|
+
],
|
|
4952
|
+
description: "An example for the true/false statement/question",
|
|
4953
|
+
format: TagFormat.boolean,
|
|
4954
|
+
nullable: true
|
|
4955
|
+
}
|
|
4956
|
+
]
|
|
4957
|
+
}
|
|
4958
|
+
]
|
|
4959
|
+
},
|
|
4960
|
+
[ConfigKey.group_trueFalseInlineSelect]: {
|
|
4961
|
+
type: GroupConfigType.standard,
|
|
4962
|
+
description: "True/False chain composed inline (select body-bit). +/- tags are consume-only at bit level.",
|
|
4963
|
+
tags: [
|
|
4964
|
+
{
|
|
4965
|
+
exportJsonKey: {
|
|
4966
|
+
"@body-inline": {
|
|
4967
|
+
type: "select",
|
|
4968
|
+
attrs: { options: [{ text: "$", isCorrect: true }] }
|
|
4969
|
+
}
|
|
4970
|
+
},
|
|
4971
|
+
key: ConfigKey.tag_true,
|
|
4972
|
+
description: "True value for an inline select body bit",
|
|
4973
|
+
maxCount: Count.infinity,
|
|
4974
|
+
format: TagFormat.plainText,
|
|
4975
|
+
chain: [
|
|
4976
|
+
{
|
|
4977
|
+
key: ConfigKey.tag_true,
|
|
4978
|
+
exportJsonKey: {},
|
|
4979
|
+
description: "True values for an inline select body bit",
|
|
4980
|
+
maxCount: Count.infinity,
|
|
4981
|
+
format: TagFormat.plainText
|
|
4982
|
+
},
|
|
4983
|
+
{
|
|
4984
|
+
key: ConfigKey.tag_false,
|
|
4985
|
+
exportJsonKey: {},
|
|
4986
|
+
description: "False values for an inline select body bit",
|
|
4987
|
+
maxCount: Count.infinity,
|
|
4988
|
+
format: TagFormat.plainText
|
|
4989
|
+
},
|
|
4990
|
+
{
|
|
4991
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
4992
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
4993
|
+
},
|
|
4994
|
+
{
|
|
4995
|
+
// PLAN-083: cascade-fired `@example` from bit header fires
|
|
4996
|
+
// `isExample:true, example:true` on the FIRST CORRECT option
|
|
4997
|
+
// only (BPG `fillBooleanExample(select.options,
|
|
4998
|
+
// firstCorrectOnly=true)`). Mirrors group_trueFalseInlineHighlight.
|
|
4999
|
+
// Every rule also bubbles `@bit:{isExample:true}` (idempotent
|
|
5000
|
+
// OR — any cascade ⇒ bit marked) and
|
|
5001
|
+
// `@body-inline:{attrs:{isExample:true}}` (node-level marker
|
|
5002
|
+
// on the select node).
|
|
5003
|
+
key: ConfigKey.property_example,
|
|
5004
|
+
jsonKey: "example",
|
|
5005
|
+
exportJsonKey: [
|
|
5006
|
+
{
|
|
5007
|
+
"@keyonly": {
|
|
5008
|
+
isExample: true,
|
|
5009
|
+
example: "$parent.isCorrect",
|
|
5010
|
+
"@bit": { isExample: true },
|
|
5011
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5012
|
+
}
|
|
5013
|
+
},
|
|
5014
|
+
{
|
|
5015
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5016
|
+
maxEmits: 1,
|
|
5017
|
+
rule: {
|
|
5018
|
+
isExample: true,
|
|
5019
|
+
example: true,
|
|
5020
|
+
"@bit": { isExample: true },
|
|
5021
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5022
|
+
}
|
|
5023
|
+
},
|
|
5024
|
+
{
|
|
5025
|
+
isExample: true,
|
|
5026
|
+
example: "$",
|
|
5027
|
+
"@bit": { isExample: true },
|
|
5028
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5029
|
+
}
|
|
5030
|
+
],
|
|
5031
|
+
description: "An example for the inline select option (first correct only)",
|
|
5032
|
+
format: TagFormat.boolean,
|
|
5033
|
+
nullable: true
|
|
5034
|
+
}
|
|
5035
|
+
]
|
|
5036
|
+
},
|
|
5037
|
+
{
|
|
5038
|
+
exportJsonKey: {
|
|
5039
|
+
"@body-inline": {
|
|
5040
|
+
type: "select",
|
|
5041
|
+
attrs: { options: [{ text: "$", isCorrect: false }] }
|
|
5042
|
+
}
|
|
5043
|
+
},
|
|
5044
|
+
key: ConfigKey.tag_false,
|
|
5045
|
+
description: "False value for an inline select body bit",
|
|
5046
|
+
maxCount: Count.infinity,
|
|
5047
|
+
format: TagFormat.plainText,
|
|
5048
|
+
chain: [
|
|
5049
|
+
{
|
|
5050
|
+
key: ConfigKey.tag_true,
|
|
5051
|
+
exportJsonKey: {},
|
|
5052
|
+
description: "True values for an inline select body bit",
|
|
5053
|
+
maxCount: Count.infinity,
|
|
5054
|
+
format: TagFormat.plainText
|
|
5055
|
+
},
|
|
5056
|
+
{
|
|
5057
|
+
key: ConfigKey.tag_false,
|
|
5058
|
+
exportJsonKey: {},
|
|
5059
|
+
description: "False values for an inline select body bit",
|
|
5060
|
+
maxCount: Count.infinity,
|
|
5061
|
+
format: TagFormat.plainText
|
|
5062
|
+
},
|
|
5063
|
+
{
|
|
5064
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5065
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5066
|
+
},
|
|
5067
|
+
{
|
|
5068
|
+
// PLAN-083: identical to the `+` lead's chain @example —
|
|
5069
|
+
// cascade reaches the first correct option regardless of
|
|
5070
|
+
// which lead (+/-) opens the chain. Every firing rule bubbles
|
|
5071
|
+
// `@bit:{isExample:true}` and `@body-inline:{attrs:{isExample:true}}`.
|
|
5072
|
+
key: ConfigKey.property_example,
|
|
5073
|
+
jsonKey: "example",
|
|
5074
|
+
exportJsonKey: [
|
|
5075
|
+
{
|
|
5076
|
+
"@keyonly": {
|
|
5077
|
+
isExample: true,
|
|
5078
|
+
example: "$parent.isCorrect",
|
|
5079
|
+
"@bit": { isExample: true },
|
|
5080
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5081
|
+
}
|
|
5082
|
+
},
|
|
5083
|
+
{
|
|
5084
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5085
|
+
maxEmits: 1,
|
|
5086
|
+
rule: {
|
|
5087
|
+
isExample: true,
|
|
5088
|
+
example: true,
|
|
5089
|
+
"@bit": { isExample: true },
|
|
5090
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5091
|
+
}
|
|
5092
|
+
},
|
|
5093
|
+
{
|
|
5094
|
+
isExample: true,
|
|
5095
|
+
example: "$",
|
|
5096
|
+
"@bit": { isExample: true },
|
|
5097
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5098
|
+
}
|
|
5099
|
+
],
|
|
5100
|
+
description: "An example for the inline select option (first correct only)",
|
|
5101
|
+
format: TagFormat.boolean,
|
|
5102
|
+
nullable: true
|
|
5103
|
+
}
|
|
5104
|
+
]
|
|
5105
|
+
}
|
|
5106
|
+
]
|
|
5107
|
+
},
|
|
5108
|
+
[ConfigKey.group_trueFalseInlineHighlight]: {
|
|
5109
|
+
type: GroupConfigType.standard,
|
|
5110
|
+
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.',
|
|
5111
|
+
tags: [
|
|
5112
|
+
{
|
|
5113
|
+
exportJsonKey: {
|
|
5114
|
+
"@body-inline": {
|
|
5115
|
+
type: "highlight",
|
|
5116
|
+
attrs: { texts: [{ text: "$", isCorrect: true }] }
|
|
5117
|
+
}
|
|
5118
|
+
},
|
|
5119
|
+
key: ConfigKey.tag_true,
|
|
5120
|
+
description: "Highlighted span in the body (correct)",
|
|
5121
|
+
maxCount: Count.infinity,
|
|
5122
|
+
format: TagFormat.plainText,
|
|
5123
|
+
chain: [
|
|
5124
|
+
{
|
|
5125
|
+
key: ConfigKey.tag_true,
|
|
5126
|
+
exportJsonKey: {},
|
|
5127
|
+
description: "Highlighted span values (correct)",
|
|
5128
|
+
maxCount: Count.infinity,
|
|
5129
|
+
format: TagFormat.plainText
|
|
5130
|
+
},
|
|
5131
|
+
{
|
|
5132
|
+
key: ConfigKey.tag_false,
|
|
5133
|
+
exportJsonKey: {},
|
|
5134
|
+
description: "Highlighted span values (incorrect)",
|
|
5135
|
+
maxCount: Count.infinity,
|
|
5136
|
+
format: TagFormat.plainText
|
|
5137
|
+
},
|
|
5138
|
+
{
|
|
5139
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5140
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5141
|
+
},
|
|
5142
|
+
{
|
|
5143
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.13: cascade-fired
|
|
5144
|
+
// `@example` from the bit header fires `example: true` +
|
|
5145
|
+
// `isExample: true` on the FIRST correct highlight only
|
|
5146
|
+
// (BPG `fillBooleanExample(highlight.texts,
|
|
5147
|
+
// firstCorrectOnly=true)`). Incorrect highlights get
|
|
5148
|
+
// nothing (unlike choices, the highlight-text fixture
|
|
5149
|
+
// shows no `isExample` on incorrect entries).
|
|
5150
|
+
key: ConfigKey.property_example,
|
|
5151
|
+
jsonKey: "example",
|
|
5152
|
+
exportJsonKey: [
|
|
5153
|
+
{
|
|
5154
|
+
"@keyonly": {
|
|
5155
|
+
isExample: true,
|
|
5156
|
+
example: "$parent.isCorrect",
|
|
5157
|
+
"@bit": { isExample: true },
|
|
5158
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5159
|
+
}
|
|
5160
|
+
},
|
|
5161
|
+
{
|
|
5162
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5163
|
+
maxEmits: 1,
|
|
5164
|
+
rule: {
|
|
5165
|
+
isExample: true,
|
|
5166
|
+
example: true,
|
|
5167
|
+
"@bit": { isExample: true },
|
|
5168
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5169
|
+
}
|
|
5170
|
+
},
|
|
5171
|
+
{
|
|
5172
|
+
isExample: true,
|
|
5173
|
+
example: "$",
|
|
5174
|
+
"@bit": { isExample: true },
|
|
5175
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5176
|
+
}
|
|
5177
|
+
],
|
|
5178
|
+
description: "An example for the highlighted span (first correct only)",
|
|
5179
|
+
format: TagFormat.boolean,
|
|
5180
|
+
nullable: true
|
|
5181
|
+
}
|
|
5182
|
+
]
|
|
5183
|
+
},
|
|
5184
|
+
{
|
|
5185
|
+
// PLAN-083 follow-up (2026-05-22): mirror the select `-` lead shape
|
|
5186
|
+
// by writing `isCorrect: false`. Without it, `$parent.isCorrect` in
|
|
5187
|
+
// chain-child @example rules resolves to ParentPathMissing for `-`
|
|
5188
|
+
// entries (e.g. `[-fish][@example]`), so the @keyonly rule falls
|
|
5189
|
+
// through and nothing fires. The natural-default strip removes
|
|
5190
|
+
// `isCorrect: false` from the final texts entries (matches fixture).
|
|
5191
|
+
exportJsonKey: {
|
|
5192
|
+
"@body-inline": {
|
|
5193
|
+
type: "highlight",
|
|
5194
|
+
attrs: { texts: [{ text: "$", isCorrect: false }] }
|
|
5195
|
+
}
|
|
5196
|
+
},
|
|
5197
|
+
key: ConfigKey.tag_false,
|
|
5198
|
+
description: "Highlighted span in the body (incorrect)",
|
|
5199
|
+
maxCount: Count.infinity,
|
|
5200
|
+
format: TagFormat.plainText,
|
|
5201
|
+
chain: [
|
|
5202
|
+
{
|
|
5203
|
+
key: ConfigKey.tag_true,
|
|
5204
|
+
exportJsonKey: {},
|
|
5205
|
+
description: "Highlighted span values (correct)",
|
|
5206
|
+
maxCount: Count.infinity,
|
|
5207
|
+
format: TagFormat.plainText
|
|
5208
|
+
},
|
|
5209
|
+
{
|
|
5210
|
+
key: ConfigKey.tag_false,
|
|
5211
|
+
exportJsonKey: {},
|
|
5212
|
+
description: "Highlighted span values (incorrect)",
|
|
5213
|
+
maxCount: Count.infinity,
|
|
5214
|
+
format: TagFormat.plainText
|
|
5215
|
+
},
|
|
5216
|
+
{
|
|
5217
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5218
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5219
|
+
},
|
|
5220
|
+
{
|
|
5221
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.13: cascade-fired
|
|
5222
|
+
// `@example` on a `-` (incorrect highlight) emits nothing
|
|
5223
|
+
// (highlight-text fixture has no `isExample` on incorrect
|
|
5224
|
+
// entries; firstCorrectOnly cascade skips them entirely).
|
|
5225
|
+
// No `@absent` rule.
|
|
5226
|
+
// PLAN-083: identical to the `+` lead's chain @example —
|
|
5227
|
+
// cascade reaches the first correct option regardless of
|
|
5228
|
+
// which lead (+/-) opens the chain.
|
|
5229
|
+
key: ConfigKey.property_example,
|
|
5230
|
+
jsonKey: "example",
|
|
5231
|
+
exportJsonKey: [
|
|
5232
|
+
{
|
|
5233
|
+
"@keyonly": {
|
|
5234
|
+
isExample: true,
|
|
5235
|
+
example: "$parent.isCorrect",
|
|
5236
|
+
"@bit": { isExample: true },
|
|
5237
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5238
|
+
}
|
|
5239
|
+
},
|
|
5240
|
+
{
|
|
5241
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5242
|
+
maxEmits: 1,
|
|
5243
|
+
rule: {
|
|
5244
|
+
isExample: true,
|
|
5245
|
+
example: true,
|
|
5246
|
+
"@bit": { isExample: true },
|
|
5247
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5248
|
+
}
|
|
5249
|
+
},
|
|
5250
|
+
{
|
|
5251
|
+
isExample: true,
|
|
5252
|
+
example: "$",
|
|
5253
|
+
"@bit": { isExample: true },
|
|
5254
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5255
|
+
}
|
|
5256
|
+
],
|
|
5257
|
+
description: "An example for the highlighted span (first correct only)",
|
|
5258
|
+
format: TagFormat.boolean,
|
|
5259
|
+
nullable: true
|
|
3993
5260
|
}
|
|
3994
5261
|
]
|
|
3995
5262
|
}
|
|
@@ -4002,7 +5269,7 @@ var GROUPS = {
|
|
|
4002
5269
|
{
|
|
4003
5270
|
key: ConfigKey.property_mark,
|
|
4004
5271
|
jsonKey: "marks.mark",
|
|
4005
|
-
exportJsonKey: { marks: { mark:
|
|
5272
|
+
exportJsonKey: { marks: [{ mark: "$" }] },
|
|
4006
5273
|
description: "The mark configuration",
|
|
4007
5274
|
format: TagFormat.plainText,
|
|
4008
5275
|
maxCount: Count.infinity,
|
|
@@ -4026,7 +5293,9 @@ var GROUPS = {
|
|
|
4026
5293
|
description: "Mark chain",
|
|
4027
5294
|
tags: [
|
|
4028
5295
|
{
|
|
4029
|
-
exportJsonKey: {
|
|
5296
|
+
exportJsonKey: {
|
|
5297
|
+
"@body-inline": { type: "mark", attrs: { solution: "$" } }
|
|
5298
|
+
},
|
|
4030
5299
|
key: ConfigKey.tag_mark,
|
|
4031
5300
|
description: "The marked content",
|
|
4032
5301
|
maxCount: Count.infinity,
|
|
@@ -4035,6 +5304,7 @@ var GROUPS = {
|
|
|
4035
5304
|
{
|
|
4036
5305
|
key: ConfigKey.property_mark,
|
|
4037
5306
|
jsonKey: "mark",
|
|
5307
|
+
exportJsonKey: { mark: "$" },
|
|
4038
5308
|
description: "The mark configuration",
|
|
4039
5309
|
format: TagFormat.plainText
|
|
4040
5310
|
},
|
|
@@ -4047,7 +5317,8 @@ var GROUPS = {
|
|
|
4047
5317
|
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
4048
5318
|
],
|
|
4049
5319
|
description: "An example for the marked content",
|
|
4050
|
-
format: TagFormat.bitmarkText
|
|
5320
|
+
format: TagFormat.bitmarkText,
|
|
5321
|
+
nullable: true
|
|
4051
5322
|
}
|
|
4052
5323
|
]
|
|
4053
5324
|
}
|
|
@@ -4476,6 +5747,42 @@ var GROUPS = {
|
|
|
4476
5747
|
}
|
|
4477
5748
|
]
|
|
4478
5749
|
},
|
|
5750
|
+
[ConfigKey.group_backgroundWallpaper]: {
|
|
5751
|
+
type: GroupConfigType.standard,
|
|
5752
|
+
description: "Background wallpaper tags",
|
|
5753
|
+
tags: [
|
|
5754
|
+
{
|
|
5755
|
+
key: ConfigKey.resource_backgroundWallpaper,
|
|
5756
|
+
exportJsonKey: { backgroundWallpaper: { type: "image", image: { src: "$" } } },
|
|
5757
|
+
description: "Background wallpaper for the image, used to set a background for the image",
|
|
5758
|
+
chain: [
|
|
5759
|
+
{
|
|
5760
|
+
key: ConfigKey.group_resourceImageCommon,
|
|
5761
|
+
description: "Common resource image tags for images"
|
|
5762
|
+
}
|
|
5763
|
+
]
|
|
5764
|
+
}
|
|
5765
|
+
]
|
|
5766
|
+
},
|
|
5767
|
+
[ConfigKey.group_imageNoZoom]: {
|
|
5768
|
+
type: GroupConfigType.standard,
|
|
5769
|
+
description: "Image bit tags",
|
|
5770
|
+
tags: [
|
|
5771
|
+
{
|
|
5772
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
5773
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
5774
|
+
},
|
|
5775
|
+
{
|
|
5776
|
+
key: ConfigKey.group_resourceBitTags,
|
|
5777
|
+
description: "Resource bit tags for images, used to define additional properties for images"
|
|
5778
|
+
},
|
|
5779
|
+
{
|
|
5780
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
5781
|
+
description: "Resource image tags for images, used to attach images to the bit",
|
|
5782
|
+
minCount: 1
|
|
5783
|
+
}
|
|
5784
|
+
]
|
|
5785
|
+
},
|
|
4479
5786
|
//
|
|
4480
5787
|
// Resource groups
|
|
4481
5788
|
//
|
|
@@ -4595,6 +5902,58 @@ var GROUPS = {
|
|
|
4595
5902
|
}
|
|
4596
5903
|
]
|
|
4597
5904
|
},
|
|
5905
|
+
[ConfigKey.group_resourceImageCommonNoZoom]: {
|
|
5906
|
+
type: GroupConfigType.standard,
|
|
5907
|
+
description: "Common properties for image resources where @zoomDisabled defaults to true",
|
|
5908
|
+
tags: [
|
|
5909
|
+
{
|
|
5910
|
+
key: ConfigKey.group_resourceCommon,
|
|
5911
|
+
description: "Common resource properties"
|
|
5912
|
+
},
|
|
5913
|
+
{
|
|
5914
|
+
key: ConfigKey.property_src1x,
|
|
5915
|
+
description: "The source URL for the image at 1x resolution",
|
|
5916
|
+
format: TagFormat.plainText
|
|
5917
|
+
},
|
|
5918
|
+
{
|
|
5919
|
+
key: ConfigKey.property_src2x,
|
|
5920
|
+
description: "The source URL for the image at 2x resolution",
|
|
5921
|
+
format: TagFormat.plainText
|
|
5922
|
+
},
|
|
5923
|
+
{
|
|
5924
|
+
key: ConfigKey.property_src3x,
|
|
5925
|
+
description: "The source URL for the image at 3x resolution",
|
|
5926
|
+
format: TagFormat.plainText
|
|
5927
|
+
},
|
|
5928
|
+
{
|
|
5929
|
+
key: ConfigKey.property_src4x,
|
|
5930
|
+
description: "The source URL for the image at 4x resolution",
|
|
5931
|
+
format: TagFormat.plainText
|
|
5932
|
+
},
|
|
5933
|
+
{
|
|
5934
|
+
key: ConfigKey.property_width,
|
|
5935
|
+
description: "The width of the image",
|
|
5936
|
+
format: TagFormat.number
|
|
5937
|
+
},
|
|
5938
|
+
{
|
|
5939
|
+
key: ConfigKey.property_height,
|
|
5940
|
+
description: "The height of the image",
|
|
5941
|
+
format: TagFormat.number
|
|
5942
|
+
},
|
|
5943
|
+
{
|
|
5944
|
+
key: ConfigKey.property_alt,
|
|
5945
|
+
description: "The alternative text for the image",
|
|
5946
|
+
format: TagFormat.plainText
|
|
5947
|
+
},
|
|
5948
|
+
// @zoomDisabled with a true default
|
|
5949
|
+
{
|
|
5950
|
+
key: ConfigKey.property_zoomDisabled,
|
|
5951
|
+
description: "If true, zooming is disabled for the image (defaults to true)",
|
|
5952
|
+
format: TagFormat.boolean,
|
|
5953
|
+
defaultValue: "true"
|
|
5954
|
+
}
|
|
5955
|
+
]
|
|
5956
|
+
},
|
|
4598
5957
|
[ConfigKey.group_resourceAudioCommon]: {
|
|
4599
5958
|
type: GroupConfigType.standard,
|
|
4600
5959
|
description: "Common properties for audio resources",
|
|
@@ -4684,22 +6043,26 @@ var GROUPS = {
|
|
|
4684
6043
|
{
|
|
4685
6044
|
key: ConfigKey.property_src1x,
|
|
4686
6045
|
description: "The source URL for the video at 1x resolution",
|
|
4687
|
-
format: TagFormat.plainText
|
|
6046
|
+
format: TagFormat.plainText,
|
|
6047
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4688
6048
|
},
|
|
4689
6049
|
{
|
|
4690
6050
|
key: ConfigKey.property_src2x,
|
|
4691
6051
|
description: "The source URL for the video at 2x resolution",
|
|
4692
|
-
format: TagFormat.plainText
|
|
6052
|
+
format: TagFormat.plainText,
|
|
6053
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4693
6054
|
},
|
|
4694
6055
|
{
|
|
4695
6056
|
key: ConfigKey.property_src3x,
|
|
4696
6057
|
description: "The source URL for the video at 3x resolution",
|
|
4697
|
-
format: TagFormat.plainText
|
|
6058
|
+
format: TagFormat.plainText,
|
|
6059
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4698
6060
|
},
|
|
4699
6061
|
{
|
|
4700
6062
|
key: ConfigKey.property_src4x,
|
|
4701
6063
|
description: "The source URL for the video at 4x resolution",
|
|
4702
|
-
format: TagFormat.plainText
|
|
6064
|
+
format: TagFormat.plainText,
|
|
6065
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4703
6066
|
}
|
|
4704
6067
|
]
|
|
4705
6068
|
},
|
|
@@ -4712,6 +6075,7 @@ var GROUPS = {
|
|
|
4712
6075
|
tags: [
|
|
4713
6076
|
{
|
|
4714
6077
|
key: ConfigKey.resource_icon,
|
|
6078
|
+
exportJsonKey: { resource: { type: "icon", icon: { src: "$" } } },
|
|
4715
6079
|
description: "The icon resource",
|
|
4716
6080
|
chain: [
|
|
4717
6081
|
{
|
|
@@ -4739,12 +6103,30 @@ var GROUPS = {
|
|
|
4739
6103
|
}
|
|
4740
6104
|
]
|
|
4741
6105
|
},
|
|
6106
|
+
[ConfigKey.group_resourceImageNoZoom]: {
|
|
6107
|
+
type: GroupConfigType.resource,
|
|
6108
|
+
description: "Image resource where @zoomDisabled defaults to true",
|
|
6109
|
+
tags: [
|
|
6110
|
+
{
|
|
6111
|
+
key: ConfigKey.resource_image,
|
|
6112
|
+
exportJsonKey: { resource: { type: "image", image: { src: "$" } } },
|
|
6113
|
+
description: "The image resource (no-zoom default)",
|
|
6114
|
+
chain: [
|
|
6115
|
+
{
|
|
6116
|
+
key: ConfigKey.group_resourceImageCommonNoZoom,
|
|
6117
|
+
description: "Common image properties with @zoomDisabled defaulting to true"
|
|
6118
|
+
}
|
|
6119
|
+
]
|
|
6120
|
+
}
|
|
6121
|
+
]
|
|
6122
|
+
},
|
|
4742
6123
|
[ConfigKey.group_resourceImagePortrait]: {
|
|
4743
6124
|
type: GroupConfigType.resource,
|
|
4744
6125
|
description: "Portrait image resource",
|
|
4745
6126
|
tags: [
|
|
4746
6127
|
{
|
|
4747
6128
|
key: ConfigKey.resource_imagePortrait,
|
|
6129
|
+
exportJsonKey: { resource: { type: "image-portrait", imagePortrait: { src: "$" } } },
|
|
4748
6130
|
description: "The portrait image resource",
|
|
4749
6131
|
chain: [
|
|
4750
6132
|
{
|
|
@@ -4761,6 +6143,7 @@ var GROUPS = {
|
|
|
4761
6143
|
tags: [
|
|
4762
6144
|
{
|
|
4763
6145
|
key: ConfigKey.resource_imageLandscape,
|
|
6146
|
+
exportJsonKey: { resource: { type: "image-landscape", imageLandscape: { src: "$" } } },
|
|
4764
6147
|
description: "The landscape image resource",
|
|
4765
6148
|
chain: [
|
|
4766
6149
|
{
|
|
@@ -4777,6 +6160,7 @@ var GROUPS = {
|
|
|
4777
6160
|
tags: [
|
|
4778
6161
|
{
|
|
4779
6162
|
key: ConfigKey.resource_imageEmbed,
|
|
6163
|
+
exportJsonKey: { resource: { type: "image-embed", imageEmbed: { src: "$" } } },
|
|
4780
6164
|
description: "The embedded image resource",
|
|
4781
6165
|
chain: [
|
|
4782
6166
|
{
|
|
@@ -4950,6 +6334,7 @@ var GROUPS = {
|
|
|
4950
6334
|
tags: [
|
|
4951
6335
|
{
|
|
4952
6336
|
key: ConfigKey.resource_article,
|
|
6337
|
+
exportJsonKey: { resource: { type: "article", article: { body: "$" } } },
|
|
4953
6338
|
description: "The article resource",
|
|
4954
6339
|
chain: [
|
|
4955
6340
|
{
|
|
@@ -4966,6 +6351,7 @@ var GROUPS = {
|
|
|
4966
6351
|
tags: [
|
|
4967
6352
|
{
|
|
4968
6353
|
key: ConfigKey.resource_articleEmbed,
|
|
6354
|
+
exportJsonKey: { resource: { type: "article-embed", articleEmbed: { url: "$" } } },
|
|
4969
6355
|
description: "The embedded article resource",
|
|
4970
6356
|
chain: [
|
|
4971
6357
|
{
|
|
@@ -4982,6 +6368,7 @@ var GROUPS = {
|
|
|
4982
6368
|
tags: [
|
|
4983
6369
|
{
|
|
4984
6370
|
key: ConfigKey.resource_articleLink,
|
|
6371
|
+
exportJsonKey: { resource: { type: "article-link", articleLink: { url: "$" } } },
|
|
4985
6372
|
description: "The link to the article resource",
|
|
4986
6373
|
chain: [
|
|
4987
6374
|
{
|
|
@@ -5252,7 +6639,12 @@ var ConfigHydrator = class {
|
|
|
5252
6639
|
isDefault: v.isDefault,
|
|
5253
6640
|
sideJsonKey: v.sideJsonKey,
|
|
5254
6641
|
sideExportJsonKey: v.sideExportJsonKey,
|
|
5255
|
-
hasSideExportJsonKey: Object.prototype.hasOwnProperty.call(v, "sideExportJsonKey")
|
|
6642
|
+
hasSideExportJsonKey: Object.prototype.hasOwnProperty.call(v, "sideExportJsonKey"),
|
|
6643
|
+
// PLAN-085: cardinality fields pass through; defaults applied
|
|
6644
|
+
// downstream by the config consumer (Rust treats `0` / undefined
|
|
6645
|
+
// as unbounded).
|
|
6646
|
+
minCount: v.minCount,
|
|
6647
|
+
maxCount: v.maxCount
|
|
5256
6648
|
};
|
|
5257
6649
|
}
|
|
5258
6650
|
return out;
|
|
@@ -5467,7 +6859,8 @@ var BITS = {
|
|
|
5467
6859
|
{ isExample: true, example: "$" }
|
|
5468
6860
|
],
|
|
5469
6861
|
description: "The example text for the bit",
|
|
5470
|
-
format: TagFormat.plainText
|
|
6862
|
+
format: TagFormat.plainText,
|
|
6863
|
+
nullable: true
|
|
5471
6864
|
}
|
|
5472
6865
|
],
|
|
5473
6866
|
rootExampleType: ExampleType.string
|
|
@@ -5806,7 +7199,8 @@ var BITS = {
|
|
|
5806
7199
|
{ isExample: true, example: "$" }
|
|
5807
7200
|
],
|
|
5808
7201
|
description: "The example text for the bit",
|
|
5809
|
-
format: TagFormat.plainText
|
|
7202
|
+
format: TagFormat.plainText,
|
|
7203
|
+
nullable: true
|
|
5810
7204
|
}
|
|
5811
7205
|
],
|
|
5812
7206
|
rootExampleType: ExampleType.string
|
|
@@ -5969,7 +7363,8 @@ var BITS = {
|
|
|
5969
7363
|
{ isExample: true, example: "$" }
|
|
5970
7364
|
],
|
|
5971
7365
|
description: "The example text for the bit",
|
|
5972
|
-
format: TagFormat.plainText
|
|
7366
|
+
format: TagFormat.plainText,
|
|
7367
|
+
nullable: true
|
|
5973
7368
|
}
|
|
5974
7369
|
],
|
|
5975
7370
|
rootExampleType: ExampleType.string
|
|
@@ -6120,7 +7515,8 @@ var BITS = {
|
|
|
6120
7515
|
{ isExample: true, example: "$" }
|
|
6121
7516
|
],
|
|
6122
7517
|
description: "The example text for the bit",
|
|
6123
|
-
format: TagFormat.plainText
|
|
7518
|
+
format: TagFormat.plainText,
|
|
7519
|
+
nullable: true
|
|
6124
7520
|
}
|
|
6125
7521
|
],
|
|
6126
7522
|
rootExampleType: ExampleType.string
|
|
@@ -6715,8 +8111,31 @@ var BITS = {
|
|
|
6715
8111
|
description: "Tags for gaps in cloze and multiple choice text bits"
|
|
6716
8112
|
},
|
|
6717
8113
|
{
|
|
6718
|
-
key: ConfigKey.
|
|
8114
|
+
key: ConfigKey.group_trueFalseInlineSelect,
|
|
6719
8115
|
description: "Tags for true/false questions in cloze and multiple choice text bits"
|
|
8116
|
+
},
|
|
8117
|
+
{
|
|
8118
|
+
// Bit-level @isCaseSensitive — empty exportJsonKey (no bit-level emission);
|
|
8119
|
+
// defaultValue 'true' phantom-fires onto the ancestor stack so the gap chain's
|
|
8120
|
+
// `@absent: $ancestor` rule resolves to true. Mirrors BPG Builder.ts:1643-1652
|
|
8121
|
+
// `pushDownTree(... 'isCaseSensitive', data.isCaseSensitive ?? true)` for cloze bits.
|
|
8122
|
+
key: ConfigKey.property_isCaseSensitive,
|
|
8123
|
+
exportJsonKey: {},
|
|
8124
|
+
description: "If the cloze answers are case sensitive",
|
|
8125
|
+
format: TagFormat.boolean,
|
|
8126
|
+
defaultValue: "true"
|
|
8127
|
+
},
|
|
8128
|
+
{
|
|
8129
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
8130
|
+
key: ConfigKey.property_example,
|
|
8131
|
+
exportJsonKey: [
|
|
8132
|
+
{ "@keyonly": { isExample: true } },
|
|
8133
|
+
{ "@absent": { isExample: true } },
|
|
8134
|
+
{ isExample: true, example: "$" }
|
|
8135
|
+
],
|
|
8136
|
+
description: "The example(s) for the bit",
|
|
8137
|
+
format: TagFormat.bitmarkText,
|
|
8138
|
+
nullable: true
|
|
6720
8139
|
}
|
|
6721
8140
|
]
|
|
6722
8141
|
},
|
|
@@ -6755,18 +8174,56 @@ var BITS = {
|
|
|
6755
8174
|
{
|
|
6756
8175
|
key: ConfigKey.group_gap,
|
|
6757
8176
|
description: "Tags for gaps in cloze bits"
|
|
8177
|
+
},
|
|
8178
|
+
{
|
|
8179
|
+
// Override inherited @example: cloze is in OLD parser's
|
|
8180
|
+
// `isTopLevelExample` allow-list, so [@example] at bit-header
|
|
8181
|
+
// emits `isExample: true`.
|
|
8182
|
+
key: ConfigKey.property_example,
|
|
8183
|
+
exportJsonKey: [
|
|
8184
|
+
{ "@keyonly": { isExample: true } },
|
|
8185
|
+
{ "@absent": { isExample: true } },
|
|
8186
|
+
{ isExample: true, example: "$" }
|
|
8187
|
+
],
|
|
8188
|
+
description: "The example(s) for the bit",
|
|
8189
|
+
format: TagFormat.bitmarkText,
|
|
8190
|
+
nullable: true
|
|
6758
8191
|
}
|
|
6759
8192
|
]
|
|
6760
8193
|
},
|
|
6761
8194
|
[BitType.clozeInstructionGrouped]: {
|
|
6762
8195
|
since: "1.3.0",
|
|
6763
8196
|
baseBitType: BitType.cloze,
|
|
6764
|
-
description: "Cloze instruction grouped bit, used for cloze questions with grouped instructions"
|
|
8197
|
+
description: "Cloze instruction grouped bit, used for cloze questions with grouped instructions",
|
|
8198
|
+
tags: [
|
|
8199
|
+
{
|
|
8200
|
+
key: ConfigKey.property_quizCountItems,
|
|
8201
|
+
description: "The number of items in the cloze quiz (instruction-grouped default: true)",
|
|
8202
|
+
format: TagFormat.boolean,
|
|
8203
|
+
defaultValue: "true"
|
|
8204
|
+
}
|
|
8205
|
+
// Note: quizStrikethroughSolutions defaults to false for instruction-grouped per OLD
|
|
8206
|
+
// JsonGenerator.ts:1689-1690, which equals the Boolean natural default → no override needed.
|
|
8207
|
+
]
|
|
6765
8208
|
},
|
|
6766
8209
|
[BitType.clozeSolutionGrouped]: {
|
|
6767
8210
|
since: "1.3.0",
|
|
6768
8211
|
baseBitType: BitType.cloze,
|
|
6769
|
-
description: "Cloze solution grouped bit, used for cloze questions with grouped solutions"
|
|
8212
|
+
description: "Cloze solution grouped bit, used for cloze questions with grouped solutions",
|
|
8213
|
+
tags: [
|
|
8214
|
+
{
|
|
8215
|
+
key: ConfigKey.property_quizCountItems,
|
|
8216
|
+
description: "The number of items in the cloze quiz (solution-grouped default: true)",
|
|
8217
|
+
format: TagFormat.boolean,
|
|
8218
|
+
defaultValue: "true"
|
|
8219
|
+
},
|
|
8220
|
+
{
|
|
8221
|
+
key: ConfigKey.property_quizStrikethroughSolutions,
|
|
8222
|
+
description: "If the cloze solutions should be strikethrough (solution-grouped default: true)",
|
|
8223
|
+
format: TagFormat.boolean,
|
|
8224
|
+
defaultValue: "true"
|
|
8225
|
+
}
|
|
8226
|
+
]
|
|
6770
8227
|
},
|
|
6771
8228
|
[BitType.clozeSeveral]: {
|
|
6772
8229
|
since: "3.5.0",
|
|
@@ -6802,6 +8259,17 @@ var BITS = {
|
|
|
6802
8259
|
{
|
|
6803
8260
|
key: ConfigKey.group_quizCommon,
|
|
6804
8261
|
description: "Common tags for quiz bits"
|
|
8262
|
+
},
|
|
8263
|
+
{
|
|
8264
|
+
// PLAN-084 (R12): bit-level @isCaseSensitive — empty exportJsonKey
|
|
8265
|
+
// (no bit-level emission); defaultValue 'true' phantom-fires onto
|
|
8266
|
+
// the ancestor stack so each listItem's gap chain `@absent: $ancestor`
|
|
8267
|
+
// rule resolves to true. Mirrors the cloze bit (bits.ts:1326-1336).
|
|
8268
|
+
key: ConfigKey.property_isCaseSensitive,
|
|
8269
|
+
exportJsonKey: {},
|
|
8270
|
+
description: "If the cloze answers are case sensitive",
|
|
8271
|
+
format: TagFormat.boolean,
|
|
8272
|
+
defaultValue: "true"
|
|
6805
8273
|
}
|
|
6806
8274
|
],
|
|
6807
8275
|
cardSet: CardSetConfigKey.clozeList
|
|
@@ -6968,6 +8436,7 @@ var BITS = {
|
|
|
6968
8436
|
tags: [
|
|
6969
8437
|
{
|
|
6970
8438
|
key: ConfigKey.group_person,
|
|
8439
|
+
exportJsonKey: { partner: { name: "$" } },
|
|
6971
8440
|
description: "Tags for the person in the conversation"
|
|
6972
8441
|
}
|
|
6973
8442
|
]
|
|
@@ -7406,7 +8875,8 @@ var BITS = {
|
|
|
7406
8875
|
{ isExample: true, example: "$" }
|
|
7407
8876
|
],
|
|
7408
8877
|
description: "The example text for the essay bit",
|
|
7409
|
-
format: TagFormat.plainText
|
|
8878
|
+
format: TagFormat.plainText,
|
|
8879
|
+
nullable: true
|
|
7410
8880
|
}
|
|
7411
8881
|
],
|
|
7412
8882
|
rootExampleType: ExampleType.string
|
|
@@ -7440,7 +8910,8 @@ var BITS = {
|
|
|
7440
8910
|
{ isExample: true, example: "$" }
|
|
7441
8911
|
],
|
|
7442
8912
|
description: "The example text for the example bit",
|
|
7443
|
-
format: TagFormat.plainText
|
|
8913
|
+
format: TagFormat.plainText,
|
|
8914
|
+
nullable: true
|
|
7444
8915
|
}
|
|
7445
8916
|
],
|
|
7446
8917
|
rootExampleType: ExampleType.string
|
|
@@ -7526,7 +8997,19 @@ var BITS = {
|
|
|
7526
8997
|
[BitType.articleAi]: {
|
|
7527
8998
|
since: "1.3.0",
|
|
7528
8999
|
baseBitType: BitType.article,
|
|
7529
|
-
description: "Article AI bit, used to create AI-generated articles"
|
|
9000
|
+
description: "Article AI bit, used to create AI-generated articles",
|
|
9001
|
+
tags: [
|
|
9002
|
+
{
|
|
9003
|
+
// Shadows the inherited @aiGenerated from the standard group: this
|
|
9004
|
+
// bit type forces aiGenerated:true regardless of source value or
|
|
9005
|
+
// absence. Literal `true` in the export pattern ignores `$`.
|
|
9006
|
+
key: ConfigKey.property_aiGenerated,
|
|
9007
|
+
description: "AI-generated flag, forced true for article-ai bits",
|
|
9008
|
+
format: TagFormat.boolean,
|
|
9009
|
+
defaultValue: "true",
|
|
9010
|
+
exportJsonKey: { aiGenerated: true }
|
|
9011
|
+
}
|
|
9012
|
+
]
|
|
7530
9013
|
},
|
|
7531
9014
|
[BitType.articleAttachment]: {
|
|
7532
9015
|
since: "1.3.0",
|
|
@@ -7851,7 +9334,19 @@ var BITS = {
|
|
|
7851
9334
|
[BitType.noteAi]: {
|
|
7852
9335
|
since: "1.3.0",
|
|
7853
9336
|
baseBitType: BitType.note,
|
|
7854
|
-
description: "Note AI bit, used to create AI-generated notes in articles or books"
|
|
9337
|
+
description: "Note AI bit, used to create AI-generated notes in articles or books",
|
|
9338
|
+
tags: [
|
|
9339
|
+
{
|
|
9340
|
+
// Shadows the inherited @aiGenerated from the standard group: this
|
|
9341
|
+
// bit type forces aiGenerated:true regardless of source value or
|
|
9342
|
+
// absence. Literal `true` in the export pattern ignores `$`.
|
|
9343
|
+
key: ConfigKey.property_aiGenerated,
|
|
9344
|
+
description: "AI-generated flag, forced true for article-ai bits",
|
|
9345
|
+
format: TagFormat.boolean,
|
|
9346
|
+
defaultValue: "true",
|
|
9347
|
+
exportJsonKey: { aiGenerated: true }
|
|
9348
|
+
}
|
|
9349
|
+
]
|
|
7855
9350
|
},
|
|
7856
9351
|
[BitType.notebookArticle]: {
|
|
7857
9352
|
since: "1.3.0",
|
|
@@ -7976,7 +9471,19 @@ var BITS = {
|
|
|
7976
9471
|
[BitType.summaryAi]: {
|
|
7977
9472
|
since: "1.3.0",
|
|
7978
9473
|
baseBitType: BitType.summary,
|
|
7979
|
-
description: "AI-generated summary bit"
|
|
9474
|
+
description: "AI-generated summary bit",
|
|
9475
|
+
tags: [
|
|
9476
|
+
{
|
|
9477
|
+
// Shadows the inherited @aiGenerated from the standard group: this
|
|
9478
|
+
// bit type forces aiGenerated:true regardless of source value or
|
|
9479
|
+
// absence. Literal `true` in the export pattern ignores `$`.
|
|
9480
|
+
key: ConfigKey.property_aiGenerated,
|
|
9481
|
+
description: "AI-generated flag, forced true for article-ai bits",
|
|
9482
|
+
format: TagFormat.boolean,
|
|
9483
|
+
defaultValue: "true",
|
|
9484
|
+
exportJsonKey: { aiGenerated: true }
|
|
9485
|
+
}
|
|
9486
|
+
]
|
|
7980
9487
|
},
|
|
7981
9488
|
[BitType.videoTranscript]: {
|
|
7982
9489
|
since: "1.3.0",
|
|
@@ -8250,7 +9757,7 @@ var BITS = {
|
|
|
8250
9757
|
description: "Product ID for the module product, used to link to a specific product",
|
|
8251
9758
|
format: TagFormat.plainText,
|
|
8252
9759
|
minCount: 1,
|
|
8253
|
-
maxCount:
|
|
9760
|
+
maxCount: 1
|
|
8254
9761
|
}
|
|
8255
9762
|
]
|
|
8256
9763
|
},
|
|
@@ -8303,10 +9810,13 @@ var BITS = {
|
|
|
8303
9810
|
description: "Resource bit tags for logo grave images, used to define additional properties"
|
|
8304
9811
|
},
|
|
8305
9812
|
{
|
|
8306
|
-
// Image resource
|
|
8307
|
-
|
|
9813
|
+
// Image resource — fully-expanded shape so each `&image` emission
|
|
9814
|
+
// produces a complete `{type, image: {src}}` object inside the
|
|
9815
|
+
// `images[]` array. Chain attrs like `[@zoomDisabled]` fold under
|
|
9816
|
+
// `images[].image` via the `[]` last-element-merge semantic.
|
|
9817
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
8308
9818
|
description: "Resource image tags for logo grave images, used to attach images",
|
|
8309
|
-
exportJsonKey: { images: "$" },
|
|
9819
|
+
exportJsonKey: { images: [{ type: "image", image: { src: "$" } }] },
|
|
8310
9820
|
minCount: 1,
|
|
8311
9821
|
maxCount: Count.infinity
|
|
8312
9822
|
}
|
|
@@ -8596,6 +10106,10 @@ var BITS = {
|
|
|
8596
10106
|
tags: [
|
|
8597
10107
|
{
|
|
8598
10108
|
key: ConfigKey.property_book,
|
|
10109
|
+
// Starter-array shape: each `[@book:value]` chain appends a fresh
|
|
10110
|
+
// `{ book, reference }` entry. The chained `►` (tag_reference) lands
|
|
10111
|
+
// inside the most-recently-appended entry as `reference: $`.
|
|
10112
|
+
exportJsonKey: { book: [{ book: "$" }] },
|
|
8599
10113
|
description: "Book reference for the page, used to link to a specific book",
|
|
8600
10114
|
maxCount: Count.infinity,
|
|
8601
10115
|
chain: [
|
|
@@ -8663,7 +10177,9 @@ var BITS = {
|
|
|
8663
10177
|
format: TagFormat.plainText
|
|
8664
10178
|
}
|
|
8665
10179
|
],
|
|
8666
|
-
|
|
10180
|
+
// page-footer emits cards under `sections` (vs `listItems` for the
|
|
10181
|
+
// sibling exampleList / assignmentList bits) — see JsonGenerator.ts.
|
|
10182
|
+
cardSet: CardSetConfigKey.pageFooterSections
|
|
8667
10183
|
},
|
|
8668
10184
|
[BitType.legend]: {
|
|
8669
10185
|
since: "3.12.0",
|
|
@@ -8705,6 +10221,20 @@ var BITS = {
|
|
|
8705
10221
|
since: "1.34.0",
|
|
8706
10222
|
baseBitType: BitType._standard,
|
|
8707
10223
|
description: "Definition list bit, used to create lists of definitions in articles or books",
|
|
10224
|
+
tags: [
|
|
10225
|
+
{
|
|
10226
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10227
|
+
key: ConfigKey.property_example,
|
|
10228
|
+
exportJsonKey: [
|
|
10229
|
+
{ "@keyonly": { isExample: true } },
|
|
10230
|
+
{ "@absent": { isExample: true } },
|
|
10231
|
+
{ isExample: true, example: "$" }
|
|
10232
|
+
],
|
|
10233
|
+
description: "The example(s) for the bit",
|
|
10234
|
+
format: TagFormat.bitmarkText,
|
|
10235
|
+
nullable: true
|
|
10236
|
+
}
|
|
10237
|
+
],
|
|
8708
10238
|
cardSet: CardSetConfigKey.definitionList
|
|
8709
10239
|
},
|
|
8710
10240
|
[BitType.metaSearchDefaultTerms]: {
|
|
@@ -8727,6 +10257,18 @@ var BITS = {
|
|
|
8727
10257
|
{
|
|
8728
10258
|
key: ConfigKey.group_quizCommon,
|
|
8729
10259
|
description: "Common quiz tags for flashcards"
|
|
10260
|
+
},
|
|
10261
|
+
{
|
|
10262
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10263
|
+
key: ConfigKey.property_example,
|
|
10264
|
+
exportJsonKey: [
|
|
10265
|
+
{ "@keyonly": { isExample: true } },
|
|
10266
|
+
{ "@absent": { isExample: true } },
|
|
10267
|
+
{ isExample: true, example: "$" }
|
|
10268
|
+
],
|
|
10269
|
+
description: "The example(s) for the bit",
|
|
10270
|
+
format: TagFormat.bitmarkText,
|
|
10271
|
+
nullable: true
|
|
8730
10272
|
}
|
|
8731
10273
|
],
|
|
8732
10274
|
cardSet: CardSetConfigKey.flashcard
|
|
@@ -8734,7 +10276,11 @@ var BITS = {
|
|
|
8734
10276
|
[BitType.flashcard1]: {
|
|
8735
10277
|
since: "1.3.0",
|
|
8736
10278
|
baseBitType: BitType.flashcard,
|
|
8737
|
-
description: "Flashcard 1 bit"
|
|
10279
|
+
description: "Flashcard 1 bit",
|
|
10280
|
+
// PLAN-085: use the flashcard1 cardset (sections.default.maxCount=1)
|
|
10281
|
+
// instead of inheriting `flashcard`'s unbounded cardset, since this
|
|
10282
|
+
// bit type structurally allows only a single card.
|
|
10283
|
+
cardSet: CardSetConfigKey.flashcard1
|
|
8738
10284
|
},
|
|
8739
10285
|
[BitType.qAndACard]: {
|
|
8740
10286
|
since: "3.25.0",
|
|
@@ -8769,8 +10315,24 @@ var BITS = {
|
|
|
8769
10315
|
description: "Common quiz tags for highlighted text"
|
|
8770
10316
|
},
|
|
8771
10317
|
{
|
|
8772
|
-
|
|
8773
|
-
|
|
10318
|
+
// Dedicated highlight inline-select chain: tag_true / tag_false
|
|
10319
|
+
// emit `{type:"highlight", attrs:{texts:[{text,isCorrect?}]}}`
|
|
10320
|
+
// inline body nodes via @body-inline. Bit shares no tag IDs with
|
|
10321
|
+
// multiple-choice / multiple-choice-1 (which use group_trueFalse).
|
|
10322
|
+
key: ConfigKey.group_trueFalseInlineHighlight,
|
|
10323
|
+
description: "True/False quiz tags for highlighted text (inline body nodes)"
|
|
10324
|
+
},
|
|
10325
|
+
{
|
|
10326
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10327
|
+
key: ConfigKey.property_example,
|
|
10328
|
+
exportJsonKey: [
|
|
10329
|
+
{ "@keyonly": { isExample: true } },
|
|
10330
|
+
{ "@absent": { isExample: true } },
|
|
10331
|
+
{ isExample: true, example: "$" }
|
|
10332
|
+
],
|
|
10333
|
+
description: "The example(s) for the bit",
|
|
10334
|
+
format: TagFormat.bitmarkText,
|
|
10335
|
+
nullable: true
|
|
8774
10336
|
}
|
|
8775
10337
|
]
|
|
8776
10338
|
},
|
|
@@ -8780,15 +10342,8 @@ var BITS = {
|
|
|
8780
10342
|
description: "Image bit, used to create images in articles or books",
|
|
8781
10343
|
tags: [
|
|
8782
10344
|
{
|
|
8783
|
-
key: ConfigKey.
|
|
8784
|
-
|
|
8785
|
-
description: "Background wallpaper for the image, used to set a background for the image",
|
|
8786
|
-
chain: [
|
|
8787
|
-
{
|
|
8788
|
-
key: ConfigKey.group_resourceImageCommon,
|
|
8789
|
-
description: "Common resource image tags for images"
|
|
8790
|
-
}
|
|
8791
|
-
]
|
|
10345
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
10346
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
8792
10347
|
},
|
|
8793
10348
|
{
|
|
8794
10349
|
key: ConfigKey.group_resourceBitTags,
|
|
@@ -8891,8 +10446,15 @@ var BITS = {
|
|
|
8891
10446
|
},
|
|
8892
10447
|
[BitType.imageSeparator]: {
|
|
8893
10448
|
since: "1.4.15",
|
|
8894
|
-
baseBitType: BitType.
|
|
8895
|
-
description: "Image separator bit, used to create separators in articles or books"
|
|
10449
|
+
baseBitType: BitType._standard,
|
|
10450
|
+
description: "Image separator bit, used to create separators in articles or books",
|
|
10451
|
+
tags: [
|
|
10452
|
+
{
|
|
10453
|
+
key: ConfigKey.group_imageNoZoom,
|
|
10454
|
+
description: "Image no zoom tags for images, used to define whether images should have zoom functionality"
|
|
10455
|
+
}
|
|
10456
|
+
],
|
|
10457
|
+
resourceAttachmentAllowed: false
|
|
8896
10458
|
},
|
|
8897
10459
|
[BitType.imageSeparatorAlt]: {
|
|
8898
10460
|
since: "1.16.0",
|
|
@@ -8931,15 +10493,20 @@ var BITS = {
|
|
|
8931
10493
|
},
|
|
8932
10494
|
[BitType.pageBanner]: {
|
|
8933
10495
|
since: "1.4.3",
|
|
8934
|
-
baseBitType: BitType.
|
|
10496
|
+
baseBitType: BitType._standard,
|
|
8935
10497
|
description: "Page banner bit, used to create banners for pages in articles or books",
|
|
8936
10498
|
tags: [
|
|
8937
10499
|
{
|
|
8938
10500
|
key: ConfigKey.property_slug,
|
|
8939
10501
|
description: "Slug for the page banner, used to identify the banner in the system",
|
|
8940
10502
|
format: TagFormat.plainText
|
|
10503
|
+
},
|
|
10504
|
+
{
|
|
10505
|
+
key: ConfigKey.group_imageNoZoom,
|
|
10506
|
+
description: "Image no zoom tags for images, used to define whether images should have zoom functionality"
|
|
8941
10507
|
}
|
|
8942
|
-
]
|
|
10508
|
+
],
|
|
10509
|
+
resourceAttachmentAllowed: false
|
|
8943
10510
|
},
|
|
8944
10511
|
[BitType.pageHero]: {
|
|
8945
10512
|
since: "1.11.0",
|
|
@@ -8954,7 +10521,7 @@ var BITS = {
|
|
|
8954
10521
|
},
|
|
8955
10522
|
[BitType.tableImage]: {
|
|
8956
10523
|
since: "1.5.15",
|
|
8957
|
-
baseBitType: BitType.
|
|
10524
|
+
baseBitType: BitType.tableExtended,
|
|
8958
10525
|
description: "Table image bit, used to create images in tables in articles or books",
|
|
8959
10526
|
tags: [
|
|
8960
10527
|
{
|
|
@@ -8963,15 +10530,8 @@ var BITS = {
|
|
|
8963
10530
|
format: TagFormat.bitmarkText
|
|
8964
10531
|
},
|
|
8965
10532
|
{
|
|
8966
|
-
key: ConfigKey.
|
|
8967
|
-
|
|
8968
|
-
description: "Background wallpaper for the image, used to set a background for the image",
|
|
8969
|
-
chain: [
|
|
8970
|
-
{
|
|
8971
|
-
key: ConfigKey.group_resourceImageCommon,
|
|
8972
|
-
description: "Common resource image tags for images"
|
|
8973
|
-
}
|
|
8974
|
-
]
|
|
10533
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
10534
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
8975
10535
|
},
|
|
8976
10536
|
{
|
|
8977
10537
|
key: ConfigKey.group_resourceBitTags,
|
|
@@ -9114,10 +10674,10 @@ var BITS = {
|
|
|
9114
10674
|
description: "Resource bit tags for logo grave images, used to define additional properties"
|
|
9115
10675
|
},
|
|
9116
10676
|
{
|
|
9117
|
-
// Image resource
|
|
9118
|
-
key: ConfigKey.
|
|
10677
|
+
// Image resource — fully-expanded shape (see BitType.extractorImage).
|
|
10678
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
9119
10679
|
description: "Resource image tags for logo grave images, used to attach images",
|
|
9120
|
-
exportJsonKey: { logos: "$" },
|
|
10680
|
+
exportJsonKey: { logos: [{ type: "image", image: { src: "$" } }] },
|
|
9121
10681
|
minCount: 1,
|
|
9122
10682
|
maxCount: Count.infinity
|
|
9123
10683
|
}
|
|
@@ -9127,7 +10687,17 @@ var BITS = {
|
|
|
9127
10687
|
[BitType.prototypeImages]: {
|
|
9128
10688
|
since: "1.6.1",
|
|
9129
10689
|
baseBitType: BitType.imagesLogoGrave,
|
|
9130
|
-
description: "Prototype images bit, used to create prototype images in articles or books"
|
|
10690
|
+
description: "Prototype images bit, used to create prototype images in articles or books",
|
|
10691
|
+
tags: [
|
|
10692
|
+
{
|
|
10693
|
+
// Override inherited `logos` wrapper with `images` for this bit type.
|
|
10694
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
10695
|
+
description: "Resource image tags for prototype images",
|
|
10696
|
+
exportJsonKey: { images: [{ type: "image", image: { src: "$" } }] },
|
|
10697
|
+
minCount: 1,
|
|
10698
|
+
maxCount: Count.infinity
|
|
10699
|
+
}
|
|
10700
|
+
]
|
|
9131
10701
|
},
|
|
9132
10702
|
[BitType.internalLink]: {
|
|
9133
10703
|
since: "1.3.0",
|
|
@@ -9157,6 +10727,18 @@ var BITS = {
|
|
|
9157
10727
|
exportJsonKey: {},
|
|
9158
10728
|
description: "Reasonable number of characters for the interview, used to limit input size",
|
|
9159
10729
|
format: TagFormat.number
|
|
10730
|
+
},
|
|
10731
|
+
{
|
|
10732
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10733
|
+
key: ConfigKey.property_example,
|
|
10734
|
+
exportJsonKey: [
|
|
10735
|
+
{ "@keyonly": { isExample: true } },
|
|
10736
|
+
{ "@absent": { isExample: true } },
|
|
10737
|
+
{ isExample: true, example: "$" }
|
|
10738
|
+
],
|
|
10739
|
+
description: "The example(s) for the bit",
|
|
10740
|
+
format: TagFormat.bitmarkText,
|
|
10741
|
+
nullable: true
|
|
9160
10742
|
}
|
|
9161
10743
|
],
|
|
9162
10744
|
cardSet: CardSetConfigKey.questions
|
|
@@ -9515,6 +11097,18 @@ var BITS = {
|
|
|
9515
11097
|
{
|
|
9516
11098
|
key: ConfigKey.group_mark,
|
|
9517
11099
|
description: "Mark tags, used to define the content of marks"
|
|
11100
|
+
},
|
|
11101
|
+
{
|
|
11102
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11103
|
+
key: ConfigKey.property_example,
|
|
11104
|
+
exportJsonKey: [
|
|
11105
|
+
{ "@keyonly": { isExample: true } },
|
|
11106
|
+
{ "@absent": { isExample: true } },
|
|
11107
|
+
{ isExample: true, example: "$" }
|
|
11108
|
+
],
|
|
11109
|
+
description: "The example(s) for the bit",
|
|
11110
|
+
format: TagFormat.bitmarkText,
|
|
11111
|
+
nullable: true
|
|
9518
11112
|
}
|
|
9519
11113
|
]
|
|
9520
11114
|
},
|
|
@@ -9534,6 +11128,23 @@ var BITS = {
|
|
|
9534
11128
|
description: "Case sensitivity for matching pairs, used to define if matches are case-sensitive",
|
|
9535
11129
|
format: TagFormat.boolean,
|
|
9536
11130
|
defaultValue: "true"
|
|
11131
|
+
},
|
|
11132
|
+
{
|
|
11133
|
+
// Override inherited @example: in `isTopLevelExample` allow-list
|
|
11134
|
+
// (covers match, matchAll, matchReverse, matchAllReverse,
|
|
11135
|
+
// matchSolutionGrouped, matchMatrix, matchAudio, matchPicture).
|
|
11136
|
+
// Bit-level fires emit only `isExample`; the @example value (when
|
|
11137
|
+
// provided) is recorded in the ancestor stack and consumed by
|
|
11138
|
+
// per-pair/per-cell variant overrides — not surfaced at bit scope.
|
|
11139
|
+
key: ConfigKey.property_example,
|
|
11140
|
+
exportJsonKey: [
|
|
11141
|
+
{ "@keyonly": { isExample: true } },
|
|
11142
|
+
{ "@absent": { isExample: true } },
|
|
11143
|
+
{ isExample: true }
|
|
11144
|
+
],
|
|
11145
|
+
description: "The example(s) for the bit",
|
|
11146
|
+
format: TagFormat.bitmarkText,
|
|
11147
|
+
nullable: true
|
|
9537
11148
|
}
|
|
9538
11149
|
],
|
|
9539
11150
|
cardSet: CardSetConfigKey.matchPairs
|
|
@@ -9618,6 +11229,18 @@ var BITS = {
|
|
|
9618
11229
|
{
|
|
9619
11230
|
key: ConfigKey.group_trueFalse,
|
|
9620
11231
|
description: "True/False tags for multiple choice 1 questions"
|
|
11232
|
+
},
|
|
11233
|
+
{
|
|
11234
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11235
|
+
key: ConfigKey.property_example,
|
|
11236
|
+
exportJsonKey: [
|
|
11237
|
+
{ "@keyonly": { isExample: true } },
|
|
11238
|
+
{ "@absent": { isExample: true } },
|
|
11239
|
+
{ isExample: true, example: "$" }
|
|
11240
|
+
],
|
|
11241
|
+
description: "The example(s) for the bit",
|
|
11242
|
+
format: TagFormat.bitmarkText,
|
|
11243
|
+
nullable: true
|
|
9621
11244
|
}
|
|
9622
11245
|
]
|
|
9623
11246
|
},
|
|
@@ -9639,8 +11262,20 @@ var BITS = {
|
|
|
9639
11262
|
{
|
|
9640
11263
|
key: ConfigKey.group_trueFalse,
|
|
9641
11264
|
description: "True/False tags for multiple choice questions"
|
|
9642
|
-
}
|
|
11265
|
+
},
|
|
9643
11266
|
// This is actually for multiple-choice-1, but we support it here as well (as many bits are wrong)
|
|
11267
|
+
{
|
|
11268
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11269
|
+
key: ConfigKey.property_example,
|
|
11270
|
+
exportJsonKey: [
|
|
11271
|
+
{ "@keyonly": { isExample: true } },
|
|
11272
|
+
{ "@absent": { isExample: true } },
|
|
11273
|
+
{ isExample: true, example: "$" }
|
|
11274
|
+
],
|
|
11275
|
+
description: "The example(s) for the bit",
|
|
11276
|
+
format: TagFormat.bitmarkText,
|
|
11277
|
+
nullable: true
|
|
11278
|
+
}
|
|
9644
11279
|
],
|
|
9645
11280
|
cardSet: CardSetConfigKey.quiz
|
|
9646
11281
|
},
|
|
@@ -9660,8 +11295,20 @@ var BITS = {
|
|
|
9660
11295
|
description: "Common quiz tags for multiple choice text questions"
|
|
9661
11296
|
},
|
|
9662
11297
|
{
|
|
9663
|
-
key: ConfigKey.
|
|
11298
|
+
key: ConfigKey.group_trueFalseInlineSelect,
|
|
9664
11299
|
description: "True/False tags for multiple choice text questions"
|
|
11300
|
+
},
|
|
11301
|
+
{
|
|
11302
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11303
|
+
key: ConfigKey.property_example,
|
|
11304
|
+
exportJsonKey: [
|
|
11305
|
+
{ "@keyonly": { isExample: true } },
|
|
11306
|
+
{ "@absent": { isExample: true } },
|
|
11307
|
+
{ isExample: true, example: "$" }
|
|
11308
|
+
],
|
|
11309
|
+
description: "The example(s) for the bit",
|
|
11310
|
+
format: TagFormat.bitmarkText,
|
|
11311
|
+
nullable: true
|
|
9665
11312
|
}
|
|
9666
11313
|
]
|
|
9667
11314
|
},
|
|
@@ -9686,8 +11333,20 @@ var BITS = {
|
|
|
9686
11333
|
description: "Common quiz tags for multiple response 1 questions"
|
|
9687
11334
|
},
|
|
9688
11335
|
{
|
|
9689
|
-
key: ConfigKey.
|
|
11336
|
+
key: ConfigKey.group_trueFalseResponses,
|
|
9690
11337
|
description: "True/False tags for multiple response 1 questions"
|
|
11338
|
+
},
|
|
11339
|
+
{
|
|
11340
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11341
|
+
key: ConfigKey.property_example,
|
|
11342
|
+
exportJsonKey: [
|
|
11343
|
+
{ "@keyonly": { isExample: true } },
|
|
11344
|
+
{ "@absent": { isExample: true } },
|
|
11345
|
+
{ isExample: true, example: "$" }
|
|
11346
|
+
],
|
|
11347
|
+
description: "The example(s) for the bit",
|
|
11348
|
+
format: TagFormat.bitmarkText,
|
|
11349
|
+
nullable: true
|
|
9691
11350
|
}
|
|
9692
11351
|
]
|
|
9693
11352
|
},
|
|
@@ -9707,12 +11366,24 @@ var BITS = {
|
|
|
9707
11366
|
description: "Common quiz tags for multiple response questions"
|
|
9708
11367
|
},
|
|
9709
11368
|
{
|
|
9710
|
-
key: ConfigKey.
|
|
11369
|
+
key: ConfigKey.group_trueFalseResponses,
|
|
9711
11370
|
description: "True/False tags for multiple response questions"
|
|
9712
|
-
}
|
|
11371
|
+
},
|
|
9713
11372
|
// This is actually for multiple-response-1, but we support it here as well (as many bits are wrong)
|
|
11373
|
+
{
|
|
11374
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11375
|
+
key: ConfigKey.property_example,
|
|
11376
|
+
exportJsonKey: [
|
|
11377
|
+
{ "@keyonly": { isExample: true } },
|
|
11378
|
+
{ "@absent": { isExample: true } },
|
|
11379
|
+
{ isExample: true, example: "$" }
|
|
11380
|
+
],
|
|
11381
|
+
description: "The example(s) for the bit",
|
|
11382
|
+
format: TagFormat.bitmarkText,
|
|
11383
|
+
nullable: true
|
|
11384
|
+
}
|
|
9714
11385
|
],
|
|
9715
|
-
cardSet: CardSetConfigKey.
|
|
11386
|
+
cardSet: CardSetConfigKey.quizResponses
|
|
9716
11387
|
},
|
|
9717
11388
|
[BitType.coachSelfReflectionMultipleResponse]: {
|
|
9718
11389
|
since: "1.3.0",
|
|
@@ -9962,6 +11633,8 @@ var BITS = {
|
|
|
9962
11633
|
},
|
|
9963
11634
|
{
|
|
9964
11635
|
key: ConfigKey.resource_platformIcon,
|
|
11636
|
+
jsonKey: "platformIcon|resource(type=image, key=image)",
|
|
11637
|
+
exportJsonKey: { platformIcon: { type: "image", image: { src: "$" } } },
|
|
9965
11638
|
description: "The platform icon",
|
|
9966
11639
|
chain: [
|
|
9967
11640
|
{
|
|
@@ -9997,6 +11670,8 @@ var BITS = {
|
|
|
9997
11670
|
tags: [
|
|
9998
11671
|
{
|
|
9999
11672
|
key: ConfigKey.resource_platformLogo,
|
|
11673
|
+
jsonKey: "platformLogo|resource(type=image, key=image)",
|
|
11674
|
+
exportJsonKey: { platformLogo: { type: "image", image: { src: "$" } } },
|
|
10000
11675
|
description: "The platform logo",
|
|
10001
11676
|
chain: [
|
|
10002
11677
|
{
|
|
@@ -10208,7 +11883,8 @@ var BITS = {
|
|
|
10208
11883
|
{ isExample: true, example: "$" }
|
|
10209
11884
|
],
|
|
10210
11885
|
description: "The example text for the review note bit",
|
|
10211
|
-
format: TagFormat.plainText
|
|
11886
|
+
format: TagFormat.plainText,
|
|
11887
|
+
nullable: true
|
|
10212
11888
|
}
|
|
10213
11889
|
],
|
|
10214
11890
|
rootExampleType: ExampleType.string
|
|
@@ -10295,7 +11971,8 @@ var BITS = {
|
|
|
10295
11971
|
{ isExample: true, example: "$" }
|
|
10296
11972
|
],
|
|
10297
11973
|
description: "The example flag for the bit (boolean)",
|
|
10298
|
-
format: TagFormat.
|
|
11974
|
+
format: TagFormat.boolean,
|
|
11975
|
+
nullable: true
|
|
10299
11976
|
}
|
|
10300
11977
|
],
|
|
10301
11978
|
cardSet: CardSetConfigKey.elements,
|
|
@@ -10569,15 +12246,8 @@ var BITS = {
|
|
|
10569
12246
|
format: TagFormat.bitmarkText
|
|
10570
12247
|
},
|
|
10571
12248
|
{
|
|
10572
|
-
key: ConfigKey.
|
|
10573
|
-
|
|
10574
|
-
description: "Background wallpaper for the image, used to set a background for the image",
|
|
10575
|
-
chain: [
|
|
10576
|
-
{
|
|
10577
|
-
key: ConfigKey.group_resourceImageCommon,
|
|
10578
|
-
description: "Common resource image tags for images"
|
|
10579
|
-
}
|
|
10580
|
-
]
|
|
12249
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
12250
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
10581
12251
|
},
|
|
10582
12252
|
{
|
|
10583
12253
|
key: ConfigKey.group_resourceBitTags,
|
|
@@ -10954,16 +12624,20 @@ var BITS = {
|
|
|
10954
12624
|
format: TagFormat.plainText
|
|
10955
12625
|
},
|
|
10956
12626
|
{
|
|
10957
|
-
|
|
12627
|
+
// PLAN-067 Edit #1: true-false-1's `+` / `-` emit a flat
|
|
12628
|
+
// `{ statement, isCorrect }` at bit root (single-statement bit),
|
|
12629
|
+
// not a `choices[]` array. Format is bitmarkText so the statement
|
|
12630
|
+
// body renders as a ProseMirror tree, matching reference fixtures.
|
|
12631
|
+
exportJsonKey: { statement: "$", isCorrect: true },
|
|
10958
12632
|
key: ConfigKey.tag_true,
|
|
10959
12633
|
description: "Tag for the true option in the true/false question",
|
|
10960
|
-
format: TagFormat.
|
|
12634
|
+
format: TagFormat.bitmarkText
|
|
10961
12635
|
},
|
|
10962
12636
|
{
|
|
10963
|
-
exportJsonKey: {
|
|
12637
|
+
exportJsonKey: { statement: "$", isCorrect: false },
|
|
10964
12638
|
key: ConfigKey.tag_false,
|
|
10965
12639
|
description: "Tag for the false option in the true/false question",
|
|
10966
|
-
format: TagFormat.
|
|
12640
|
+
format: TagFormat.bitmarkText
|
|
10967
12641
|
},
|
|
10968
12642
|
{
|
|
10969
12643
|
// Override inherited @example from group_standardTags: boolean root
|
|
@@ -10974,14 +12648,24 @@ var BITS = {
|
|
|
10974
12648
|
// sufficient for `[+...]` (correct) statements which dominate the
|
|
10975
12649
|
// fixtures; `[-...]` (incorrect) bits with bare `[@example]` would
|
|
10976
12650
|
// need either a runtime extension or an explicit `[@example:false]`.
|
|
12651
|
+
//
|
|
12652
|
+
// Format is `boolean` so `[@example:false]` coerces to JSON `false`
|
|
12653
|
+
// (a natural default that gets stripped in optimised mode, matching
|
|
12654
|
+
// BPG's `rootExampleType: boolean`). PlainText would emit the
|
|
12655
|
+
// STRING `"false"` which doesn't strip.
|
|
10977
12656
|
key: ConfigKey.property_example,
|
|
10978
12657
|
exportJsonKey: [
|
|
10979
12658
|
{ "@keyonly": { isExample: true, example: true } },
|
|
10980
12659
|
{ "@absent": { isExample: true, example: true } },
|
|
12660
|
+
// `[@example:false]`: emit `isExample: true` only — `example: false`
|
|
12661
|
+
// is the natural default for boolean, stripped in optimised mode.
|
|
12662
|
+
// Mirrors BPG `removeUnwantedProperties` `ignoreAllFalse: true`.
|
|
12663
|
+
{ "@value=false": { isExample: true } },
|
|
10981
12664
|
{ isExample: true, example: "$" }
|
|
10982
12665
|
],
|
|
10983
12666
|
description: "The example flag for the bit (boolean)",
|
|
10984
|
-
format: TagFormat.
|
|
12667
|
+
format: TagFormat.boolean,
|
|
12668
|
+
nullable: true
|
|
10985
12669
|
}
|
|
10986
12670
|
],
|
|
10987
12671
|
rootExampleType: ExampleType.boolean
|
|
@@ -11005,6 +12689,18 @@ var BITS = {
|
|
|
11005
12689
|
key: ConfigKey.property_labelFalse,
|
|
11006
12690
|
description: "Label for the false option in the true/false question",
|
|
11007
12691
|
format: TagFormat.plainText
|
|
12692
|
+
},
|
|
12693
|
+
{
|
|
12694
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
12695
|
+
key: ConfigKey.property_example,
|
|
12696
|
+
exportJsonKey: [
|
|
12697
|
+
{ "@keyonly": { isExample: true } },
|
|
12698
|
+
{ "@absent": { isExample: true } },
|
|
12699
|
+
{ isExample: true, example: "$" }
|
|
12700
|
+
],
|
|
12701
|
+
description: "The example(s) for the bit",
|
|
12702
|
+
format: TagFormat.bitmarkText,
|
|
12703
|
+
nullable: true
|
|
11008
12704
|
}
|
|
11009
12705
|
],
|
|
11010
12706
|
cardSet: CardSetConfigKey.statements
|
|
@@ -11194,6 +12890,11 @@ var BITS = {
|
|
|
11194
12890
|
baseBitType: BitType.vendorStripePricingTable,
|
|
11195
12891
|
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",
|
|
11196
12892
|
tags: [
|
|
12893
|
+
{
|
|
12894
|
+
key: ConfigKey.property_stripePricingTableDescriptiveName,
|
|
12895
|
+
description: "Descriptive name for the Stripe pricing table",
|
|
12896
|
+
format: TagFormat.plainText
|
|
12897
|
+
},
|
|
11197
12898
|
{
|
|
11198
12899
|
key: ConfigKey.property_printOnRequestCustomerId,
|
|
11199
12900
|
description: "Print-on-request customer ID, used to identify the customer for the print-on-request flow",
|
|
@@ -11670,7 +13371,7 @@ var instance2 = new Config();
|
|
|
11670
13371
|
// src/generated/package_info.ts
|
|
11671
13372
|
var PACKAGE_INFO = {
|
|
11672
13373
|
"name": "@gmb/bitmark-parser-generator",
|
|
11673
|
-
"version": "5.
|
|
13374
|
+
"version": "5.24.0",
|
|
11674
13375
|
"license": "ISC"};
|
|
11675
13376
|
var Environment = {
|
|
11676
13377
|
unknown: "",
|
|
@@ -12603,6 +14304,8 @@ var NodeType = {
|
|
|
12603
14304
|
stillImageFilmLink: "stillImageFilmLink",
|
|
12604
14305
|
stripePricingTableId: "stripePricingTableId",
|
|
12605
14306
|
stripePricingTableIdValue: "stripePricingTableIdValue",
|
|
14307
|
+
stripePricingTableDescriptiveName: "stripePricingTableDescriptiveName",
|
|
14308
|
+
stripePricingTableDescriptiveNameValue: "stripePricingTableDescriptiveNameValue",
|
|
12606
14309
|
stripePublishableKey: "stripePublishableKey",
|
|
12607
14310
|
stripePublishableKeyValue: "stripePublishableKeyValue",
|
|
12608
14311
|
subject: "subject",
|
|
@@ -25844,6 +27547,12 @@ var Builder = class extends BaseBuilder {
|
|
|
25844
27547
|
data.stripePricingTableId,
|
|
25845
27548
|
options
|
|
25846
27549
|
),
|
|
27550
|
+
stripePricingTableDescriptiveName: this.toAstProperty(
|
|
27551
|
+
bitType,
|
|
27552
|
+
ConfigKey.property_stripePricingTableDescriptiveName,
|
|
27553
|
+
data.stripePricingTableDescriptiveName,
|
|
27554
|
+
options
|
|
27555
|
+
),
|
|
25847
27556
|
stripePublishableKey: this.toAstProperty(
|
|
25848
27557
|
bitType,
|
|
25849
27558
|
ConfigKey.property_stripePublishableKey,
|
|
@@ -33996,6 +35705,7 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
33996
35705
|
const cardSetType = bitConfig.cardSet?.configKey;
|
|
33997
35706
|
switch (cardSetType) {
|
|
33998
35707
|
case CardSetConfigKey.flashcard:
|
|
35708
|
+
case CardSetConfigKey.flashcard1:
|
|
33999
35709
|
case CardSetConfigKey.definitionList:
|
|
34000
35710
|
result = parseFlashcardOrDefinitionList(context, bitType, processedCardSet);
|
|
34001
35711
|
break;
|
|
@@ -34009,6 +35719,7 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
34009
35719
|
result = parseFeedback(context, bitType, processedCardSet);
|
|
34010
35720
|
break;
|
|
34011
35721
|
case CardSetConfigKey.quiz:
|
|
35722
|
+
case CardSetConfigKey.quizResponses:
|
|
34012
35723
|
result = parseQuiz(context, bitType, processedCardSet, choicesV1, responsesV1);
|
|
34013
35724
|
break;
|
|
34014
35725
|
case CardSetConfigKey.questions:
|
|
@@ -34035,6 +35746,7 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
34035
35746
|
break;
|
|
34036
35747
|
case CardSetConfigKey.clozeList:
|
|
34037
35748
|
case CardSetConfigKey.exampleBitList:
|
|
35749
|
+
case CardSetConfigKey.pageFooterSections:
|
|
34038
35750
|
case CardSetConfigKey.bookReferenceList:
|
|
34039
35751
|
result = parseCardBits(context, bitType, textFormat, processedCardSet);
|
|
34040
35752
|
break;
|
|
@@ -40729,6 +42441,13 @@ var ConfigBuilder = class {
|
|
|
40729
42441
|
const cardSetConfig = CARDSETS[cardSetKey];
|
|
40730
42442
|
if (!cardSetConfig) return void 0;
|
|
40731
42443
|
const normalizedKey = normalizeCardKey(cardSetKey);
|
|
42444
|
+
const variantTagEntriesTypeOrder = [
|
|
42445
|
+
BitTagConfigKeyType.group,
|
|
42446
|
+
BitTagConfigKeyType.tag,
|
|
42447
|
+
BitTagConfigKeyType.property,
|
|
42448
|
+
BitTagConfigKeyType.resource,
|
|
42449
|
+
BitTagConfigKeyType.unknown
|
|
42450
|
+
];
|
|
40732
42451
|
const sides = cardSetConfig.sides.map((side, sideIdx) => {
|
|
40733
42452
|
const sidePath = `cardSets.${normalizedKey} / sides.${side.name ?? `[${sideIdx}]`}`;
|
|
40734
42453
|
const variants = side.variants.map((variant, variantIdx) => {
|
|
@@ -40739,7 +42458,7 @@ var ConfigBuilder = class {
|
|
|
40739
42458
|
const tagB = b[1];
|
|
40740
42459
|
const typeA = typeFromConfigKey(tagA.key);
|
|
40741
42460
|
const typeB = typeFromConfigKey(tagB.key);
|
|
40742
|
-
const typeOrder =
|
|
42461
|
+
const typeOrder = variantTagEntriesTypeOrder.indexOf(typeA) - variantTagEntriesTypeOrder.indexOf(typeB);
|
|
40743
42462
|
return typeOrder;
|
|
40744
42463
|
});
|
|
40745
42464
|
for (const [, variantTag] of variantTagEntries) {
|
|
@@ -40779,6 +42498,10 @@ var ConfigBuilder = class {
|
|
|
40779
42498
|
name: sectionName,
|
|
40780
42499
|
...section.isDefault ? { isDefault: true } : {},
|
|
40781
42500
|
...cardJsonKeyField(section, "jsonKey", "exportJsonKey", sectionPath),
|
|
42501
|
+
// PLAN-085: per-section cardinality. Emit only when non-default
|
|
42502
|
+
// (treat `0` / undefined as "unbounded — omit").
|
|
42503
|
+
...section.minCount != null && section.minCount !== 0 ? { min: section.minCount } : {},
|
|
42504
|
+
...section.maxCount != null && section.maxCount !== 0 ? { max: section.maxCount } : {},
|
|
40782
42505
|
sides: cardSides
|
|
40783
42506
|
};
|
|
40784
42507
|
});
|
|
@@ -40848,10 +42571,20 @@ var ConfigBuilder = class {
|
|
|
40848
42571
|
return typeOrder;
|
|
40849
42572
|
});
|
|
40850
42573
|
const isInheritedFrom = bitGroupConfigKeys.has(b.bitType);
|
|
42574
|
+
const indexByKey = /* @__PURE__ */ new Map();
|
|
42575
|
+
const pushOrReplace = (entry) => {
|
|
42576
|
+
const existing = indexByKey.get(entry.key);
|
|
42577
|
+
if (existing !== void 0) {
|
|
42578
|
+
tags2[existing] = entry;
|
|
42579
|
+
} else {
|
|
42580
|
+
indexByKey.set(entry.key, tags2.length);
|
|
42581
|
+
tags2.push(entry);
|
|
42582
|
+
}
|
|
42583
|
+
};
|
|
40851
42584
|
if (isInheritedFrom) {
|
|
40852
42585
|
const resolvedGroups = resolveGroupReferences(`group-${b.bitType}`);
|
|
40853
42586
|
for (const ref of resolvedGroups) {
|
|
40854
|
-
|
|
42587
|
+
pushOrReplace({
|
|
40855
42588
|
type: "group",
|
|
40856
42589
|
key: ref.key,
|
|
40857
42590
|
...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
|
|
@@ -40864,7 +42597,7 @@ var ConfigBuilder = class {
|
|
|
40864
42597
|
if (b.baseBitType) {
|
|
40865
42598
|
const resolvedGroups = resolveGroupReferences(`group-${b.baseBitType}`);
|
|
40866
42599
|
for (const ref of resolvedGroups) {
|
|
40867
|
-
|
|
42600
|
+
pushOrReplace({
|
|
40868
42601
|
type: "group",
|
|
40869
42602
|
key: ref.key,
|
|
40870
42603
|
...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
|
|
@@ -40875,7 +42608,9 @@ var ConfigBuilder = class {
|
|
|
40875
42608
|
}
|
|
40876
42609
|
}
|
|
40877
42610
|
for (const [_tagKey, tag] of tagEntries) {
|
|
40878
|
-
|
|
42611
|
+
for (const entry of processTagEntries(tag, [])) {
|
|
42612
|
+
pushOrReplace(entry);
|
|
42613
|
+
}
|
|
40879
42614
|
}
|
|
40880
42615
|
}
|
|
40881
42616
|
let cardRef;
|