@gmb/bitmark-parser-generator 5.22.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 +2669 -166
- package/dist/browser/cjs/index.cjs.map +1 -1
- package/dist/browser/cjs/index.d.cts +180 -47
- package/dist/browser/esm/index.d.ts +180 -47
- package/dist/browser/esm/index.js +2668 -166
- package/dist/browser/esm/index.js.map +1 -1
- package/dist/cli/main.js +2704 -249
- package/dist/cli/main.js.map +1 -1
- package/dist/index.cjs +2817 -249
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +180 -47
- package/dist/index.d.ts +180 -47
- package/dist/index.js +2816 -249
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -31,6 +31,7 @@ __export(index_exports, {
|
|
|
31
31
|
BitmarkStringGenerator: () => BitmarkStringGenerator,
|
|
32
32
|
BitmarkVersion: () => BitmarkVersion,
|
|
33
33
|
BodyTextFormat: () => BodyTextFormat,
|
|
34
|
+
BoundingBoxIndex: () => BoundingBoxIndex,
|
|
34
35
|
Builder: () => Builder,
|
|
35
36
|
CardSetVersion: () => CardSetVersion,
|
|
36
37
|
InfoFormat: () => InfoFormat,
|
|
@@ -326,6 +327,7 @@ var BitType2 = {
|
|
|
326
327
|
footNote: "foot-note",
|
|
327
328
|
formFreeText: "form-free-text",
|
|
328
329
|
formula: "formula",
|
|
330
|
+
formulaImage: "formula-image",
|
|
329
331
|
gapText: "gap-text",
|
|
330
332
|
gapTextInstructionGrouped: "gap-text-instruction-grouped",
|
|
331
333
|
glossaryTerm: "glossary-term",
|
|
@@ -750,8 +752,10 @@ var TagFormat = {
|
|
|
750
752
|
// If the value is treated as a boolean
|
|
751
753
|
invertedBoolean: "invertedBoolean",
|
|
752
754
|
// If the value is treated as a boolean with the value inverted (e.g. isLongAnswer ==> isShortAnswer = false)
|
|
753
|
-
enumeration: "enumeration"
|
|
755
|
+
enumeration: "enumeration",
|
|
754
756
|
// If the value is treated as an enumeration (the value is a string that must be one of a predefined set of values)
|
|
757
|
+
coordinates: "coordinates"
|
|
758
|
+
// Comma-separated list of 4 numbers (e.g. bounding-box x, y, x1, y1)
|
|
755
759
|
};
|
|
756
760
|
|
|
757
761
|
// src/model/enum/TextFormat.ts
|
|
@@ -774,10 +778,12 @@ var TextFormat2 = {
|
|
|
774
778
|
var import_superenum7 = require("@ncoderz/superenum");
|
|
775
779
|
var CardSetConfigKey = {
|
|
776
780
|
flashcard: "flashcard",
|
|
781
|
+
flashcard1: "flashcard1",
|
|
777
782
|
definitionList: "definitionList",
|
|
778
783
|
elements: "elements",
|
|
779
784
|
statements: "statements",
|
|
780
785
|
quiz: "quiz",
|
|
786
|
+
quizResponses: "quizResponses",
|
|
781
787
|
feedback: "feedback",
|
|
782
788
|
questions: "questions",
|
|
783
789
|
matchPairs: "matchPairs",
|
|
@@ -789,6 +795,7 @@ var CardSetConfigKey = {
|
|
|
789
795
|
pronunciationTable: "pronunciationTable",
|
|
790
796
|
botActionResponses: "botActionResponses",
|
|
791
797
|
exampleBitList: "exampleBitList",
|
|
798
|
+
pageFooterSections: "pageFooterSections",
|
|
792
799
|
clozeList: "clozeList",
|
|
793
800
|
ingredients: "ingredients",
|
|
794
801
|
// DEPRECATED - TO BE REMOVED IN THE FUTURE
|
|
@@ -836,7 +843,11 @@ var AbstractTagConfig = class {
|
|
|
836
843
|
// Default: 0
|
|
837
844
|
__publicField(this, "chain");
|
|
838
845
|
__publicField(this, "jsonKey");
|
|
839
|
-
//
|
|
846
|
+
// Legacy string-form jsonKey
|
|
847
|
+
__publicField(this, "exportJsonKey");
|
|
848
|
+
// New JSON-pattern jsonKey (export-only)
|
|
849
|
+
__publicField(this, "hasExportJsonKey");
|
|
850
|
+
// True iff exportJsonKey was explicitly set
|
|
840
851
|
__publicField(this, "deprecated");
|
|
841
852
|
this.type = params.type;
|
|
842
853
|
this.configKey = params.configKey;
|
|
@@ -845,6 +856,8 @@ var AbstractTagConfig = class {
|
|
|
845
856
|
this.minCount = params.minCount;
|
|
846
857
|
this.chain = params.chain;
|
|
847
858
|
this.jsonKey = params.jsonKey;
|
|
859
|
+
this.exportJsonKey = params.exportJsonKey;
|
|
860
|
+
this.hasExportJsonKey = params.hasExportJsonKey;
|
|
848
861
|
this.deprecated = params.deprecated;
|
|
849
862
|
}
|
|
850
863
|
};
|
|
@@ -854,7 +867,6 @@ var MarkupTagConfig = class extends AbstractTagConfig {
|
|
|
854
867
|
constructor(params) {
|
|
855
868
|
super({
|
|
856
869
|
type: BitTagConfigKeyType.tag,
|
|
857
|
-
jsonKey: void 0,
|
|
858
870
|
...params
|
|
859
871
|
});
|
|
860
872
|
__publicField(this, "type", BitTagConfigKeyType.tag);
|
|
@@ -966,8 +978,8 @@ var ResourceTagConfig = class extends AbstractTagConfig {
|
|
|
966
978
|
|
|
967
979
|
// src/model/config/CardVariantConfig.ts
|
|
968
980
|
var CardVariantConfig = class {
|
|
969
|
-
//
|
|
970
|
-
constructor(tags2, bodyAllowed, bodyRequired, repeatCount, jsonKey) {
|
|
981
|
+
// Body text format. Default: bitmark++
|
|
982
|
+
constructor(tags2, bodyAllowed, bodyRequired, repeatCount, jsonKey, exportJsonKey, hasExportJsonKey = false, format) {
|
|
971
983
|
__publicField(this, "tags");
|
|
972
984
|
__publicField(this, "bodyAllowed");
|
|
973
985
|
// Default: true
|
|
@@ -977,11 +989,19 @@ var CardVariantConfig = class {
|
|
|
977
989
|
// Default: 1
|
|
978
990
|
// JSON mapping fields
|
|
979
991
|
__publicField(this, "jsonKey");
|
|
992
|
+
// JSON path for body text (legacy)
|
|
993
|
+
__publicField(this, "exportJsonKey");
|
|
994
|
+
// New JSON-pattern jsonKey
|
|
995
|
+
__publicField(this, "hasExportJsonKey");
|
|
996
|
+
__publicField(this, "format");
|
|
980
997
|
this.tags = tags2;
|
|
981
998
|
this.bodyAllowed = bodyAllowed == null ? true : bodyAllowed;
|
|
982
999
|
this.bodyRequired = bodyRequired;
|
|
983
1000
|
this.repeatCount = repeatCount;
|
|
984
1001
|
this.jsonKey = jsonKey;
|
|
1002
|
+
this.exportJsonKey = exportJsonKey;
|
|
1003
|
+
this.hasExportJsonKey = hasExportJsonKey;
|
|
1004
|
+
this.format = format;
|
|
985
1005
|
}
|
|
986
1006
|
toString(options) {
|
|
987
1007
|
const opts = Object.assign({}, options);
|
|
@@ -1005,14 +1025,18 @@ ${tag.toString(opts)}`;
|
|
|
1005
1025
|
|
|
1006
1026
|
// src/model/config/CardSideConfig.ts
|
|
1007
1027
|
var CardSideConfig = class {
|
|
1008
|
-
constructor(name, repeat, variants, jsonKey) {
|
|
1028
|
+
constructor(name, repeat, variants, jsonKey, exportJsonKey, hasExportJsonKey = false) {
|
|
1009
1029
|
__publicField(this, "name");
|
|
1010
1030
|
__publicField(this, "repeat");
|
|
1011
1031
|
__publicField(this, "jsonKey");
|
|
1032
|
+
__publicField(this, "exportJsonKey");
|
|
1033
|
+
__publicField(this, "hasExportJsonKey");
|
|
1012
1034
|
__publicField(this, "variants");
|
|
1013
1035
|
this.name = name;
|
|
1014
1036
|
this.repeat = repeat;
|
|
1015
1037
|
this.jsonKey = jsonKey;
|
|
1038
|
+
this.exportJsonKey = exportJsonKey;
|
|
1039
|
+
this.hasExportJsonKey = hasExportJsonKey;
|
|
1016
1040
|
this.variants = variants;
|
|
1017
1041
|
}
|
|
1018
1042
|
toString(options) {
|
|
@@ -1034,13 +1058,17 @@ var CardSideConfig = class {
|
|
|
1034
1058
|
|
|
1035
1059
|
// src/model/config/CardSetConfig.ts
|
|
1036
1060
|
var CardSetConfig = class {
|
|
1037
|
-
constructor(configKey, jsonKey, sections, sides) {
|
|
1061
|
+
constructor(configKey, jsonKey, exportJsonKey, hasExportJsonKey, sections, sides) {
|
|
1038
1062
|
__publicField(this, "configKey");
|
|
1039
1063
|
__publicField(this, "jsonKey");
|
|
1064
|
+
__publicField(this, "exportJsonKey");
|
|
1065
|
+
__publicField(this, "hasExportJsonKey");
|
|
1040
1066
|
__publicField(this, "sections");
|
|
1041
1067
|
__publicField(this, "sides");
|
|
1042
1068
|
this.configKey = configKey;
|
|
1043
1069
|
this.jsonKey = jsonKey;
|
|
1070
|
+
this.exportJsonKey = exportJsonKey;
|
|
1071
|
+
this.hasExportJsonKey = hasExportJsonKey;
|
|
1044
1072
|
this.sections = sections;
|
|
1045
1073
|
this.sides = sides;
|
|
1046
1074
|
}
|
|
@@ -1184,12 +1212,17 @@ var groupKeys = {
|
|
|
1184
1212
|
group_standardAllBits: "group_standardAllBits",
|
|
1185
1213
|
group_standardItemLead: "group_standardItemLead",
|
|
1186
1214
|
group_standardItemLeadInstructionHint: "group_standardItemLeadInstructionHint",
|
|
1215
|
+
group_standardInstructionHint: "group_standardInstructionHint",
|
|
1187
1216
|
group_standardTags: "group_standardTags",
|
|
1217
|
+
group_standardTagsNoItemLead: "group_standardTagsNoItemLead",
|
|
1188
1218
|
group_imageSource: "group_imageSource",
|
|
1189
1219
|
group_technicalTerm: "group_technicalTerm",
|
|
1190
1220
|
group_person: "group_person",
|
|
1191
1221
|
group_gap: "group_gap",
|
|
1192
1222
|
group_trueFalse: "group_trueFalse",
|
|
1223
|
+
group_trueFalseInlineHighlight: "group_trueFalseInlineHighlight",
|
|
1224
|
+
group_trueFalseInlineSelect: "group_trueFalseInlineSelect",
|
|
1225
|
+
group_trueFalseResponses: "group_trueFalseResponses",
|
|
1193
1226
|
group_markConfig: "group_markConfig",
|
|
1194
1227
|
group_mark: "group_mark",
|
|
1195
1228
|
group_bookCommon: "group_bookCommon",
|
|
@@ -1197,14 +1230,18 @@ var groupKeys = {
|
|
|
1197
1230
|
group_advertisingCommon: "group_advertisingCommon",
|
|
1198
1231
|
group_platformStylesCommon: "group_platformStylesCommon",
|
|
1199
1232
|
group_quizCommon: "group_quizCommon",
|
|
1233
|
+
group_backgroundWallpaper: "group_backgroundWallpaper",
|
|
1234
|
+
group_imageNoZoom: "group_imageNoZoom",
|
|
1200
1235
|
group_resourceBitTags: "group_resourceBitTags",
|
|
1201
1236
|
group_resourceCommon: "group_resourceCommon",
|
|
1202
1237
|
group_resourceImageCommon: "group_resourceImageCommon",
|
|
1238
|
+
group_resourceImageCommonNoZoom: "group_resourceImageCommonNoZoom",
|
|
1203
1239
|
group_resourceAudioCommon: "group_resourceAudioCommon",
|
|
1204
1240
|
group_resourceVideoCommon: "group_resourceVideoCommon",
|
|
1205
1241
|
group_resourceIcon: "group_resourceIcon",
|
|
1206
1242
|
// Alias for image
|
|
1207
1243
|
group_resourceImage: "group_resourceImage",
|
|
1244
|
+
group_resourceImageNoZoom: "group_resourceImageNoZoom",
|
|
1208
1245
|
group_resourceImageEmbed: "group_resourceImageEmbed",
|
|
1209
1246
|
group_resourceImageLink: "group_resourceImageLink",
|
|
1210
1247
|
group_resourceImageResponsive: "group_resourceImageResponsive",
|
|
@@ -1335,6 +1372,7 @@ var propertyKeys = {
|
|
|
1335
1372
|
property_formula: "@formula",
|
|
1336
1373
|
property_fullName: "@fullName",
|
|
1337
1374
|
property_groupTag: "@groupTag",
|
|
1375
|
+
property_gUri: "@gUri",
|
|
1338
1376
|
property_handInAcceptFileType: "@handInAcceptFileType",
|
|
1339
1377
|
property_handInInstruction: "@handInInstruction",
|
|
1340
1378
|
property_handInRequirement: "@handInRequirement",
|
|
@@ -1470,6 +1508,7 @@ var propertyKeys = {
|
|
|
1470
1508
|
property_siteName: "@siteName",
|
|
1471
1509
|
property_size: "@size",
|
|
1472
1510
|
property_slug: "@slug",
|
|
1511
|
+
property_sourceBB: "@sourceBB",
|
|
1473
1512
|
property_sourceDocument: "@sourceDocument",
|
|
1474
1513
|
property_sourceRL: "@sourceRL",
|
|
1475
1514
|
property_spaceId: "@spaceId",
|
|
@@ -1479,6 +1518,7 @@ var propertyKeys = {
|
|
|
1479
1518
|
property_src4x: "@src4x",
|
|
1480
1519
|
property_srcAlt: "@srcAlt",
|
|
1481
1520
|
property_stripePricingTableId: "@stripePricingTableId",
|
|
1521
|
+
property_stripePricingTableDescriptiveName: "@stripePricingTableDescriptiveName",
|
|
1482
1522
|
property_stripePublishableKey: "@stripePublishableKey",
|
|
1483
1523
|
property_subject: "@subject",
|
|
1484
1524
|
property_subtype: "@subtype",
|
|
@@ -2223,25 +2263,159 @@ var CARDSETS = {
|
|
|
2223
2263
|
//
|
|
2224
2264
|
[CardSetConfigKey.flashcard]: {
|
|
2225
2265
|
jsonKey: "cards",
|
|
2266
|
+
exportJsonKey: { cards: "$" },
|
|
2267
|
+
sides: [
|
|
2268
|
+
{
|
|
2269
|
+
name: "question",
|
|
2270
|
+
variants: [
|
|
2271
|
+
{
|
|
2272
|
+
jsonKey: "question.text",
|
|
2273
|
+
exportJsonKey: [{ "@absent": { question: {} } }, { question: { text: "$" } }],
|
|
2274
|
+
tags: [
|
|
2275
|
+
{
|
|
2276
|
+
key: ConfigKey.group_standardTags,
|
|
2277
|
+
description: "Standard tags for the flashcard."
|
|
2278
|
+
},
|
|
2279
|
+
{
|
|
2280
|
+
exportJsonKey: { title: "$" },
|
|
2281
|
+
key: ConfigKey.tag_title,
|
|
2282
|
+
description: "Title of the flashcard."
|
|
2283
|
+
},
|
|
2284
|
+
{
|
|
2285
|
+
key: ConfigKey.group_resourceIcon,
|
|
2286
|
+
description: "Icon resource for the flashcard.",
|
|
2287
|
+
jsonKey: "question.icon|resource(type=image, key=image)",
|
|
2288
|
+
exportJsonKey: { question: { icon: { type: "image", image: { src: "$" } } } }
|
|
2289
|
+
},
|
|
2290
|
+
{
|
|
2291
|
+
key: ConfigKey.property_example,
|
|
2292
|
+
exportJsonKey: [
|
|
2293
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2294
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2295
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2296
|
+
],
|
|
2297
|
+
description: "Example marker for the flashcard question.",
|
|
2298
|
+
format: TagFormat.bitmarkText,
|
|
2299
|
+
nullable: true
|
|
2300
|
+
}
|
|
2301
|
+
]
|
|
2302
|
+
}
|
|
2303
|
+
]
|
|
2304
|
+
},
|
|
2305
|
+
{
|
|
2306
|
+
name: "answer",
|
|
2307
|
+
variants: [
|
|
2308
|
+
{
|
|
2309
|
+
jsonKey: "answer.text",
|
|
2310
|
+
exportJsonKey: [{ "@absent": { answer: {} } }, { answer: { text: "$" } }],
|
|
2311
|
+
tags: [
|
|
2312
|
+
{
|
|
2313
|
+
key: ConfigKey.group_standardTags,
|
|
2314
|
+
description: "Standard tags for the flashcard."
|
|
2315
|
+
},
|
|
2316
|
+
{
|
|
2317
|
+
exportJsonKey: { title: "$" },
|
|
2318
|
+
key: ConfigKey.tag_title,
|
|
2319
|
+
description: "Title of the flashcard."
|
|
2320
|
+
},
|
|
2321
|
+
{
|
|
2322
|
+
key: ConfigKey.group_resourceIcon,
|
|
2323
|
+
description: "Icon resource for the flashcard.",
|
|
2324
|
+
jsonKey: "answer.icon|resource(type=image, key=image)",
|
|
2325
|
+
exportJsonKey: { answer: { icon: { type: "image", image: { src: "$" } } } }
|
|
2326
|
+
},
|
|
2327
|
+
{
|
|
2328
|
+
key: ConfigKey.property_example,
|
|
2329
|
+
exportJsonKey: [
|
|
2330
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2331
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2332
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2333
|
+
],
|
|
2334
|
+
description: "Example marker for the flashcard answer.",
|
|
2335
|
+
format: TagFormat.bitmarkText,
|
|
2336
|
+
nullable: true
|
|
2337
|
+
}
|
|
2338
|
+
]
|
|
2339
|
+
},
|
|
2340
|
+
{
|
|
2341
|
+
jsonKey: "alternativeAnswers[].text",
|
|
2342
|
+
exportJsonKey: { alternativeAnswers: [{ text: "$" }] },
|
|
2343
|
+
tags: [
|
|
2344
|
+
{
|
|
2345
|
+
key: ConfigKey.group_standardTags,
|
|
2346
|
+
description: "Standard tags for the flashcard."
|
|
2347
|
+
},
|
|
2348
|
+
{
|
|
2349
|
+
exportJsonKey: { title: "$" },
|
|
2350
|
+
key: ConfigKey.tag_title,
|
|
2351
|
+
description: "Title of the flashcard."
|
|
2352
|
+
},
|
|
2353
|
+
{
|
|
2354
|
+
key: ConfigKey.group_resourceIcon,
|
|
2355
|
+
description: "Icon resource for the flashcard.",
|
|
2356
|
+
jsonKey: "alternativeAnswers[].icon|resource(type=image, key=image)",
|
|
2357
|
+
exportJsonKey: {
|
|
2358
|
+
alternativeAnswers: [{ icon: { type: "image", image: { src: "$" } } }]
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
],
|
|
2362
|
+
repeatCount: Count.infinity
|
|
2363
|
+
}
|
|
2364
|
+
]
|
|
2365
|
+
}
|
|
2366
|
+
]
|
|
2367
|
+
},
|
|
2368
|
+
//
|
|
2369
|
+
// flashcard1 — single-card variant of flashcard. Same shape, but capped
|
|
2370
|
+
// at one card via `sections.default.maxCount = 1` (PLAN-085). Used by
|
|
2371
|
+
// the `flashcard-1` bit type; the multi-card `flashcard` and
|
|
2372
|
+
// `q-and-a-card` bit types continue to use the unbounded `flashcard`
|
|
2373
|
+
// cardset.
|
|
2374
|
+
//
|
|
2375
|
+
[CardSetConfigKey.flashcard1]: {
|
|
2376
|
+
jsonKey: "cards",
|
|
2377
|
+
exportJsonKey: { cards: "$" },
|
|
2378
|
+
sections: {
|
|
2379
|
+
default: {
|
|
2380
|
+
jsonKey: "cards",
|
|
2381
|
+
exportJsonKey: { cards: "$" },
|
|
2382
|
+
isDefault: true,
|
|
2383
|
+
maxCount: 1
|
|
2384
|
+
}
|
|
2385
|
+
},
|
|
2226
2386
|
sides: [
|
|
2227
2387
|
{
|
|
2228
2388
|
name: "question",
|
|
2229
2389
|
variants: [
|
|
2230
2390
|
{
|
|
2231
2391
|
jsonKey: "question.text",
|
|
2392
|
+
exportJsonKey: [{ "@absent": { question: {} } }, { question: { text: "$" } }],
|
|
2232
2393
|
tags: [
|
|
2233
2394
|
{
|
|
2234
2395
|
key: ConfigKey.group_standardTags,
|
|
2235
2396
|
description: "Standard tags for the flashcard."
|
|
2236
2397
|
},
|
|
2237
2398
|
{
|
|
2399
|
+
exportJsonKey: { title: "$" },
|
|
2238
2400
|
key: ConfigKey.tag_title,
|
|
2239
2401
|
description: "Title of the flashcard."
|
|
2240
2402
|
},
|
|
2241
2403
|
{
|
|
2242
2404
|
key: ConfigKey.group_resourceIcon,
|
|
2243
2405
|
description: "Icon resource for the flashcard.",
|
|
2244
|
-
jsonKey: "question.icon|resource(type=image, key=image)"
|
|
2406
|
+
jsonKey: "question.icon|resource(type=image, key=image)",
|
|
2407
|
+
exportJsonKey: { question: { icon: { type: "image", image: { src: "$" } } } }
|
|
2408
|
+
},
|
|
2409
|
+
{
|
|
2410
|
+
key: ConfigKey.property_example,
|
|
2411
|
+
exportJsonKey: [
|
|
2412
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2413
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2414
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2415
|
+
],
|
|
2416
|
+
description: "Example marker for the flashcard question.",
|
|
2417
|
+
format: TagFormat.bitmarkText,
|
|
2418
|
+
nullable: true
|
|
2245
2419
|
}
|
|
2246
2420
|
]
|
|
2247
2421
|
}
|
|
@@ -2252,37 +2426,56 @@ var CARDSETS = {
|
|
|
2252
2426
|
variants: [
|
|
2253
2427
|
{
|
|
2254
2428
|
jsonKey: "answer.text",
|
|
2429
|
+
exportJsonKey: [{ "@absent": { answer: {} } }, { answer: { text: "$" } }],
|
|
2255
2430
|
tags: [
|
|
2256
2431
|
{
|
|
2257
2432
|
key: ConfigKey.group_standardTags,
|
|
2258
2433
|
description: "Standard tags for the flashcard."
|
|
2259
2434
|
},
|
|
2260
2435
|
{
|
|
2436
|
+
exportJsonKey: { title: "$" },
|
|
2261
2437
|
key: ConfigKey.tag_title,
|
|
2262
2438
|
description: "Title of the flashcard."
|
|
2263
2439
|
},
|
|
2264
2440
|
{
|
|
2265
2441
|
key: ConfigKey.group_resourceIcon,
|
|
2266
2442
|
description: "Icon resource for the flashcard.",
|
|
2267
|
-
jsonKey: "answer.icon|resource(type=image, key=image)"
|
|
2443
|
+
jsonKey: "answer.icon|resource(type=image, key=image)",
|
|
2444
|
+
exportJsonKey: { answer: { icon: { type: "image", image: { src: "$" } } } }
|
|
2445
|
+
},
|
|
2446
|
+
{
|
|
2447
|
+
key: ConfigKey.property_example,
|
|
2448
|
+
exportJsonKey: [
|
|
2449
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2450
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2451
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2452
|
+
],
|
|
2453
|
+
description: "Example marker for the flashcard answer.",
|
|
2454
|
+
format: TagFormat.bitmarkText,
|
|
2455
|
+
nullable: true
|
|
2268
2456
|
}
|
|
2269
2457
|
]
|
|
2270
2458
|
},
|
|
2271
2459
|
{
|
|
2272
2460
|
jsonKey: "alternativeAnswers[].text",
|
|
2461
|
+
exportJsonKey: { alternativeAnswers: [{ text: "$" }] },
|
|
2273
2462
|
tags: [
|
|
2274
2463
|
{
|
|
2275
2464
|
key: ConfigKey.group_standardTags,
|
|
2276
2465
|
description: "Standard tags for the flashcard."
|
|
2277
2466
|
},
|
|
2278
2467
|
{
|
|
2468
|
+
exportJsonKey: { title: "$" },
|
|
2279
2469
|
key: ConfigKey.tag_title,
|
|
2280
2470
|
description: "Title of the flashcard."
|
|
2281
2471
|
},
|
|
2282
2472
|
{
|
|
2283
2473
|
key: ConfigKey.group_resourceIcon,
|
|
2284
2474
|
description: "Icon resource for the flashcard.",
|
|
2285
|
-
jsonKey: "alternativeAnswers[].icon|resource(type=image, key=image)"
|
|
2475
|
+
jsonKey: "alternativeAnswers[].icon|resource(type=image, key=image)",
|
|
2476
|
+
exportJsonKey: {
|
|
2477
|
+
alternativeAnswers: [{ icon: { type: "image", image: { src: "$" } } }]
|
|
2478
|
+
}
|
|
2286
2479
|
}
|
|
2287
2480
|
],
|
|
2288
2481
|
repeatCount: Count.infinity
|
|
@@ -2296,12 +2489,14 @@ var CARDSETS = {
|
|
|
2296
2489
|
//
|
|
2297
2490
|
[CardSetConfigKey.definitionList]: {
|
|
2298
2491
|
jsonKey: "definitions",
|
|
2492
|
+
exportJsonKey: { definitions: "$" },
|
|
2299
2493
|
sides: [
|
|
2300
2494
|
{
|
|
2301
2495
|
name: "term",
|
|
2302
2496
|
variants: [
|
|
2303
2497
|
{
|
|
2304
2498
|
jsonKey: "term.text",
|
|
2499
|
+
exportJsonKey: [{ "@absent": { term: {} } }, { term: { text: "$" } }],
|
|
2305
2500
|
tags: [
|
|
2306
2501
|
{
|
|
2307
2502
|
key: ConfigKey.group_standardTags,
|
|
@@ -2311,13 +2506,26 @@ var CARDSETS = {
|
|
|
2311
2506
|
key: ConfigKey.tag_title,
|
|
2312
2507
|
description: "Title of the definition.",
|
|
2313
2508
|
format: TagFormat.plainText,
|
|
2314
|
-
jsonKey: "^heading.forKeys"
|
|
2509
|
+
jsonKey: "^heading.forKeys",
|
|
2510
|
+
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2315
2511
|
},
|
|
2316
2512
|
{
|
|
2317
2513
|
key: ConfigKey.group_resourceIcon,
|
|
2318
2514
|
description: "Icon resource for the definition.",
|
|
2319
2515
|
format: TagFormat.plainText,
|
|
2320
|
-
jsonKey: "term.icon|resource(type=image, key=image)"
|
|
2516
|
+
jsonKey: "term.icon|resource(type=image, key=image)",
|
|
2517
|
+
exportJsonKey: { term: { icon: { type: "image", image: { src: "$" } } } }
|
|
2518
|
+
},
|
|
2519
|
+
{
|
|
2520
|
+
key: ConfigKey.property_example,
|
|
2521
|
+
exportJsonKey: [
|
|
2522
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2523
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2524
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2525
|
+
],
|
|
2526
|
+
description: "Example marker for the definition term.",
|
|
2527
|
+
format: TagFormat.bitmarkText,
|
|
2528
|
+
nullable: true
|
|
2321
2529
|
}
|
|
2322
2530
|
]
|
|
2323
2531
|
}
|
|
@@ -2328,6 +2536,7 @@ var CARDSETS = {
|
|
|
2328
2536
|
variants: [
|
|
2329
2537
|
{
|
|
2330
2538
|
jsonKey: "definition.text",
|
|
2539
|
+
exportJsonKey: [{ "@absent": { definition: {} } }, { definition: { text: "$" } }],
|
|
2331
2540
|
tags: [
|
|
2332
2541
|
{
|
|
2333
2542
|
key: ConfigKey.group_standardTags,
|
|
@@ -2337,30 +2546,48 @@ var CARDSETS = {
|
|
|
2337
2546
|
key: ConfigKey.tag_title,
|
|
2338
2547
|
description: "Title of the definition.",
|
|
2339
2548
|
format: TagFormat.plainText,
|
|
2340
|
-
jsonKey: "^heading.forValues"
|
|
2549
|
+
jsonKey: "^heading.forValues",
|
|
2550
|
+
exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
|
|
2341
2551
|
},
|
|
2342
2552
|
{
|
|
2343
2553
|
key: ConfigKey.group_resourceIcon,
|
|
2344
2554
|
description: "Icon resource for the definition.",
|
|
2345
|
-
jsonKey: "definition.icon|resource(type=image, key=image)"
|
|
2555
|
+
jsonKey: "definition.icon|resource(type=image, key=image)",
|
|
2556
|
+
exportJsonKey: { definition: { icon: { type: "image", image: { src: "$" } } } }
|
|
2557
|
+
},
|
|
2558
|
+
{
|
|
2559
|
+
key: ConfigKey.property_example,
|
|
2560
|
+
exportJsonKey: [
|
|
2561
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2562
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2563
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2564
|
+
],
|
|
2565
|
+
description: "Example marker for the definition.",
|
|
2566
|
+
format: TagFormat.bitmarkText,
|
|
2567
|
+
nullable: true
|
|
2346
2568
|
}
|
|
2347
2569
|
]
|
|
2348
2570
|
},
|
|
2349
2571
|
{
|
|
2350
2572
|
jsonKey: "alternativeDefinitions[].text",
|
|
2573
|
+
exportJsonKey: { alternativeDefinitions: [{ text: "$" }] },
|
|
2351
2574
|
tags: [
|
|
2352
2575
|
{
|
|
2353
2576
|
key: ConfigKey.group_standardTags,
|
|
2354
2577
|
description: "Standard tags for the definition."
|
|
2355
2578
|
},
|
|
2356
2579
|
{
|
|
2580
|
+
exportJsonKey: { title: "$" },
|
|
2357
2581
|
key: ConfigKey.tag_title,
|
|
2358
2582
|
description: "Title of the definition."
|
|
2359
2583
|
},
|
|
2360
2584
|
{
|
|
2361
2585
|
key: ConfigKey.group_resourceIcon,
|
|
2362
2586
|
description: "Icon resource for the definition.",
|
|
2363
|
-
jsonKey: "alternativeDefinitions[].icon|resource(type=image, key=image)"
|
|
2587
|
+
jsonKey: "alternativeDefinitions[].icon|resource(type=image, key=image)",
|
|
2588
|
+
exportJsonKey: {
|
|
2589
|
+
alternativeDefinitions: [{ icon: { type: "image", image: { src: "$" } } }]
|
|
2590
|
+
}
|
|
2364
2591
|
}
|
|
2365
2592
|
],
|
|
2366
2593
|
repeatCount: Count.infinity
|
|
@@ -2374,37 +2601,96 @@ var CARDSETS = {
|
|
|
2374
2601
|
//
|
|
2375
2602
|
[CardSetConfigKey.matchPairs]: {
|
|
2376
2603
|
jsonKey: "pairs",
|
|
2604
|
+
exportJsonKey: { pairs: "$" },
|
|
2377
2605
|
sides: [
|
|
2378
2606
|
{
|
|
2379
2607
|
name: "key",
|
|
2380
2608
|
variants: [
|
|
2381
2609
|
{
|
|
2382
2610
|
jsonKey: "key",
|
|
2611
|
+
exportJsonKey: { key: "$" },
|
|
2612
|
+
format: TextFormat2.plainText,
|
|
2383
2613
|
tags: [
|
|
2384
2614
|
{
|
|
2385
2615
|
key: ConfigKey.group_standardTags,
|
|
2386
2616
|
description: "Standard tags for the match pair."
|
|
2387
2617
|
},
|
|
2618
|
+
{
|
|
2619
|
+
// Pair-level example: emit `isExample` alongside `example`
|
|
2620
|
+
// (matches OLD parser's per-pair allow-list behaviour).
|
|
2621
|
+
//
|
|
2622
|
+
// PLAN-074: a valued cascade source (`[@example:V]` anywhere
|
|
2623
|
+
// in the cardset) fills each pair's `example` with `V`
|
|
2624
|
+
// once per pair from the keys-side cascade fire (single
|
|
2625
|
+
// parsed_variant per pair — no per-value duplication).
|
|
2626
|
+
//
|
|
2627
|
+
// PLAN-076 NOTE: matchPairs (TAG 415) KEEPS `example: '$'`
|
|
2628
|
+
// at the pair-object level. BPG `parseMatchPairs`
|
|
2629
|
+
// (`CardContentProcessor.ts:714-723`) emits ONE example
|
|
2630
|
+
// per PAIR (the `exampleCard` accumulator), placed at the
|
|
2631
|
+
// pair object. Unlike matchMatrix (per-cell example),
|
|
2632
|
+
// matchPairs has no nested per-cell layer, so the pair-key
|
|
2633
|
+
// `[@example:V]` must double-emit as the visible field.
|
|
2634
|
+
// Confirmed via `chaining` fixture: `match-solution-grouped`
|
|
2635
|
+
// expects `example: "packen"` at pair-object level from
|
|
2636
|
+
// `die Koffer[%1][@example:packen]`. Original PLAN-076
|
|
2637
|
+
// draft applied to both keys-side tags; the matchPairs
|
|
2638
|
+
// half was reverted after fixture parity testing.
|
|
2639
|
+
key: ConfigKey.property_example,
|
|
2640
|
+
exportJsonKey: [
|
|
2641
|
+
{ "@keyonly": { isExample: true, "@bit": { isExample: true } } },
|
|
2642
|
+
{
|
|
2643
|
+
predicates: ["@absent", { $cascade: "*" }],
|
|
2644
|
+
rule: {
|
|
2645
|
+
isExample: true,
|
|
2646
|
+
example: "$cascade",
|
|
2647
|
+
"@bit": { isExample: true }
|
|
2648
|
+
}
|
|
2649
|
+
},
|
|
2650
|
+
{ "@absent": { isExample: true } },
|
|
2651
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2652
|
+
],
|
|
2653
|
+
description: "Example marker / value on the match pair.",
|
|
2654
|
+
format: TagFormat.bitmarkText,
|
|
2655
|
+
nullable: true
|
|
2656
|
+
},
|
|
2388
2657
|
{
|
|
2389
2658
|
key: ConfigKey.tag_title,
|
|
2390
2659
|
description: "Title of the match pair.",
|
|
2391
2660
|
format: TagFormat.plainText,
|
|
2392
|
-
jsonKey: "^heading.forKeys"
|
|
2661
|
+
jsonKey: "^heading.forKeys",
|
|
2662
|
+
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2393
2663
|
},
|
|
2394
2664
|
{
|
|
2665
|
+
// PLAN-084: gate the key-side `@absent → $ancestor` cascade
|
|
2666
|
+
// synth with `@variantLacksTag=isCaseSensitive` so the rule
|
|
2667
|
+
// only fires when NO variant in the active card explicitly
|
|
2668
|
+
// carries `[@isCaseSensitive]`. When a value-side variant
|
|
2669
|
+
// carries the tag (e.g. `[@isCaseSensitive:false]`), the
|
|
2670
|
+
// synth is skipped here; the value-side explicit fire owns
|
|
2671
|
+
// the pair-level emission.
|
|
2395
2672
|
key: ConfigKey.property_isCaseSensitive,
|
|
2673
|
+
exportJsonKey: [
|
|
2674
|
+
{
|
|
2675
|
+
predicates: ["@absent", { "@variantLacksTag": "@isCaseSensitive" }],
|
|
2676
|
+
rule: { isCaseSensitive: "$ancestor" }
|
|
2677
|
+
},
|
|
2678
|
+
{ isCaseSensitive: "$" }
|
|
2679
|
+
],
|
|
2396
2680
|
description: "Property to indicate if the match is case sensitive.",
|
|
2397
2681
|
format: TagFormat.boolean
|
|
2398
2682
|
},
|
|
2399
2683
|
{
|
|
2400
2684
|
key: ConfigKey.resource_audio,
|
|
2401
2685
|
description: "Audio resource for the match pair.",
|
|
2402
|
-
jsonKey: "keyAudio"
|
|
2686
|
+
jsonKey: "keyAudio",
|
|
2687
|
+
exportJsonKey: { keyAudio: "$" }
|
|
2403
2688
|
},
|
|
2404
2689
|
{
|
|
2405
2690
|
key: ConfigKey.resource_image,
|
|
2406
2691
|
description: "Image resource for the match pair.",
|
|
2407
|
-
jsonKey: "keyImage"
|
|
2692
|
+
jsonKey: "keyImage",
|
|
2693
|
+
exportJsonKey: { keyImage: "$" }
|
|
2408
2694
|
}
|
|
2409
2695
|
]
|
|
2410
2696
|
}
|
|
@@ -2416,19 +2702,104 @@ var CARDSETS = {
|
|
|
2416
2702
|
variants: [
|
|
2417
2703
|
{
|
|
2418
2704
|
jsonKey: "values[]",
|
|
2705
|
+
exportJsonKey: { values: ["$"] },
|
|
2706
|
+
format: TextFormat2.plainText,
|
|
2419
2707
|
tags: [
|
|
2420
2708
|
{
|
|
2421
|
-
|
|
2422
|
-
|
|
2709
|
+
// PLAN-084: value-side excludes item/lead/pageNumber/marginNumber.
|
|
2710
|
+
// BPG `parseMatchPairs` does `delete tags.item; delete tags.lead;`
|
|
2711
|
+
// for sideIdx > 0; the schema-side equivalent is to use a
|
|
2712
|
+
// group_standardTags variant that omits group_standardItemLead.
|
|
2713
|
+
key: ConfigKey.group_standardTagsNoItemLead,
|
|
2714
|
+
description: "Standard tags for the match pair (values side, no item/lead)."
|
|
2715
|
+
},
|
|
2716
|
+
{
|
|
2717
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.6: cascade-fired
|
|
2718
|
+
// `@example` from the bit header fills each pair's
|
|
2719
|
+
// `example` with the pair's first value (mirrors BPG's
|
|
2720
|
+
// `fillStringExample(pairs, __defaultExample=values[0])`).
|
|
2721
|
+
//
|
|
2722
|
+
// PLAN-074: the cascade-source-VALUE branch is handled by
|
|
2723
|
+
// TAG 415 (keys side) which fires once per pair — keeping
|
|
2724
|
+
// it here would emit `example` twice per pair (one per
|
|
2725
|
+
// values-side parsed_variant) and merge them into a
|
|
2726
|
+
// multi-paragraph array.
|
|
2727
|
+
//
|
|
2728
|
+
// PLAN-075: bare `$parent` reads the parent variant fire's
|
|
2729
|
+
// source `$` value (the current `++`-iteration's value
|
|
2730
|
+
// text). For single-value pairs this matches the old
|
|
2731
|
+
// `$parent.values[0]`; for multi-value pairs with
|
|
2732
|
+
// `[@example]` attached to a non-first value, it correctly
|
|
2733
|
+
// resolves to that value.
|
|
2734
|
+
//
|
|
2735
|
+
// PLAN-077: dual `[@absent, { '$cascade': '*' }]` rule
|
|
2736
|
+
// routes pair-key `[@example:V]` (a per-pair cascade
|
|
2737
|
+
// source, bound via per-card CascadeCounters scope) and
|
|
2738
|
+
// bit-header `[@example:V]` (cardset cascade) into the
|
|
2739
|
+
// pair-level `example` via `$cascade`. The aggregator in
|
|
2740
|
+
// `populate_variants` fires this rule ONCE per pair (BPG
|
|
2741
|
+
// `parseMatchPairs` `exampleCard` precedence), avoiding
|
|
2742
|
+
// per-iter pollution.
|
|
2743
|
+
key: ConfigKey.property_example,
|
|
2744
|
+
exportJsonKey: [
|
|
2745
|
+
// PLAN-084: bare `[@example]` on a values-side variant fires
|
|
2746
|
+
// once per pair (first-wins, mirrors BPG `parseMatchPairs`
|
|
2747
|
+
// `exampleCard` + `pushDownTree` set-if-null semantic).
|
|
2748
|
+
// `maxEmits: 1` enforced inside the per-pair cascade-counter
|
|
2749
|
+
// scope opened by `build_card_item`.
|
|
2750
|
+
{
|
|
2751
|
+
predicates: ["@keyonly"],
|
|
2752
|
+
maxEmits: 1,
|
|
2753
|
+
rule: {
|
|
2754
|
+
isExample: true,
|
|
2755
|
+
example: "$parent",
|
|
2756
|
+
"@bit": { isExample: true }
|
|
2757
|
+
}
|
|
2758
|
+
},
|
|
2759
|
+
{
|
|
2760
|
+
predicates: ["@absent", { $cascade: "*" }],
|
|
2761
|
+
rule: {
|
|
2762
|
+
isExample: true,
|
|
2763
|
+
example: "$cascade",
|
|
2764
|
+
"@bit": { isExample: true }
|
|
2765
|
+
}
|
|
2766
|
+
},
|
|
2767
|
+
{
|
|
2768
|
+
"@absent": {
|
|
2769
|
+
isExample: true,
|
|
2770
|
+
example: "$parent",
|
|
2771
|
+
"@bit": { isExample: true }
|
|
2772
|
+
}
|
|
2773
|
+
},
|
|
2774
|
+
// PLAN-084: same cap applies to the explicit-value `[@example:V]`
|
|
2775
|
+
// form so per-`++`-iter values-side fires also first-win.
|
|
2776
|
+
{
|
|
2777
|
+
predicates: [],
|
|
2778
|
+
maxEmits: 1,
|
|
2779
|
+
rule: { isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2780
|
+
}
|
|
2781
|
+
],
|
|
2782
|
+
description: "Example marker / value on the match pair (values side).",
|
|
2783
|
+
format: TagFormat.bitmarkText,
|
|
2784
|
+
nullable: true
|
|
2423
2785
|
},
|
|
2424
2786
|
{
|
|
2425
2787
|
key: ConfigKey.tag_title,
|
|
2426
2788
|
description: "Title of the match pair.",
|
|
2427
2789
|
format: TagFormat.plainText,
|
|
2428
|
-
jsonKey: "^heading.forValues"
|
|
2790
|
+
jsonKey: "^heading.forValues",
|
|
2791
|
+
exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
|
|
2429
2792
|
},
|
|
2430
2793
|
{
|
|
2794
|
+
// PLAN-084: symmetric @variantLacksTag gating with the key-side.
|
|
2431
2795
|
key: ConfigKey.property_isCaseSensitive,
|
|
2796
|
+
exportJsonKey: [
|
|
2797
|
+
{
|
|
2798
|
+
predicates: ["@absent", { "@variantLacksTag": "@isCaseSensitive" }],
|
|
2799
|
+
rule: { isCaseSensitive: "$ancestor" }
|
|
2800
|
+
},
|
|
2801
|
+
{ isCaseSensitive: "$" }
|
|
2802
|
+
],
|
|
2432
2803
|
description: "Property to indicate if the match is case sensitive.",
|
|
2433
2804
|
format: TagFormat.boolean
|
|
2434
2805
|
}
|
|
@@ -2444,12 +2815,15 @@ var CARDSETS = {
|
|
|
2444
2815
|
//
|
|
2445
2816
|
[CardSetConfigKey.matchAudioPairs]: {
|
|
2446
2817
|
jsonKey: "pairs",
|
|
2818
|
+
exportJsonKey: { pairs: "$" },
|
|
2447
2819
|
sides: [
|
|
2448
2820
|
{
|
|
2449
2821
|
name: "key",
|
|
2450
2822
|
variants: [
|
|
2451
2823
|
{
|
|
2452
2824
|
jsonKey: "key",
|
|
2825
|
+
exportJsonKey: { key: "$" },
|
|
2826
|
+
format: TextFormat2.plainText,
|
|
2453
2827
|
tags: [
|
|
2454
2828
|
{
|
|
2455
2829
|
key: ConfigKey.group_standardTags,
|
|
@@ -2459,12 +2833,14 @@ var CARDSETS = {
|
|
|
2459
2833
|
key: ConfigKey.tag_title,
|
|
2460
2834
|
description: "Title of the audio match pair.",
|
|
2461
2835
|
format: TagFormat.plainText,
|
|
2462
|
-
jsonKey: "^heading.forKeys"
|
|
2836
|
+
jsonKey: "^heading.forKeys",
|
|
2837
|
+
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2463
2838
|
},
|
|
2464
2839
|
{
|
|
2465
2840
|
key: ConfigKey.resource_audio,
|
|
2466
2841
|
description: "Audio resource for the match pair.",
|
|
2467
|
-
jsonKey: "keyAudio"
|
|
2842
|
+
jsonKey: "keyAudio",
|
|
2843
|
+
exportJsonKey: { keyAudio: "$" }
|
|
2468
2844
|
}
|
|
2469
2845
|
]
|
|
2470
2846
|
}
|
|
@@ -2476,16 +2852,20 @@ var CARDSETS = {
|
|
|
2476
2852
|
variants: [
|
|
2477
2853
|
{
|
|
2478
2854
|
jsonKey: "values[]",
|
|
2855
|
+
exportJsonKey: { values: ["$"] },
|
|
2856
|
+
format: TextFormat2.plainText,
|
|
2479
2857
|
tags: [
|
|
2480
2858
|
{
|
|
2481
|
-
|
|
2482
|
-
|
|
2859
|
+
// PLAN-084: value-side excludes item/lead/pageNumber/marginNumber.
|
|
2860
|
+
key: ConfigKey.group_standardTagsNoItemLead,
|
|
2861
|
+
description: "Standard tags for the audio match pair (values side, no item/lead)."
|
|
2483
2862
|
},
|
|
2484
2863
|
{
|
|
2485
2864
|
key: ConfigKey.tag_title,
|
|
2486
2865
|
description: "Title of the audio match pair.",
|
|
2487
2866
|
format: TagFormat.plainText,
|
|
2488
|
-
jsonKey: "^heading.forValues"
|
|
2867
|
+
jsonKey: "^heading.forValues",
|
|
2868
|
+
exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
|
|
2489
2869
|
},
|
|
2490
2870
|
{
|
|
2491
2871
|
key: ConfigKey.resource_audio,
|
|
@@ -2503,12 +2883,15 @@ var CARDSETS = {
|
|
|
2503
2883
|
//
|
|
2504
2884
|
[CardSetConfigKey.matchImagePairs]: {
|
|
2505
2885
|
jsonKey: "pairs",
|
|
2886
|
+
exportJsonKey: { pairs: "$" },
|
|
2506
2887
|
sides: [
|
|
2507
2888
|
{
|
|
2508
2889
|
name: "key",
|
|
2509
2890
|
variants: [
|
|
2510
2891
|
{
|
|
2511
2892
|
jsonKey: "key",
|
|
2893
|
+
exportJsonKey: { key: "$" },
|
|
2894
|
+
format: TextFormat2.plainText,
|
|
2512
2895
|
tags: [
|
|
2513
2896
|
{
|
|
2514
2897
|
key: ConfigKey.group_standardTags,
|
|
@@ -2518,12 +2901,14 @@ var CARDSETS = {
|
|
|
2518
2901
|
key: ConfigKey.tag_title,
|
|
2519
2902
|
description: "Title of the image match pair.",
|
|
2520
2903
|
format: TagFormat.plainText,
|
|
2521
|
-
jsonKey: "^heading.forKeys"
|
|
2904
|
+
jsonKey: "^heading.forKeys",
|
|
2905
|
+
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2522
2906
|
},
|
|
2523
2907
|
{
|
|
2524
2908
|
key: ConfigKey.resource_image,
|
|
2525
2909
|
description: "Image resource for the match pair.",
|
|
2526
|
-
jsonKey: "keyImage"
|
|
2910
|
+
jsonKey: "keyImage",
|
|
2911
|
+
exportJsonKey: { keyImage: "$" }
|
|
2527
2912
|
}
|
|
2528
2913
|
]
|
|
2529
2914
|
}
|
|
@@ -2535,16 +2920,20 @@ var CARDSETS = {
|
|
|
2535
2920
|
variants: [
|
|
2536
2921
|
{
|
|
2537
2922
|
jsonKey: "values[]",
|
|
2923
|
+
exportJsonKey: { values: ["$"] },
|
|
2924
|
+
format: TextFormat2.plainText,
|
|
2538
2925
|
tags: [
|
|
2539
2926
|
{
|
|
2540
|
-
|
|
2541
|
-
|
|
2927
|
+
// PLAN-084: value-side excludes item/lead/pageNumber/marginNumber.
|
|
2928
|
+
key: ConfigKey.group_standardTagsNoItemLead,
|
|
2929
|
+
description: "Standard tags for the image match pair (values side, no item/lead)."
|
|
2542
2930
|
},
|
|
2543
2931
|
{
|
|
2544
2932
|
key: ConfigKey.tag_title,
|
|
2545
2933
|
description: "Title of the image match pair.",
|
|
2546
2934
|
format: TagFormat.plainText,
|
|
2547
|
-
jsonKey: "^heading.forValues"
|
|
2935
|
+
jsonKey: "^heading.forValues",
|
|
2936
|
+
exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
|
|
2548
2937
|
},
|
|
2549
2938
|
{
|
|
2550
2939
|
key: ConfigKey.resource_image,
|
|
@@ -2562,30 +2951,71 @@ var CARDSETS = {
|
|
|
2562
2951
|
//
|
|
2563
2952
|
[CardSetConfigKey.matchMatrix]: {
|
|
2564
2953
|
jsonKey: "matrix",
|
|
2954
|
+
exportJsonKey: { matrix: "$" },
|
|
2565
2955
|
sides: [
|
|
2566
2956
|
{
|
|
2567
2957
|
name: "key",
|
|
2568
2958
|
variants: [
|
|
2569
2959
|
{
|
|
2570
2960
|
jsonKey: "key",
|
|
2961
|
+
exportJsonKey: { key: "$" },
|
|
2962
|
+
format: TextFormat2.plainText,
|
|
2571
2963
|
tags: [
|
|
2572
2964
|
{
|
|
2573
2965
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2574
2966
|
description: "Standard tags for lead, instruction, and hint."
|
|
2575
2967
|
},
|
|
2576
2968
|
{
|
|
2969
|
+
// PLAN-076: drop `example: '$'` from valued rule — pair-key
|
|
2970
|
+
// `[@example:V]` is consumed as the per-pair cascade source.
|
|
2971
|
+
// PLAN-077 R14 follow-up: investigation showed the fixture
|
|
2972
|
+
// reference is INCONSISTENT — bits without a cardset-level
|
|
2973
|
+
// cascade (e.g. bit 3 `[@example:Y]should be...`) expect
|
|
2974
|
+
// pair-level `example: V` at pair scope, but bits WITH a
|
|
2975
|
+
// cardset cascade (e.g. bit 8 `[@example:99]` in title-row
|
|
2976
|
+
// PLUS pair-key `[@example:Y]`) expect NO pair-level
|
|
2977
|
+
// example. Emitting `example: $` here satisfies bit 3 but
|
|
2978
|
+
// breaks bit 8; dropping it satisfies bit 8 but breaks bit
|
|
2979
|
+
// 3. Conditional emission would require runtime gating on
|
|
2980
|
+
// the cardset cascade scope state. Left dropped pending a
|
|
2981
|
+
// dedicated plan — accepted divergence on bit 3's pair-
|
|
2982
|
+
// level emission (cells still get the per-cell `example`
|
|
2983
|
+
// correctly via PLAN-077 §4.2 + §4.3).
|
|
2577
2984
|
key: ConfigKey.property_example,
|
|
2985
|
+
exportJsonKey: [
|
|
2986
|
+
{
|
|
2987
|
+
"@keyonly": {
|
|
2988
|
+
isExample: true,
|
|
2989
|
+
"@bit": { isExample: true },
|
|
2990
|
+
"@card": { isExample: true }
|
|
2991
|
+
}
|
|
2992
|
+
},
|
|
2993
|
+
{
|
|
2994
|
+
"@absent": {
|
|
2995
|
+
isExample: true,
|
|
2996
|
+
"@bit": { isExample: true },
|
|
2997
|
+
"@card": { isExample: true }
|
|
2998
|
+
}
|
|
2999
|
+
},
|
|
3000
|
+
{ isExample: true, "@bit": { isExample: true }, "@card": { isExample: true } }
|
|
3001
|
+
],
|
|
2578
3002
|
description: "Example text for the match matrix.",
|
|
2579
|
-
format: TagFormat.plainText
|
|
3003
|
+
format: TagFormat.plainText,
|
|
3004
|
+
nullable: true
|
|
2580
3005
|
},
|
|
2581
3006
|
{
|
|
2582
3007
|
key: ConfigKey.tag_title,
|
|
2583
3008
|
description: "Title of the match matrix.",
|
|
2584
3009
|
format: TagFormat.plainText,
|
|
2585
|
-
jsonKey: "^heading.forKeys"
|
|
3010
|
+
jsonKey: "^heading.forKeys",
|
|
3011
|
+
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2586
3012
|
},
|
|
2587
3013
|
{
|
|
2588
3014
|
key: ConfigKey.property_isCaseSensitive,
|
|
3015
|
+
exportJsonKey: [
|
|
3016
|
+
{ "@absent": { isCaseSensitive: "$ancestor" } },
|
|
3017
|
+
{ isCaseSensitive: "$" }
|
|
3018
|
+
],
|
|
2589
3019
|
description: "Property to indicate if the match is case sensitive.",
|
|
2590
3020
|
format: TagFormat.boolean
|
|
2591
3021
|
}
|
|
@@ -2599,24 +3029,103 @@ var CARDSETS = {
|
|
|
2599
3029
|
variants: [
|
|
2600
3030
|
{
|
|
2601
3031
|
jsonKey: "cells[{s}].values[]",
|
|
3032
|
+
exportJsonKey: [
|
|
3033
|
+
// PLAN-085 / R14: the positional-blank emission for an
|
|
3034
|
+
// effectively-absent cell side fires ONLY when the active
|
|
3035
|
+
// card has at least one `[#]` variant fire. This matches
|
|
3036
|
+
// BPG `extractHeadingCard`'s `isHeading` gate: when no
|
|
3037
|
+
// `[#]` exists anywhere in the title card, BPG returns
|
|
3038
|
+
// undefined and no `heading` is emitted. The phantom
|
|
3039
|
+
// `forValues:['']` placeholder is appropriate only when
|
|
3040
|
+
// the card is being treated as a title-row.
|
|
3041
|
+
{
|
|
3042
|
+
predicates: ["@absent", { "@variantHasTag": "#" }],
|
|
3043
|
+
rule: { "@bit": { heading: { forValues: [""] } } }
|
|
3044
|
+
},
|
|
3045
|
+
{ cells: { $s: { values: ["$"] } } }
|
|
3046
|
+
],
|
|
3047
|
+
format: TextFormat2.plainText,
|
|
2602
3048
|
tags: [
|
|
2603
3049
|
{
|
|
2604
3050
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2605
3051
|
description: "Standard tags for lead, instruction, and hint."
|
|
2606
3052
|
},
|
|
2607
3053
|
{
|
|
3054
|
+
// PLAN-075: bare `$parent` reads the parent variant fire's
|
|
3055
|
+
// source `$` value (the current `++`-iteration's cell text).
|
|
3056
|
+
// Replaces `$parent.values[0]` which pinned to position 0
|
|
3057
|
+
// regardless of which `++`-value `[@example]` was on.
|
|
3058
|
+
//
|
|
3059
|
+
// PLAN-077: dual `[@absent, { '$cascade': '*' }]` rule
|
|
3060
|
+
// routes pair-key `[@example:V]` (a per-pair cascade
|
|
3061
|
+
// source, bound via per-card CascadeCounters scope) and
|
|
3062
|
+
// bit-header `[@example:V]` (cardset cascade) into the
|
|
3063
|
+
// per-cell `example` via `$cascade`. The aggregator in
|
|
3064
|
+
// `populate_variants` fires this rule ONCE per cell (BPG
|
|
3065
|
+
// `parseMatchMatrix` `exampleSide` precedence), avoiding
|
|
3066
|
+
// per-iter pollution.
|
|
3067
|
+
// @card scope-shift writes matrix-row container isExample.
|
|
2608
3068
|
key: ConfigKey.property_example,
|
|
3069
|
+
exportJsonKey: [
|
|
3070
|
+
{
|
|
3071
|
+
"@keyonly": {
|
|
3072
|
+
cells: { $s: { isExample: true, example: "$parent" } },
|
|
3073
|
+
"@bit": { isExample: true },
|
|
3074
|
+
"@card": { isExample: true }
|
|
3075
|
+
}
|
|
3076
|
+
},
|
|
3077
|
+
{
|
|
3078
|
+
predicates: ["@absent", { $cascade: "*" }],
|
|
3079
|
+
rule: {
|
|
3080
|
+
cells: { $s: { isExample: true, example: "$cascade" } },
|
|
3081
|
+
"@bit": { isExample: true },
|
|
3082
|
+
"@card": { isExample: true }
|
|
3083
|
+
}
|
|
3084
|
+
},
|
|
3085
|
+
{
|
|
3086
|
+
"@absent": {
|
|
3087
|
+
cells: { $s: { isExample: true, example: "$parent" } },
|
|
3088
|
+
"@bit": { isExample: true },
|
|
3089
|
+
"@card": { isExample: true }
|
|
3090
|
+
}
|
|
3091
|
+
},
|
|
3092
|
+
{
|
|
3093
|
+
cells: { $s: { isExample: true, example: "$" } },
|
|
3094
|
+
"@bit": { isExample: true },
|
|
3095
|
+
"@card": { isExample: true }
|
|
3096
|
+
}
|
|
3097
|
+
],
|
|
2609
3098
|
description: "Example text for the match matrix.",
|
|
2610
|
-
format: TagFormat.
|
|
3099
|
+
format: TagFormat.bitmarkText,
|
|
3100
|
+
nullable: true
|
|
2611
3101
|
},
|
|
2612
3102
|
{
|
|
3103
|
+
// PLAN-085 / R14: bare `[#]` on a value-side emits the
|
|
3104
|
+
// empty-string positional blank into `forValues` so the
|
|
3105
|
+
// array stays aligned with the cell positions (matches BPG
|
|
3106
|
+
// `extractHeadingCard`'s "all value-side headings present"
|
|
3107
|
+
// shape). The `@keyonly` rule is required for two reasons:
|
|
3108
|
+
// 1) it provides an emission for bare `[#]` (the `$` sigil
|
|
3109
|
+
// in the unconditional rule has no source for bare); and
|
|
3110
|
+
// 2) the presence of any `@keyonly` rule disables the
|
|
3111
|
+
// optimised-mode `should_suppress_outcome` strip (see
|
|
3112
|
+
// `forward_emit.rs`) so the resulting `forValues: [""]`
|
|
3113
|
+
// survives the all-natural-defaults check.
|
|
2613
3114
|
key: ConfigKey.tag_title,
|
|
2614
3115
|
description: "Title of the match matrix.",
|
|
2615
3116
|
format: TagFormat.plainText,
|
|
2616
|
-
jsonKey: "^heading.forValues"
|
|
3117
|
+
jsonKey: "^heading.forValues",
|
|
3118
|
+
exportJsonKey: [
|
|
3119
|
+
{ "@keyonly": { "@bit": { heading: { forValues: [""] } } } },
|
|
3120
|
+
{ "@bit": { heading: { forValues: ["$"] } } }
|
|
3121
|
+
]
|
|
2617
3122
|
},
|
|
2618
3123
|
{
|
|
2619
3124
|
key: ConfigKey.property_isCaseSensitive,
|
|
3125
|
+
exportJsonKey: [
|
|
3126
|
+
{ "@absent": { isCaseSensitive: "$ancestor" } },
|
|
3127
|
+
{ isCaseSensitive: "$" }
|
|
3128
|
+
],
|
|
2620
3129
|
description: "Property to indicate if the match is case sensitive.",
|
|
2621
3130
|
format: TagFormat.boolean
|
|
2622
3131
|
}
|
|
@@ -2632,28 +3141,61 @@ var CARDSETS = {
|
|
|
2632
3141
|
//
|
|
2633
3142
|
[CardSetConfigKey.statements]: {
|
|
2634
3143
|
jsonKey: "statements",
|
|
3144
|
+
exportJsonKey: { statements: "$" },
|
|
2635
3145
|
sides: [
|
|
2636
3146
|
{
|
|
2637
3147
|
name: "statement",
|
|
2638
3148
|
variants: [
|
|
2639
3149
|
{
|
|
2640
3150
|
jsonKey: "statement",
|
|
3151
|
+
exportJsonKey: { statement: "$" },
|
|
2641
3152
|
tags: [
|
|
2642
3153
|
{
|
|
2643
3154
|
key: ConfigKey.tag_true,
|
|
2644
3155
|
description: "Tag for true statements.",
|
|
2645
3156
|
jsonKey: "statement|set(isCorrect=true)",
|
|
3157
|
+
exportJsonKey: { statement: "$", isCorrect: true },
|
|
2646
3158
|
maxCount: 1
|
|
2647
3159
|
},
|
|
2648
3160
|
{
|
|
2649
3161
|
key: ConfigKey.tag_false,
|
|
2650
3162
|
description: "Tag for false statements.",
|
|
2651
3163
|
jsonKey: "statement|set(isCorrect=false)",
|
|
3164
|
+
exportJsonKey: { statement: "$", isCorrect: false },
|
|
2652
3165
|
maxCount: 1
|
|
2653
3166
|
},
|
|
2654
3167
|
{
|
|
2655
3168
|
key: ConfigKey.group_standardTags,
|
|
2656
3169
|
description: "Standard tags for the statement."
|
|
3170
|
+
},
|
|
3171
|
+
{
|
|
3172
|
+
// PLAN-072: cascade-fired `@example` from the bit header
|
|
3173
|
+
// fills each statement entry's `example` with the entry's
|
|
3174
|
+
// own `isCorrect`, mirroring BPG's `pushExampleDownTree`
|
|
3175
|
+
// for the statements cardset. Per-array-item strip removes
|
|
3176
|
+
// `example: false` from incorrect entries so only correct
|
|
3177
|
+
// entries retain `example: true`.
|
|
3178
|
+
key: ConfigKey.property_example,
|
|
3179
|
+
exportJsonKey: [
|
|
3180
|
+
{
|
|
3181
|
+
"@keyonly": {
|
|
3182
|
+
isExample: true,
|
|
3183
|
+
example: true,
|
|
3184
|
+
"@bit": { isExample: true }
|
|
3185
|
+
}
|
|
3186
|
+
},
|
|
3187
|
+
{
|
|
3188
|
+
"@absent": {
|
|
3189
|
+
isExample: true,
|
|
3190
|
+
example: "$parent.isCorrect",
|
|
3191
|
+
"@bit": { isExample: true }
|
|
3192
|
+
}
|
|
3193
|
+
},
|
|
3194
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3195
|
+
],
|
|
3196
|
+
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`.",
|
|
3197
|
+
format: TagFormat.boolean,
|
|
3198
|
+
nullable: true
|
|
2657
3199
|
}
|
|
2658
3200
|
],
|
|
2659
3201
|
bodyAllowed: false
|
|
@@ -2667,6 +3209,7 @@ var CARDSETS = {
|
|
|
2667
3209
|
//
|
|
2668
3210
|
[CardSetConfigKey.quiz]: {
|
|
2669
3211
|
jsonKey: "quizzes",
|
|
3212
|
+
exportJsonKey: { quizzes: "$" },
|
|
2670
3213
|
sides: [
|
|
2671
3214
|
{
|
|
2672
3215
|
name: "choices",
|
|
@@ -2681,6 +3224,71 @@ var CARDSETS = {
|
|
|
2681
3224
|
{
|
|
2682
3225
|
key: ConfigKey.group_standardTags,
|
|
2683
3226
|
description: "Standard tags for the quiz."
|
|
3227
|
+
},
|
|
3228
|
+
{
|
|
3229
|
+
// ALIGN-EXAMPLE-CASCADE §3.2: variant-level cascade for
|
|
3230
|
+
// quiz choices is delegated to group_trueFalse's
|
|
3231
|
+
// chain-child `@example` (`+` chain with maxEmits:1 +
|
|
3232
|
+
// `@parent.isCorrect=true`). Variant-level `@absent`
|
|
3233
|
+
// would over-fire on subsequent correct choices and on
|
|
3234
|
+
// incorrect ones — drop it.
|
|
3235
|
+
key: ConfigKey.property_example,
|
|
3236
|
+
exportJsonKey: [
|
|
3237
|
+
{ "@keyonly": { isExample: true, "@bit": { isExample: true } } },
|
|
3238
|
+
{ isExample: true, "@bit": { isExample: true } }
|
|
3239
|
+
],
|
|
3240
|
+
description: "Example marker on the quiz choice (entry-local only; cascade handled by group_trueFalse chain-children).",
|
|
3241
|
+
format: TagFormat.boolean,
|
|
3242
|
+
nullable: true
|
|
3243
|
+
}
|
|
3244
|
+
],
|
|
3245
|
+
bodyAllowed: false
|
|
3246
|
+
}
|
|
3247
|
+
]
|
|
3248
|
+
}
|
|
3249
|
+
]
|
|
3250
|
+
},
|
|
3251
|
+
//
|
|
3252
|
+
// quiz (responses)
|
|
3253
|
+
//
|
|
3254
|
+
[CardSetConfigKey.quizResponses]: {
|
|
3255
|
+
jsonKey: "quizzes",
|
|
3256
|
+
exportJsonKey: { quizzes: "$" },
|
|
3257
|
+
sides: [
|
|
3258
|
+
{
|
|
3259
|
+
name: "responses",
|
|
3260
|
+
variants: [
|
|
3261
|
+
{
|
|
3262
|
+
jsonKey: null,
|
|
3263
|
+
tags: [
|
|
3264
|
+
{
|
|
3265
|
+
key: ConfigKey.group_trueFalseResponses,
|
|
3266
|
+
description: "Group for true/false questions."
|
|
3267
|
+
},
|
|
3268
|
+
{
|
|
3269
|
+
key: ConfigKey.group_standardTags,
|
|
3270
|
+
description: "Standard tags for the quiz."
|
|
3271
|
+
},
|
|
3272
|
+
{
|
|
3273
|
+
// PLAN-072: cascade-fired `@example` from the bit header
|
|
3274
|
+
// fills each response entry's `example` with the entry's
|
|
3275
|
+
// own `isCorrect`, mirroring BPG's `pushExampleDownTree`
|
|
3276
|
+
// for the quiz-responses cardset (statements-style).
|
|
3277
|
+
key: ConfigKey.property_example,
|
|
3278
|
+
exportJsonKey: [
|
|
3279
|
+
{ "@keyonly": { isExample: true, "@bit": { isExample: true } } },
|
|
3280
|
+
{
|
|
3281
|
+
"@absent": {
|
|
3282
|
+
isExample: true,
|
|
3283
|
+
example: "$parent.isCorrect",
|
|
3284
|
+
"@bit": { isExample: true }
|
|
3285
|
+
}
|
|
3286
|
+
},
|
|
3287
|
+
{ isExample: true, "@bit": { isExample: true } }
|
|
3288
|
+
],
|
|
3289
|
+
description: "Example marker on the quiz response; cascade from bit-header fills `example` with the entry\u2019s own `isCorrect`.",
|
|
3290
|
+
format: TagFormat.boolean,
|
|
3291
|
+
nullable: true
|
|
2684
3292
|
}
|
|
2685
3293
|
],
|
|
2686
3294
|
bodyAllowed: false
|
|
@@ -2694,6 +3302,7 @@ var CARDSETS = {
|
|
|
2694
3302
|
//
|
|
2695
3303
|
[CardSetConfigKey.feedback]: {
|
|
2696
3304
|
jsonKey: "feedbacks",
|
|
3305
|
+
exportJsonKey: { feedbacks: "$" },
|
|
2697
3306
|
sides: [
|
|
2698
3307
|
{
|
|
2699
3308
|
name: "choices",
|
|
@@ -2705,6 +3314,73 @@ var CARDSETS = {
|
|
|
2705
3314
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2706
3315
|
description: "Standard tags for lead, instruction, and hint."
|
|
2707
3316
|
},
|
|
3317
|
+
{
|
|
3318
|
+
// Feedback choices: `[+]` / `[-]` map to choice + `requireReason`
|
|
3319
|
+
// (NOT `isCorrect` like trueFalse). Shadow the inherited
|
|
3320
|
+
// `tag_true` / `tag_false` from `group_trueFalse` to emit the
|
|
3321
|
+
// feedback-specific shape.
|
|
3322
|
+
//
|
|
3323
|
+
// Chain @example: `[+ X][@example]` writes
|
|
3324
|
+
// `isExample/example` onto the X choice only. BPG's
|
|
3325
|
+
// `setIsExampleFlags` (Builder.ts:4041-4172) does NOT
|
|
3326
|
+
// iterate `cardNode.feedbacks` — so unlike multipleChoice,
|
|
3327
|
+
// there is no bubble to bit-level or feedbacks-level
|
|
3328
|
+
// isExample. Pattern omits `@bit` scope-shift accordingly.
|
|
3329
|
+
// No `@absent`/`@parent.isCorrect` cascade rules either:
|
|
3330
|
+
// BPG's `pushExampleDownTree` (Builder.ts:3777-3849) has
|
|
3331
|
+
// no feedback dispatch, so bit-header `[@example]` does
|
|
3332
|
+
// not flow into feedback choices.
|
|
3333
|
+
key: ConfigKey.tag_true,
|
|
3334
|
+
exportJsonKey: { choices: [{ choice: "$", requireReason: true }] },
|
|
3335
|
+
description: "Reason-required choice for feedback (`[+]`).",
|
|
3336
|
+
maxCount: Count.infinity,
|
|
3337
|
+
format: TagFormat.plainText,
|
|
3338
|
+
chain: [
|
|
3339
|
+
{
|
|
3340
|
+
key: ConfigKey.property_example,
|
|
3341
|
+
exportJsonKey: [
|
|
3342
|
+
{ "@keyonly": { isExample: true, example: true } },
|
|
3343
|
+
{ isExample: true, example: "$" }
|
|
3344
|
+
],
|
|
3345
|
+
description: "Per-choice example marker for feedback `[+]`.",
|
|
3346
|
+
format: TagFormat.boolean,
|
|
3347
|
+
maxCount: 1,
|
|
3348
|
+
nullable: true
|
|
3349
|
+
},
|
|
3350
|
+
{
|
|
3351
|
+
// `[+ X][! foo]` chains `!` (instruction) onto the
|
|
3352
|
+
// choice; same for `[?]` (hint), `[%]` (item),
|
|
3353
|
+
// `[%2]`/`[%3]`/`[%4]` (lead/pageNumber/marginNumber).
|
|
3354
|
+
// Mirrors group_trueFalse's `+` chain shape.
|
|
3355
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3356
|
+
description: "Item, lead, page number, margin number, instruction and hint chained onto the feedback choice."
|
|
3357
|
+
}
|
|
3358
|
+
]
|
|
3359
|
+
},
|
|
3360
|
+
{
|
|
3361
|
+
key: ConfigKey.tag_false,
|
|
3362
|
+
exportJsonKey: { choices: [{ choice: "$", requireReason: false }] },
|
|
3363
|
+
description: "Reason-not-required choice for feedback (`[-]`).",
|
|
3364
|
+
maxCount: Count.infinity,
|
|
3365
|
+
format: TagFormat.plainText,
|
|
3366
|
+
chain: [
|
|
3367
|
+
{
|
|
3368
|
+
key: ConfigKey.property_example,
|
|
3369
|
+
exportJsonKey: [
|
|
3370
|
+
{ "@keyonly": { isExample: true, example: true } },
|
|
3371
|
+
{ isExample: true, example: "$" }
|
|
3372
|
+
],
|
|
3373
|
+
description: "Per-choice example marker for feedback `[-]`.",
|
|
3374
|
+
format: TagFormat.boolean,
|
|
3375
|
+
maxCount: 1,
|
|
3376
|
+
nullable: true
|
|
3377
|
+
},
|
|
3378
|
+
{
|
|
3379
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3380
|
+
description: "Item, lead, page number, margin number, instruction and hint chained onto the feedback choice."
|
|
3381
|
+
}
|
|
3382
|
+
]
|
|
3383
|
+
},
|
|
2708
3384
|
{
|
|
2709
3385
|
key: ConfigKey.group_trueFalse,
|
|
2710
3386
|
description: "Group for true/false feedback."
|
|
@@ -2713,7 +3389,8 @@ var CARDSETS = {
|
|
|
2713
3389
|
key: ConfigKey.tag_title,
|
|
2714
3390
|
description: "Title of the feedback.",
|
|
2715
3391
|
format: TagFormat.plainText,
|
|
2716
|
-
jsonKey: "^heading.forKeys"
|
|
3392
|
+
jsonKey: "^heading.forKeys",
|
|
3393
|
+
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2717
3394
|
}
|
|
2718
3395
|
],
|
|
2719
3396
|
bodyAllowed: false
|
|
@@ -2724,27 +3401,78 @@ var CARDSETS = {
|
|
|
2724
3401
|
name: "reason",
|
|
2725
3402
|
variants: [
|
|
2726
3403
|
{
|
|
3404
|
+
// PLAN: feedback.reason — Object-only variant pattern. Per
|
|
3405
|
+
// SYNTAX.md §8.1, sibling tag emissions do NOT auto-wrap
|
|
3406
|
+
// under `reason.*`; each tag here spells out the full path.
|
|
3407
|
+
// Body is a plain string (BPG `parseFeedback` uses
|
|
3408
|
+
// `cardBodyStr ?? ''` for `reason.text`).
|
|
2727
3409
|
jsonKey: "reason.text",
|
|
3410
|
+
exportJsonKey: { reason: { text: "$" } },
|
|
3411
|
+
format: TextFormat2.plainText,
|
|
2728
3412
|
tags: [
|
|
2729
3413
|
{
|
|
2730
|
-
|
|
2731
|
-
|
|
3414
|
+
// Instruction lands under reason. Hint/item/lead/etc.
|
|
3415
|
+
// omitted: not exercised by any fixture and BPG's
|
|
3416
|
+
// `parseFeedback` spreads only the tags actually present
|
|
3417
|
+
// — adding the rest can be done lazily as fixtures
|
|
3418
|
+
// require them, with the same `{reason: {…}}` wrapper.
|
|
3419
|
+
key: ConfigKey.tag_instruction,
|
|
3420
|
+
exportJsonKey: { reason: { instruction: "$" } },
|
|
3421
|
+
description: "Instruction for the feedback reason.",
|
|
3422
|
+
format: TagFormat.bitmarkText
|
|
2732
3423
|
},
|
|
2733
3424
|
{
|
|
2734
3425
|
key: ConfigKey.property_reasonableNumOfChars,
|
|
3426
|
+
exportJsonKey: [
|
|
3427
|
+
{ "@absent": { reason: { reasonableNumOfChars: "$ancestor" } } },
|
|
3428
|
+
{ reason: { reasonableNumOfChars: "$" } }
|
|
3429
|
+
],
|
|
2735
3430
|
description: "Property for reasonable number of characters.",
|
|
2736
3431
|
format: TagFormat.number
|
|
2737
3432
|
},
|
|
2738
3433
|
{
|
|
3434
|
+
// ALIGN-EXAMPLE-CASCADE §3.9: `feedback.reason` is NOT in
|
|
3435
|
+
// BPG's `pushExampleDownTree` dispatch — no bit-header
|
|
3436
|
+
// cascade. Local emission only.
|
|
3437
|
+
//
|
|
3438
|
+
// Both `reason.example` and `feedbacks[].example` are
|
|
3439
|
+
// `TextAst` per BPG's schema — paragraph arrays. Format
|
|
3440
|
+
// here is `bitmarkText` so `$` coerces to a paragraph
|
|
3441
|
+
// array at both write sites.
|
|
2739
3442
|
key: ConfigKey.property_example,
|
|
2740
|
-
|
|
2741
|
-
|
|
3443
|
+
exportJsonKey: [
|
|
3444
|
+
{
|
|
3445
|
+
// Bare `[@example]`: reason.example is TextAst — BPG
|
|
3446
|
+
// coerces the boolean default to a paragraph
|
|
3447
|
+
// containing the string "true". feedbacks[].example
|
|
3448
|
+
// is not TextAst, stays a boolean. Two literal writes.
|
|
3449
|
+
"@keyonly": {
|
|
3450
|
+
reason: {
|
|
3451
|
+
isExample: true,
|
|
3452
|
+
example: [{ type: "paragraph", content: [{ text: "true", type: "text" }] }]
|
|
3453
|
+
},
|
|
3454
|
+
isExample: true,
|
|
3455
|
+
example: true,
|
|
3456
|
+
"@bit": { isExample: true }
|
|
3457
|
+
}
|
|
3458
|
+
},
|
|
3459
|
+
{
|
|
3460
|
+
reason: { isExample: true, example: "$" },
|
|
3461
|
+
isExample: true,
|
|
3462
|
+
example: "$",
|
|
3463
|
+
"@bit": { isExample: true }
|
|
3464
|
+
}
|
|
3465
|
+
],
|
|
3466
|
+
description: "Example text for the feedback reason (entry-local only; no bit-header cascade).",
|
|
3467
|
+
format: TagFormat.bitmarkText,
|
|
3468
|
+
nullable: true
|
|
2742
3469
|
},
|
|
2743
3470
|
{
|
|
2744
3471
|
key: ConfigKey.tag_title,
|
|
2745
3472
|
description: "Title of the feedback.",
|
|
2746
3473
|
format: TagFormat.plainText,
|
|
2747
|
-
jsonKey: "^heading.forValues"
|
|
3474
|
+
jsonKey: "^heading.forValues",
|
|
3475
|
+
exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
|
|
2748
3476
|
}
|
|
2749
3477
|
],
|
|
2750
3478
|
bodyAllowed: true
|
|
@@ -2758,21 +3486,29 @@ var CARDSETS = {
|
|
|
2758
3486
|
//
|
|
2759
3487
|
[CardSetConfigKey.questions]: {
|
|
2760
3488
|
jsonKey: "questions",
|
|
3489
|
+
exportJsonKey: { questions: "$" },
|
|
2761
3490
|
sides: [
|
|
2762
3491
|
{
|
|
2763
3492
|
name: "question",
|
|
2764
3493
|
variants: [
|
|
2765
3494
|
{
|
|
2766
3495
|
jsonKey: "question",
|
|
3496
|
+
exportJsonKey: { question: "$" },
|
|
2767
3497
|
tags: [
|
|
2768
3498
|
{
|
|
2769
3499
|
key: ConfigKey.property_reasonableNumOfChars,
|
|
3500
|
+
exportJsonKey: [
|
|
3501
|
+
{ "@absent": { reasonableNumOfChars: "$ancestor" } },
|
|
3502
|
+
{ reasonableNumOfChars: "$" }
|
|
3503
|
+
],
|
|
2770
3504
|
description: "Property for reasonable number of characters.",
|
|
2771
3505
|
format: TagFormat.number
|
|
2772
3506
|
},
|
|
2773
3507
|
{
|
|
3508
|
+
exportJsonKey: { sampleSolution: "$" },
|
|
2774
3509
|
key: ConfigKey.tag_sampleSolution,
|
|
2775
|
-
description: "Sample solution for the question."
|
|
3510
|
+
description: "Sample solution for the question.",
|
|
3511
|
+
format: TagFormat.plainText
|
|
2776
3512
|
},
|
|
2777
3513
|
{
|
|
2778
3514
|
key: ConfigKey.property_sampleSolution,
|
|
@@ -2793,6 +3529,22 @@ var CARDSETS = {
|
|
|
2793
3529
|
{
|
|
2794
3530
|
key: ConfigKey.group_standardTags,
|
|
2795
3531
|
description: "Standard tags for the question."
|
|
3532
|
+
},
|
|
3533
|
+
{
|
|
3534
|
+
// ALIGN-EXAMPLE-CASCADE §3.10: `questions` is NOT in BPG's
|
|
3535
|
+
// `pushExampleDownTree` dispatch — bit-header `[@example]`
|
|
3536
|
+
// does not propagate `example`/`isExample` onto question
|
|
3537
|
+
// entries. Only entry-local `[@example]` fires (handled by
|
|
3538
|
+
// `@keyonly` and the unconditional fallback). No `@absent`
|
|
3539
|
+
// rule.
|
|
3540
|
+
key: ConfigKey.property_example,
|
|
3541
|
+
exportJsonKey: [
|
|
3542
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
3543
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3544
|
+
],
|
|
3545
|
+
description: "Example marker for the question (entry-local only; no bit-header cascade).",
|
|
3546
|
+
format: TagFormat.bitmarkText,
|
|
3547
|
+
nullable: true
|
|
2796
3548
|
}
|
|
2797
3549
|
]
|
|
2798
3550
|
}
|
|
@@ -2812,15 +3564,23 @@ var CARDSETS = {
|
|
|
2812
3564
|
variants: [
|
|
2813
3565
|
{
|
|
2814
3566
|
jsonKey: "elements[]",
|
|
3567
|
+
exportJsonKey: { elements: ["$"] },
|
|
2815
3568
|
tags: [
|
|
2816
3569
|
{
|
|
2817
3570
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2818
3571
|
description: "Standard tags for lead, instruction, and hint."
|
|
2819
3572
|
},
|
|
2820
3573
|
{
|
|
3574
|
+
// ALIGN-EXAMPLE-CASCADE §3.11: `elements` is NOT in BPG's
|
|
3575
|
+
// `pushExampleDownTree` dispatch — no bit-header cascade.
|
|
2821
3576
|
key: ConfigKey.property_example,
|
|
2822
|
-
|
|
2823
|
-
|
|
3577
|
+
exportJsonKey: [
|
|
3578
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
3579
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3580
|
+
],
|
|
3581
|
+
description: "Example text for the element (entry-local only; no bit-header cascade).",
|
|
3582
|
+
format: TagFormat.plainText,
|
|
3583
|
+
nullable: true
|
|
2824
3584
|
}
|
|
2825
3585
|
],
|
|
2826
3586
|
repeatCount: Count.infinity
|
|
@@ -2832,8 +3592,57 @@ var CARDSETS = {
|
|
|
2832
3592
|
//
|
|
2833
3593
|
// table
|
|
2834
3594
|
//
|
|
3595
|
+
// PLAN-079: supports BOTH source formats and collapses to the same basic
|
|
3596
|
+
// output (`{ columns?, data, columnWidths? }`):
|
|
3597
|
+
//
|
|
3598
|
+
// 1. Basic format — first card carries `[#X]` markers (fire `tag_title`
|
|
3599
|
+
// → `^table.columns[]`); subsequent cards are body rows. Cards have
|
|
3600
|
+
// no qualifier, so they route to the `table-body` (default) section.
|
|
3601
|
+
//
|
|
3602
|
+
// 2. Extended format — `==== table-header ====` / `==== table-footer ====`
|
|
3603
|
+
// qualifiers. The `table-header` section uses `@cardIndex=0` to route
|
|
3604
|
+
// the first header card's cells to `columns` and demote remaining
|
|
3605
|
+
// header cards (rows) into `data`. Per-cell `[@tableRowSpan]` /
|
|
3606
|
+
// `[@tableScope]` / `[@tableCellType]` tags are valid-but-unmapped
|
|
3607
|
+
// here (no per-cell metadata in basic shape) — declared on the cell
|
|
3608
|
+
// variant below.
|
|
3609
|
+
//
|
|
2835
3610
|
[CardSetConfigKey.table]: {
|
|
2836
|
-
jsonKey:
|
|
3611
|
+
jsonKey: null,
|
|
3612
|
+
exportJsonKey: null,
|
|
3613
|
+
sections: {
|
|
3614
|
+
"table-header": {
|
|
3615
|
+
// First header card's row of cells → `columns`. Subsequent header
|
|
3616
|
+
// cards' rows → `data` (per-card append; `[$]` shape because
|
|
3617
|
+
// per-card emission fires once per card, multiple fires deep_merge-
|
|
3618
|
+
// append). PLAN-079 + PLAN-080: predicates inside exportJsonKey
|
|
3619
|
+
// both ROUTE cards to this section (when no explicit `==== table-
|
|
3620
|
+
// header ====` qualifier) and SELECT the rule body once routed.
|
|
3621
|
+
// First rule = first card with any `[#]` → `columns`; second rule
|
|
3622
|
+
// = subsequent cards in this section → `data` (per-row append).
|
|
3623
|
+
jsonKey: "table.columns",
|
|
3624
|
+
exportJsonKey: [
|
|
3625
|
+
{
|
|
3626
|
+
predicates: [{ "@cardIndex": 0 }, { "@variantHasTag": "#" }],
|
|
3627
|
+
rule: { "@bit": { table: { columns: "$" } } }
|
|
3628
|
+
},
|
|
3629
|
+
{ "@cardIndex=0": { "@bit": { table: { columns: "$" } } } },
|
|
3630
|
+
{ "@bit": { table: { data: ["$"] } } }
|
|
3631
|
+
]
|
|
3632
|
+
},
|
|
3633
|
+
"table-body": {
|
|
3634
|
+
// Batched emission: `$` is the entire 2D array of body card rows.
|
|
3635
|
+
// This is the default section (no qualifier → cards land here).
|
|
3636
|
+
jsonKey: "table.data",
|
|
3637
|
+
exportJsonKey: { "@bit": { table: { data: "$" } } },
|
|
3638
|
+
isDefault: true
|
|
3639
|
+
},
|
|
3640
|
+
"table-footer": {
|
|
3641
|
+
// Batched emission: `$` is the entire 2D array of footer rows.
|
|
3642
|
+
jsonKey: "table.data",
|
|
3643
|
+
exportJsonKey: { "@bit": { table: { data: "$" } } }
|
|
3644
|
+
}
|
|
3645
|
+
},
|
|
2837
3646
|
sides: [
|
|
2838
3647
|
{
|
|
2839
3648
|
name: "cell",
|
|
@@ -2849,6 +3658,7 @@ var CARDSETS = {
|
|
|
2849
3658
|
{
|
|
2850
3659
|
key: ConfigKey.tag_title,
|
|
2851
3660
|
jsonKey: "^table.columns[]",
|
|
3661
|
+
exportJsonKey: { "@bit": { table: { columns: ["$"] } } },
|
|
2852
3662
|
description: "Title of the table."
|
|
2853
3663
|
},
|
|
2854
3664
|
{
|
|
@@ -2873,6 +3683,8 @@ var CARDSETS = {
|
|
|
2873
3683
|
},
|
|
2874
3684
|
{
|
|
2875
3685
|
key: ConfigKey.property_tableColWidth,
|
|
3686
|
+
jsonKey: "^table.columnWidths[{s}]",
|
|
3687
|
+
exportJsonKey: { "@bit": { table: { columnWidths: { $s: "$" } } } },
|
|
2876
3688
|
description: "Width for the column.",
|
|
2877
3689
|
format: TagFormat.number
|
|
2878
3690
|
}
|
|
@@ -2889,18 +3701,49 @@ var CARDSETS = {
|
|
|
2889
3701
|
[CardSetConfigKey.tableExtended]: {
|
|
2890
3702
|
jsonKey: null,
|
|
2891
3703
|
sections: {
|
|
2892
|
-
"table-header": {
|
|
2893
|
-
|
|
2894
|
-
|
|
3704
|
+
"table-header": {
|
|
3705
|
+
jsonKey: "table.header.rows",
|
|
3706
|
+
// PLAN-080: section dispatch via predicates inside exportJsonKey.
|
|
3707
|
+
// Cards with no explicit `==== table-header ====` qualifier
|
|
3708
|
+
// route here if FIRST CARD contains any `[#]` tag in any
|
|
3709
|
+
// variant. Explicit-qualifier cards fall through to the
|
|
3710
|
+
// unconditional fallback rule. Both rules use the per-card
|
|
3711
|
+
// append shape `rows: ['$']` — the runtime triggers per-card
|
|
3712
|
+
// emission whenever the pattern carries predicates, and each
|
|
3713
|
+
// fire appends a single-element array (multi-fire deep-merge
|
|
3714
|
+
// concatenates).
|
|
3715
|
+
exportJsonKey: [
|
|
3716
|
+
{
|
|
3717
|
+
predicates: [{ "@cardIndex": 0 }, { "@variantHasTag": "#" }],
|
|
3718
|
+
rule: { table: { header: { rows: ["$"] } } }
|
|
3719
|
+
},
|
|
3720
|
+
{ table: { header: { rows: ["$"] } } }
|
|
3721
|
+
],
|
|
3722
|
+
sideJsonKey: "cells[{s}]|set(title=true)",
|
|
3723
|
+
sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } }
|
|
3724
|
+
},
|
|
3725
|
+
"table-body": {
|
|
3726
|
+
jsonKey: "table.body.rows",
|
|
3727
|
+
exportJsonKey: { table: { body: { rows: "$" } } },
|
|
3728
|
+
isDefault: true
|
|
3729
|
+
},
|
|
3730
|
+
"table-footer": {
|
|
3731
|
+
jsonKey: "table.footer.rows",
|
|
3732
|
+
exportJsonKey: { table: { footer: { rows: "$" } } },
|
|
3733
|
+
sideJsonKey: "cells[{s}]|set(title=true)",
|
|
3734
|
+
sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } }
|
|
3735
|
+
}
|
|
2895
3736
|
},
|
|
2896
3737
|
sides: [
|
|
2897
3738
|
{
|
|
2898
3739
|
name: "cell",
|
|
2899
3740
|
repeat: true,
|
|
2900
3741
|
jsonKey: "cells[{s}]",
|
|
3742
|
+
exportJsonKey: { cells: { $s: "$" } },
|
|
2901
3743
|
variants: [
|
|
2902
3744
|
{
|
|
2903
3745
|
jsonKey: "content",
|
|
3746
|
+
exportJsonKey: { content: "$" },
|
|
2904
3747
|
tags: [
|
|
2905
3748
|
{
|
|
2906
3749
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
@@ -2908,35 +3751,47 @@ var CARDSETS = {
|
|
|
2908
3751
|
},
|
|
2909
3752
|
{
|
|
2910
3753
|
key: ConfigKey.tag_title,
|
|
2911
|
-
|
|
2912
|
-
|
|
3754
|
+
// PLAN-080: the `[#]` tag writes its text to the cell's
|
|
3755
|
+
// `content` field. When the card is in the `table-header`
|
|
3756
|
+
// section, the section's sideExportJsonKey wraps each
|
|
3757
|
+
// cell with `title: true` automatically.
|
|
3758
|
+
jsonKey: "content",
|
|
3759
|
+
exportJsonKey: { content: "$" },
|
|
3760
|
+
description: "Title text of the table cell (header rows)."
|
|
2913
3761
|
},
|
|
2914
3762
|
{
|
|
2915
3763
|
key: ConfigKey.property_tableCellType,
|
|
2916
3764
|
jsonKey: "title|bool(th)",
|
|
3765
|
+
exportJsonKey: [{ "@value=th": { title: true } }],
|
|
2917
3766
|
description: "Table cell type (th/td).",
|
|
2918
3767
|
format: TagFormat.plainText
|
|
2919
3768
|
},
|
|
2920
3769
|
{
|
|
2921
3770
|
key: ConfigKey.property_tableRowSpan,
|
|
2922
3771
|
jsonKey: "rowspan",
|
|
3772
|
+
exportJsonKey: { rowspan: "$" },
|
|
2923
3773
|
description: "Number of rows the cell spans.",
|
|
2924
3774
|
format: TagFormat.number
|
|
2925
3775
|
},
|
|
2926
3776
|
{
|
|
2927
3777
|
key: ConfigKey.property_tableColSpan,
|
|
2928
3778
|
jsonKey: "colspan",
|
|
3779
|
+
exportJsonKey: { colspan: "$" },
|
|
2929
3780
|
description: "Number of columns the cell spans.",
|
|
2930
3781
|
format: TagFormat.number
|
|
2931
3782
|
},
|
|
2932
3783
|
{
|
|
2933
3784
|
key: ConfigKey.property_tableScope,
|
|
2934
3785
|
jsonKey: "scope",
|
|
3786
|
+
exportJsonKey: { scope: "$" },
|
|
2935
3787
|
description: "Scope attribute for header cells.",
|
|
2936
3788
|
format: TagFormat.plainText
|
|
2937
3789
|
},
|
|
2938
3790
|
{
|
|
2939
3791
|
key: ConfigKey.property_tableColWidth,
|
|
3792
|
+
// PLAN-080: write to the cell's `colwidth` field.
|
|
3793
|
+
jsonKey: "colwidth",
|
|
3794
|
+
exportJsonKey: { colwidth: "$" },
|
|
2940
3795
|
description: "Width for the column.",
|
|
2941
3796
|
format: TagFormat.number
|
|
2942
3797
|
}
|
|
@@ -2952,6 +3807,7 @@ var CARDSETS = {
|
|
|
2952
3807
|
//
|
|
2953
3808
|
[CardSetConfigKey.pronunciationTable]: {
|
|
2954
3809
|
jsonKey: "pronunciationTable.data",
|
|
3810
|
+
exportJsonKey: { pronunciationTable: { data: "$" } },
|
|
2955
3811
|
sides: [
|
|
2956
3812
|
{
|
|
2957
3813
|
name: "cell",
|
|
@@ -2959,19 +3815,22 @@ var CARDSETS = {
|
|
|
2959
3815
|
variants: [
|
|
2960
3816
|
{
|
|
2961
3817
|
jsonKey: "body",
|
|
3818
|
+
exportJsonKey: { body: "$" },
|
|
2962
3819
|
tags: [
|
|
2963
3820
|
{
|
|
2964
3821
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2965
3822
|
description: "Standard tags for lead, instruction, and hint."
|
|
2966
3823
|
},
|
|
2967
3824
|
{
|
|
3825
|
+
exportJsonKey: { title: "$" },
|
|
2968
3826
|
key: ConfigKey.tag_title,
|
|
2969
3827
|
description: "Title of the pronunciation table."
|
|
2970
3828
|
},
|
|
2971
3829
|
{
|
|
2972
3830
|
key: ConfigKey.resource_audio,
|
|
2973
3831
|
description: "Audio resource for the pronunciation table.",
|
|
2974
|
-
jsonKey: "audio"
|
|
3832
|
+
jsonKey: "audio",
|
|
3833
|
+
exportJsonKey: { audio: { type: "audio", audio: { src: "$" } } }
|
|
2975
3834
|
}
|
|
2976
3835
|
],
|
|
2977
3836
|
repeatCount: Count.infinity
|
|
@@ -2985,12 +3844,15 @@ var CARDSETS = {
|
|
|
2985
3844
|
//
|
|
2986
3845
|
[CardSetConfigKey.botActionResponses]: {
|
|
2987
3846
|
jsonKey: "responses",
|
|
3847
|
+
exportJsonKey: { responses: "$" },
|
|
2988
3848
|
sides: [
|
|
2989
3849
|
{
|
|
2990
3850
|
name: "response",
|
|
2991
3851
|
variants: [
|
|
2992
3852
|
{
|
|
2993
3853
|
jsonKey: "feedback",
|
|
3854
|
+
exportJsonKey: { feedback: "$" },
|
|
3855
|
+
format: TextFormat2.plainText,
|
|
2994
3856
|
tags: [
|
|
2995
3857
|
{
|
|
2996
3858
|
key: ConfigKey.property_reaction,
|
|
@@ -2998,18 +3860,58 @@ var CARDSETS = {
|
|
|
2998
3860
|
format: TagFormat.plainText
|
|
2999
3861
|
},
|
|
3000
3862
|
{
|
|
3001
|
-
key: ConfigKey.
|
|
3002
|
-
|
|
3863
|
+
key: ConfigKey.tag_item,
|
|
3864
|
+
jsonKey: "item",
|
|
3865
|
+
exportJsonKey: { item: "$" },
|
|
3866
|
+
format: TagFormat.plainText,
|
|
3867
|
+
description: "The item for the bit",
|
|
3868
|
+
chain: [
|
|
3869
|
+
{
|
|
3870
|
+
key: ConfigKey.tag_item,
|
|
3871
|
+
jsonKey: "lead",
|
|
3872
|
+
exportJsonKey: { lead: "$" },
|
|
3873
|
+
description: "The lead for the bit",
|
|
3874
|
+
maxCount: 1,
|
|
3875
|
+
chain: [
|
|
3876
|
+
{
|
|
3877
|
+
key: ConfigKey.tag_item,
|
|
3878
|
+
jsonKey: "pageNumber",
|
|
3879
|
+
exportJsonKey: { pageNumber: "$" },
|
|
3880
|
+
description: "The page number for the bit",
|
|
3881
|
+
maxCount: 1,
|
|
3882
|
+
chain: [
|
|
3883
|
+
{
|
|
3884
|
+
key: ConfigKey.tag_item,
|
|
3885
|
+
jsonKey: "marginNumber",
|
|
3886
|
+
exportJsonKey: { marginNumber: "$" },
|
|
3887
|
+
description: "The margin number for the bit",
|
|
3888
|
+
maxCount: 1
|
|
3889
|
+
}
|
|
3890
|
+
]
|
|
3891
|
+
}
|
|
3892
|
+
]
|
|
3893
|
+
}
|
|
3894
|
+
]
|
|
3003
3895
|
},
|
|
3004
3896
|
{
|
|
3005
3897
|
key: ConfigKey.tag_instruction,
|
|
3006
3898
|
description: "The response label for the bot action.",
|
|
3007
|
-
jsonKey: "response"
|
|
3899
|
+
jsonKey: "response",
|
|
3900
|
+
exportJsonKey: { response: "$" },
|
|
3901
|
+
format: TagFormat.plainText
|
|
3008
3902
|
},
|
|
3009
3903
|
{
|
|
3904
|
+
// ALIGN-EXAMPLE-CASCADE §3.12: `bot-action-responses` is
|
|
3905
|
+
// NOT in BPG's `pushExampleDownTree` dispatch — no bit-
|
|
3906
|
+
// header cascade.
|
|
3010
3907
|
key: ConfigKey.property_example,
|
|
3011
|
-
|
|
3012
|
-
|
|
3908
|
+
exportJsonKey: [
|
|
3909
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
3910
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3911
|
+
],
|
|
3912
|
+
description: "Example text for the bot action response (entry-local only; no bit-header cascade).",
|
|
3913
|
+
format: TagFormat.plainText,
|
|
3914
|
+
nullable: true
|
|
3013
3915
|
}
|
|
3014
3916
|
]
|
|
3015
3917
|
}
|
|
@@ -3022,12 +3924,14 @@ var CARDSETS = {
|
|
|
3022
3924
|
//
|
|
3023
3925
|
[CardSetConfigKey.clozeList]: {
|
|
3024
3926
|
jsonKey: "listItems",
|
|
3927
|
+
exportJsonKey: { listItems: "$" },
|
|
3025
3928
|
sides: [
|
|
3026
3929
|
{
|
|
3027
3930
|
name: "content",
|
|
3028
3931
|
variants: [
|
|
3029
3932
|
{
|
|
3030
3933
|
jsonKey: "body",
|
|
3934
|
+
exportJsonKey: { body: "$" },
|
|
3031
3935
|
tags: [
|
|
3032
3936
|
{
|
|
3033
3937
|
key: ConfigKey.group_standardTags,
|
|
@@ -3048,18 +3952,21 @@ var CARDSETS = {
|
|
|
3048
3952
|
//
|
|
3049
3953
|
[CardSetConfigKey.exampleBitList]: {
|
|
3050
3954
|
jsonKey: "listItems",
|
|
3955
|
+
exportJsonKey: { listItems: "$" },
|
|
3051
3956
|
sides: [
|
|
3052
3957
|
{
|
|
3053
3958
|
name: "item",
|
|
3054
3959
|
variants: [
|
|
3055
3960
|
{
|
|
3056
3961
|
jsonKey: "body",
|
|
3962
|
+
exportJsonKey: { body: "$" },
|
|
3057
3963
|
tags: [
|
|
3058
3964
|
{
|
|
3059
3965
|
key: ConfigKey.group_standardTags,
|
|
3060
3966
|
description: "Standard tags for example bits."
|
|
3061
3967
|
},
|
|
3062
3968
|
{
|
|
3969
|
+
exportJsonKey: { title: "$" },
|
|
3063
3970
|
key: ConfigKey.tag_title,
|
|
3064
3971
|
description: "Title of the example bit."
|
|
3065
3972
|
}
|
|
@@ -3070,18 +3977,53 @@ var CARDSETS = {
|
|
|
3070
3977
|
]
|
|
3071
3978
|
},
|
|
3072
3979
|
//
|
|
3980
|
+
// page-footer-sections — mirrors example-bit-list but emits cards under
|
|
3981
|
+
// `sections` instead of `listItems`. BPG's JsonGenerator special-cases
|
|
3982
|
+
// BitType.pageFooter in code; this dedicated cardSet expresses the same
|
|
3983
|
+
// routing as pure config so the Rust serializer can pick it up.
|
|
3984
|
+
//
|
|
3985
|
+
[CardSetConfigKey.pageFooterSections]: {
|
|
3986
|
+
jsonKey: "sections",
|
|
3987
|
+
exportJsonKey: { sections: "$" },
|
|
3988
|
+
sides: [
|
|
3989
|
+
{
|
|
3990
|
+
name: "item",
|
|
3991
|
+
variants: [
|
|
3992
|
+
{
|
|
3993
|
+
jsonKey: "body",
|
|
3994
|
+
exportJsonKey: { body: "$" },
|
|
3995
|
+
tags: [
|
|
3996
|
+
{
|
|
3997
|
+
key: ConfigKey.group_standardTags,
|
|
3998
|
+
description: "Standard tags for page-footer section bits."
|
|
3999
|
+
},
|
|
4000
|
+
{
|
|
4001
|
+
exportJsonKey: { title: "$" },
|
|
4002
|
+
key: ConfigKey.tag_title,
|
|
4003
|
+
description: "Title of the page-footer section."
|
|
4004
|
+
}
|
|
4005
|
+
]
|
|
4006
|
+
}
|
|
4007
|
+
]
|
|
4008
|
+
}
|
|
4009
|
+
]
|
|
4010
|
+
},
|
|
4011
|
+
//
|
|
3073
4012
|
// ingredients
|
|
3074
4013
|
//
|
|
3075
4014
|
[CardSetConfigKey.ingredients]: {
|
|
3076
4015
|
jsonKey: "ingredients",
|
|
4016
|
+
exportJsonKey: { ingredients: "$" },
|
|
3077
4017
|
sides: [
|
|
3078
4018
|
{
|
|
3079
4019
|
name: "ingredient",
|
|
3080
4020
|
variants: [
|
|
3081
4021
|
{
|
|
3082
4022
|
jsonKey: "ingredient",
|
|
4023
|
+
exportJsonKey: { ingredient: "$" },
|
|
3083
4024
|
tags: [
|
|
3084
4025
|
{
|
|
4026
|
+
exportJsonKey: { title: "$" },
|
|
3085
4027
|
key: ConfigKey.tag_title,
|
|
3086
4028
|
description: "Title of the ingredient."
|
|
3087
4029
|
},
|
|
@@ -3089,6 +4031,7 @@ var CARDSETS = {
|
|
|
3089
4031
|
key: ConfigKey.tag_true,
|
|
3090
4032
|
description: "Checked state for the ingredient.",
|
|
3091
4033
|
jsonKey: "|set(checked=true)",
|
|
4034
|
+
exportJsonKey: { checked: true, $: "$" },
|
|
3092
4035
|
maxCount: 1
|
|
3093
4036
|
// nullable: true,
|
|
3094
4037
|
},
|
|
@@ -3096,6 +4039,7 @@ var CARDSETS = {
|
|
|
3096
4039
|
key: ConfigKey.tag_false,
|
|
3097
4040
|
description: "Unchecked state for the ingredient.",
|
|
3098
4041
|
jsonKey: "|set(checked=false)",
|
|
4042
|
+
exportJsonKey: { checked: false, $: "$" },
|
|
3099
4043
|
maxCount: 1
|
|
3100
4044
|
// nullable: true,
|
|
3101
4045
|
},
|
|
@@ -3107,9 +4051,11 @@ var CARDSETS = {
|
|
|
3107
4051
|
key: ConfigKey.tag_instruction,
|
|
3108
4052
|
description: "The quantity of the ingredient.",
|
|
3109
4053
|
jsonKey: "quantity",
|
|
4054
|
+
exportJsonKey: { quantity: "$" },
|
|
3110
4055
|
format: TagFormat.number
|
|
3111
4056
|
},
|
|
3112
4057
|
{
|
|
4058
|
+
exportJsonKey: { hint: "$" },
|
|
3113
4059
|
key: ConfigKey.tag_hint,
|
|
3114
4060
|
description: "The hint for the ingredient."
|
|
3115
4061
|
},
|
|
@@ -3145,6 +4091,7 @@ var CARDSETS = {
|
|
|
3145
4091
|
//
|
|
3146
4092
|
[CardSetConfigKey.bookReferenceList]: {
|
|
3147
4093
|
jsonKey: "bookReferences",
|
|
4094
|
+
exportJsonKey: { bookReferences: "$" },
|
|
3148
4095
|
sides: [
|
|
3149
4096
|
{
|
|
3150
4097
|
name: "reference",
|
|
@@ -3204,6 +4151,11 @@ var GROUPS = {
|
|
|
3204
4151
|
format: TagFormat.plainText,
|
|
3205
4152
|
maxCount: Count.infinity
|
|
3206
4153
|
},
|
|
4154
|
+
{
|
|
4155
|
+
key: ConfigKey.property_gUri,
|
|
4156
|
+
description: "Global URI for the bit",
|
|
4157
|
+
format: TagFormat.plainText
|
|
4158
|
+
},
|
|
3207
4159
|
{
|
|
3208
4160
|
key: ConfigKey.property_customerId,
|
|
3209
4161
|
description: "The customer-specific identifier for the bit",
|
|
@@ -3387,12 +4339,18 @@ var GROUPS = {
|
|
|
3387
4339
|
{
|
|
3388
4340
|
key: ConfigKey.property_groupTag,
|
|
3389
4341
|
jsonKey: "groupTag.name",
|
|
4342
|
+
// PLAN-063: starter-array shape with `@id` declares entity-merge
|
|
4343
|
+
// semantics — repeated `[@groupTag: name]` occurrences with the
|
|
4344
|
+
// same value fold into one entry; chained `@tag` children's
|
|
4345
|
+
// arrays merge as sets.
|
|
4346
|
+
exportJsonKey: { groupTag: [{ "@id": "name", name: "$" }] },
|
|
3390
4347
|
description: "The group tag(s) for the bit",
|
|
3391
4348
|
format: TagFormat.plainText,
|
|
3392
4349
|
maxCount: Count.infinity,
|
|
3393
4350
|
chain: [
|
|
3394
4351
|
{
|
|
3395
4352
|
key: ConfigKey.property_tag,
|
|
4353
|
+
exportJsonKey: { tags: ["$"] },
|
|
3396
4354
|
description: "The tag(s) for the group",
|
|
3397
4355
|
format: TagFormat.plainText,
|
|
3398
4356
|
maxCount: Count.infinity
|
|
@@ -3423,6 +4381,12 @@ var GROUPS = {
|
|
|
3423
4381
|
format: TagFormat.plainText,
|
|
3424
4382
|
maxCount: Count.infinity
|
|
3425
4383
|
},
|
|
4384
|
+
{
|
|
4385
|
+
key: ConfigKey.property_sourceBB,
|
|
4386
|
+
description: "The source bounding box(es) for the bit (x, y, x1, y1)",
|
|
4387
|
+
format: TagFormat.coordinates,
|
|
4388
|
+
maxCount: Count.infinity
|
|
4389
|
+
},
|
|
3426
4390
|
{
|
|
3427
4391
|
key: ConfigKey.property_levelCEFRp,
|
|
3428
4392
|
description: "The CEFRp level for the bit",
|
|
@@ -3460,6 +4424,7 @@ var GROUPS = {
|
|
|
3460
4424
|
maxCount: Count.infinity
|
|
3461
4425
|
},
|
|
3462
4426
|
{
|
|
4427
|
+
exportJsonKey: { anchor: "$" },
|
|
3463
4428
|
key: ConfigKey.tag_anchor,
|
|
3464
4429
|
name: "Anchor",
|
|
3465
4430
|
format: TagFormat.plainText,
|
|
@@ -3497,23 +4462,27 @@ var GROUPS = {
|
|
|
3497
4462
|
{
|
|
3498
4463
|
key: ConfigKey.tag_item,
|
|
3499
4464
|
jsonKey: "item",
|
|
4465
|
+
exportJsonKey: { item: "$" },
|
|
3500
4466
|
description: "The item for the bit",
|
|
3501
4467
|
chain: [
|
|
3502
4468
|
{
|
|
3503
4469
|
key: ConfigKey.tag_item,
|
|
3504
4470
|
jsonKey: "lead",
|
|
4471
|
+
exportJsonKey: { lead: "$" },
|
|
3505
4472
|
description: "The lead for the bit",
|
|
3506
4473
|
maxCount: 1,
|
|
3507
4474
|
chain: [
|
|
3508
4475
|
{
|
|
3509
4476
|
key: ConfigKey.tag_item,
|
|
3510
4477
|
jsonKey: "pageNumber",
|
|
4478
|
+
exportJsonKey: { pageNumber: "$" },
|
|
3511
4479
|
description: "The page number for the bit",
|
|
3512
4480
|
maxCount: 1,
|
|
3513
4481
|
chain: [
|
|
3514
4482
|
{
|
|
3515
4483
|
key: ConfigKey.tag_item,
|
|
3516
4484
|
jsonKey: "marginNumber",
|
|
4485
|
+
exportJsonKey: { marginNumber: "$" },
|
|
3517
4486
|
description: "The margin number for the bit",
|
|
3518
4487
|
maxCount: 1
|
|
3519
4488
|
}
|
|
@@ -3534,11 +4503,31 @@ var GROUPS = {
|
|
|
3534
4503
|
description: "Item, lead, page number, and margin number tags"
|
|
3535
4504
|
},
|
|
3536
4505
|
{
|
|
4506
|
+
exportJsonKey: { instruction: "$" },
|
|
4507
|
+
key: ConfigKey.tag_instruction,
|
|
4508
|
+
name: "Instruction",
|
|
4509
|
+
description: "The instruction for the bit"
|
|
4510
|
+
},
|
|
4511
|
+
{
|
|
4512
|
+
exportJsonKey: { hint: "$" },
|
|
4513
|
+
key: ConfigKey.tag_hint,
|
|
4514
|
+
name: "Hint",
|
|
4515
|
+
description: "The hint for the bit"
|
|
4516
|
+
}
|
|
4517
|
+
]
|
|
4518
|
+
},
|
|
4519
|
+
[ConfigKey.group_standardInstructionHint]: {
|
|
4520
|
+
type: GroupConfigType.standard,
|
|
4521
|
+
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).",
|
|
4522
|
+
tags: [
|
|
4523
|
+
{
|
|
4524
|
+
exportJsonKey: { instruction: "$" },
|
|
3537
4525
|
key: ConfigKey.tag_instruction,
|
|
3538
4526
|
name: "Instruction",
|
|
3539
4527
|
description: "The instruction for the bit"
|
|
3540
4528
|
},
|
|
3541
4529
|
{
|
|
4530
|
+
exportJsonKey: { hint: "$" },
|
|
3542
4531
|
key: ConfigKey.tag_hint,
|
|
3543
4532
|
name: "Hint",
|
|
3544
4533
|
description: "The hint for the bit"
|
|
@@ -3558,9 +4547,45 @@ var GROUPS = {
|
|
|
3558
4547
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3559
4548
|
},
|
|
3560
4549
|
{
|
|
4550
|
+
// Bit-level example tag (default — non-`isTopLevelExample` bits):
|
|
4551
|
+
// - bare `[@example]`: consume only (records cascade marker, emits
|
|
4552
|
+
// nothing at bit-level — OLD parser scrubs bit-level isExample
|
|
4553
|
+
// for bits NOT in its `isTopLevelExample` allow-list).
|
|
4554
|
+
// - synthesized (descendant cascade): still emits `isExample: true`
|
|
4555
|
+
// at the descendant scope.
|
|
4556
|
+
// - valued `[@example:text]`: emit the example value only; bit-level
|
|
4557
|
+
// `isExample` is left to bubble from descendants.
|
|
4558
|
+
// Bits in the OLD parser's allow-list (flashcard, definitionList,
|
|
4559
|
+
// sequence, multipleChoice, trueFalse, cloze*, mark, interview,
|
|
4560
|
+
// matchMatrix, match, essay, etc.) override this entry with the
|
|
4561
|
+
// legacy emit-isExample shape.
|
|
3561
4562
|
key: ConfigKey.property_example,
|
|
4563
|
+
exportJsonKey: [{ "@keyonly": {} }, { "@absent": { isExample: true } }, { example: "$" }],
|
|
3562
4564
|
description: "The example(s) for the bit",
|
|
3563
|
-
format: TagFormat.
|
|
4565
|
+
format: TagFormat.bitmarkText,
|
|
4566
|
+
nullable: true
|
|
4567
|
+
}
|
|
4568
|
+
]
|
|
4569
|
+
},
|
|
4570
|
+
[ConfigKey.group_standardTagsNoItemLead]: {
|
|
4571
|
+
type: GroupConfigType.standard,
|
|
4572
|
+
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).",
|
|
4573
|
+
tags: [
|
|
4574
|
+
{
|
|
4575
|
+
key: ConfigKey.group_standardAllBits,
|
|
4576
|
+
description: "All standard tags which apply to all bits"
|
|
4577
|
+
},
|
|
4578
|
+
{
|
|
4579
|
+
key: ConfigKey.group_standardInstructionHint,
|
|
4580
|
+
description: "Instruction and hint tags only (no item/lead chain)."
|
|
4581
|
+
},
|
|
4582
|
+
{
|
|
4583
|
+
// Mirror of group_standardTags property_example entry.
|
|
4584
|
+
key: ConfigKey.property_example,
|
|
4585
|
+
exportJsonKey: [{ "@keyonly": {} }, { "@absent": { isExample: true } }, { example: "$" }],
|
|
4586
|
+
description: "The example(s) for the bit",
|
|
4587
|
+
format: TagFormat.bitmarkText,
|
|
4588
|
+
nullable: true
|
|
3564
4589
|
}
|
|
3565
4590
|
]
|
|
3566
4591
|
},
|
|
@@ -3571,6 +4596,7 @@ var GROUPS = {
|
|
|
3571
4596
|
{
|
|
3572
4597
|
key: ConfigKey.property_imageSource,
|
|
3573
4598
|
jsonKey: "imageSource.url",
|
|
4599
|
+
exportJsonKey: { imageSource: { url: "$" } },
|
|
3574
4600
|
description: "The source of an image",
|
|
3575
4601
|
format: TagFormat.plainText,
|
|
3576
4602
|
chain: [
|
|
@@ -3605,6 +4631,7 @@ var GROUPS = {
|
|
|
3605
4631
|
{
|
|
3606
4632
|
key: ConfigKey.property_technicalTerm,
|
|
3607
4633
|
jsonKey: "technicalTerm.technicalTerm",
|
|
4634
|
+
exportJsonKey: { technicalTerm: { technicalTerm: "$" } },
|
|
3608
4635
|
description: "The technical term",
|
|
3609
4636
|
format: TagFormat.plainText,
|
|
3610
4637
|
chain: [
|
|
@@ -3623,7 +4650,8 @@ var GROUPS = {
|
|
|
3623
4650
|
tags: [
|
|
3624
4651
|
{
|
|
3625
4652
|
key: ConfigKey.property_person,
|
|
3626
|
-
jsonKey: "
|
|
4653
|
+
jsonKey: "person.name",
|
|
4654
|
+
exportJsonKey: { person: { name: "$" } },
|
|
3627
4655
|
description: "A person",
|
|
3628
4656
|
format: TagFormat.plainText,
|
|
3629
4657
|
chain: [
|
|
@@ -3635,6 +4663,7 @@ var GROUPS = {
|
|
|
3635
4663
|
{
|
|
3636
4664
|
key: ConfigKey.group_resourceImage,
|
|
3637
4665
|
jsonKey: "avatarImage|resource(type=image, key=image)",
|
|
4666
|
+
exportJsonKey: { avatarImage: { type: "image", image: { src: "$" } } },
|
|
3638
4667
|
description: "The image of the person"
|
|
3639
4668
|
}
|
|
3640
4669
|
]
|
|
@@ -3642,7 +4671,8 @@ var GROUPS = {
|
|
|
3642
4671
|
{
|
|
3643
4672
|
// Deprecated (parter renamed to person)
|
|
3644
4673
|
key: ConfigKey.property_partner,
|
|
3645
|
-
jsonKey: "
|
|
4674
|
+
jsonKey: "person.name",
|
|
4675
|
+
exportJsonKey: { person: { name: "$" } },
|
|
3646
4676
|
description: "A partner",
|
|
3647
4677
|
format: TagFormat.plainText,
|
|
3648
4678
|
chain: [
|
|
@@ -3654,6 +4684,7 @@ var GROUPS = {
|
|
|
3654
4684
|
{
|
|
3655
4685
|
key: ConfigKey.group_resourceImage,
|
|
3656
4686
|
jsonKey: "avatarImage|resource(type=image, key=image)",
|
|
4687
|
+
exportJsonKey: { avatarImage: { type: "image", image: { src: "$" } } },
|
|
3657
4688
|
description: "The image of the partner"
|
|
3658
4689
|
}
|
|
3659
4690
|
]
|
|
@@ -3665,29 +4696,66 @@ var GROUPS = {
|
|
|
3665
4696
|
description: "Gap chain",
|
|
3666
4697
|
tags: [
|
|
3667
4698
|
{
|
|
4699
|
+
exportJsonKey: {
|
|
4700
|
+
"@body-inline": { type: "gap", attrs: { solutions: ["$"] } }
|
|
4701
|
+
},
|
|
3668
4702
|
key: ConfigKey.tag_gap,
|
|
3669
4703
|
description: "The value of a gap in the content",
|
|
3670
4704
|
maxCount: Count.infinity,
|
|
4705
|
+
format: TagFormat.plainText,
|
|
3671
4706
|
chain: [
|
|
3672
4707
|
{
|
|
3673
4708
|
key: ConfigKey.tag_gap,
|
|
3674
4709
|
jsonKey: "solutions[]",
|
|
4710
|
+
exportJsonKey: { solutions: ["$"] },
|
|
3675
4711
|
description: "Alternative values for the gaps in the content",
|
|
3676
|
-
maxCount: Count.infinity
|
|
4712
|
+
maxCount: Count.infinity,
|
|
4713
|
+
format: TagFormat.plainText
|
|
3677
4714
|
},
|
|
3678
4715
|
{
|
|
3679
4716
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3680
4717
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3681
4718
|
},
|
|
3682
4719
|
{
|
|
4720
|
+
// BPG ExampleTagContentProcessor.ts:91-95 reads
|
|
4721
|
+
// `__solutionsAst[length - 1]` — the solution closest to the
|
|
4722
|
+
// `[@example]` tag at parse time. Our chain accumulator is built
|
|
4723
|
+
// incrementally (scope.rs `parent.merge` after each tag), so at
|
|
4724
|
+
// the moment `[@example]` fires, `solutions` only contains the
|
|
4725
|
+
// preceding `[_x]` entries — `[-1]` resolves to the closest one.
|
|
4726
|
+
// E.g. `[_cloze][_gap][@example]` → solutions=["cloze","gap"],
|
|
4727
|
+
// `[-1]`="gap"; `[_solution][@example][_problem]` →
|
|
4728
|
+
// solutions=["solution"], `[-1]`="solution".
|
|
3683
4729
|
key: ConfigKey.property_example,
|
|
3684
4730
|
jsonKey: "example",
|
|
4731
|
+
exportJsonKey: [
|
|
4732
|
+
{
|
|
4733
|
+
"@keyonly": {
|
|
4734
|
+
isExample: true,
|
|
4735
|
+
example: "$parent.solutions[-1]",
|
|
4736
|
+
"@bit": { isExample: true }
|
|
4737
|
+
}
|
|
4738
|
+
},
|
|
4739
|
+
{
|
|
4740
|
+
"@absent": {
|
|
4741
|
+
isExample: true,
|
|
4742
|
+
example: "$parent.solutions[-1]",
|
|
4743
|
+
"@bit": { isExample: true }
|
|
4744
|
+
}
|
|
4745
|
+
},
|
|
4746
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
4747
|
+
],
|
|
3685
4748
|
description: "An example for the gap",
|
|
3686
|
-
format: TagFormat.
|
|
4749
|
+
format: TagFormat.bitmarkText,
|
|
4750
|
+
nullable: true
|
|
3687
4751
|
},
|
|
3688
4752
|
{
|
|
3689
4753
|
key: ConfigKey.property_isCaseSensitive,
|
|
3690
4754
|
jsonKey: "isCaseSensitive",
|
|
4755
|
+
exportJsonKey: [
|
|
4756
|
+
{ "@absent": { isCaseSensitive: "$ancestor" } },
|
|
4757
|
+
{ isCaseSensitive: "$" }
|
|
4758
|
+
],
|
|
3691
4759
|
description: "If true, the gap text is case sensitive",
|
|
3692
4760
|
format: TagFormat.boolean,
|
|
3693
4761
|
defaultValue: "true"
|
|
@@ -3701,60 +4769,587 @@ var GROUPS = {
|
|
|
3701
4769
|
description: "True/False chain",
|
|
3702
4770
|
tags: [
|
|
3703
4771
|
{
|
|
4772
|
+
exportJsonKey: { choices: [{ choice: "$", isCorrect: true }] },
|
|
3704
4773
|
key: ConfigKey.tag_true,
|
|
3705
4774
|
description: "True value for a true/false statement/question",
|
|
3706
4775
|
maxCount: Count.infinity,
|
|
4776
|
+
format: TagFormat.plainText,
|
|
3707
4777
|
chain: [
|
|
3708
4778
|
{
|
|
3709
4779
|
key: ConfigKey.tag_true,
|
|
3710
4780
|
jsonKey: "choices[]|set(isCorrect=true)",
|
|
4781
|
+
exportJsonKey: { choices: [{ choice: "$", isCorrect: true }] },
|
|
3711
4782
|
description: "True values for a true/false statement/question",
|
|
3712
|
-
maxCount: Count.infinity
|
|
4783
|
+
maxCount: Count.infinity,
|
|
4784
|
+
format: TagFormat.plainText
|
|
3713
4785
|
},
|
|
3714
4786
|
{
|
|
3715
4787
|
key: ConfigKey.tag_false,
|
|
3716
4788
|
jsonKey: "choices[]|set(isCorrect=false)",
|
|
4789
|
+
exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
|
|
3717
4790
|
description: "False values for a true/false statement/question",
|
|
3718
|
-
maxCount: Count.infinity
|
|
4791
|
+
maxCount: Count.infinity,
|
|
4792
|
+
format: TagFormat.plainText
|
|
3719
4793
|
},
|
|
3720
4794
|
{
|
|
3721
4795
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3722
4796
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3723
4797
|
},
|
|
3724
4798
|
{
|
|
4799
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.2: cascade-fired
|
|
4800
|
+
// `@example` from the bit header marks EVERY choice with
|
|
4801
|
+
// `isExample: true` (matches BPG output), but only the
|
|
4802
|
+
// FIRST correct choice gets `example: true` (BPG
|
|
4803
|
+
// `fillBooleanExample(..., firstCorrectOnly=true)`).
|
|
4804
|
+
//
|
|
4805
|
+
// Two `@absent` rules, picked first-match-wins:
|
|
4806
|
+
// 1. Verbose form gated on `@parent.isCorrect=true` with
|
|
4807
|
+
// `maxEmits:1` — fires once for the first correct.
|
|
4808
|
+
// 2. Plain `@absent` — fires on every remaining entry
|
|
4809
|
+
// (subsequent corrects and all incorrects), emitting
|
|
4810
|
+
// `isExample` only.
|
|
4811
|
+
// The `serialize_cards` cascade-counter scope holds the cap
|
|
4812
|
+
// across the whole cardset.
|
|
4813
|
+
// @card scope-shift writes choice-container isExample (e.g.
|
|
4814
|
+
// `quizzes[i].isExample`) — was previously provided by the
|
|
4815
|
+
// universal `bubble_is_example` post-walk, which was removed
|
|
4816
|
+
// in favour of explicit per-tag config. SYNTAX.md §8.
|
|
3725
4817
|
key: ConfigKey.property_example,
|
|
3726
4818
|
jsonKey: "example",
|
|
4819
|
+
exportJsonKey: [
|
|
4820
|
+
{
|
|
4821
|
+
"@keyonly": {
|
|
4822
|
+
isExample: true,
|
|
4823
|
+
example: "$parent.isCorrect",
|
|
4824
|
+
"@bit": { isExample: true },
|
|
4825
|
+
"@card": { isExample: true }
|
|
4826
|
+
}
|
|
4827
|
+
},
|
|
4828
|
+
{
|
|
4829
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
4830
|
+
maxEmits: 1,
|
|
4831
|
+
rule: {
|
|
4832
|
+
isExample: true,
|
|
4833
|
+
example: true,
|
|
4834
|
+
"@bit": { isExample: true },
|
|
4835
|
+
"@card": { isExample: true }
|
|
4836
|
+
}
|
|
4837
|
+
},
|
|
4838
|
+
{
|
|
4839
|
+
"@absent": {
|
|
4840
|
+
isExample: true,
|
|
4841
|
+
"@bit": { isExample: true },
|
|
4842
|
+
"@card": { isExample: true }
|
|
4843
|
+
}
|
|
4844
|
+
},
|
|
4845
|
+
{
|
|
4846
|
+
isExample: true,
|
|
4847
|
+
example: "$",
|
|
4848
|
+
"@bit": { isExample: true },
|
|
4849
|
+
"@card": { isExample: true }
|
|
4850
|
+
}
|
|
4851
|
+
],
|
|
3727
4852
|
description: "An example for the true/false statement/question",
|
|
3728
|
-
format: TagFormat.
|
|
4853
|
+
format: TagFormat.boolean,
|
|
4854
|
+
nullable: true
|
|
3729
4855
|
}
|
|
3730
4856
|
]
|
|
3731
4857
|
},
|
|
3732
4858
|
{
|
|
4859
|
+
exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
|
|
3733
4860
|
key: ConfigKey.tag_false,
|
|
3734
4861
|
description: "False value for a true/false statement/question",
|
|
3735
4862
|
maxCount: Count.infinity,
|
|
4863
|
+
format: TagFormat.plainText,
|
|
3736
4864
|
chain: [
|
|
3737
4865
|
{
|
|
3738
4866
|
key: ConfigKey.tag_true,
|
|
3739
4867
|
jsonKey: "choices[]|set(isCorrect=true)",
|
|
4868
|
+
exportJsonKey: { choices: [{ choice: "$", isCorrect: true }] },
|
|
3740
4869
|
description: "True values for a true/false statement/question",
|
|
3741
|
-
maxCount: Count.infinity
|
|
4870
|
+
maxCount: Count.infinity,
|
|
4871
|
+
format: TagFormat.plainText
|
|
3742
4872
|
},
|
|
3743
4873
|
{
|
|
3744
4874
|
key: ConfigKey.tag_false,
|
|
3745
4875
|
jsonKey: "choices[]|set(isCorrect=false)",
|
|
4876
|
+
exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
|
|
3746
4877
|
description: "False values for a true/false statement/question",
|
|
3747
|
-
maxCount: Count.infinity
|
|
4878
|
+
maxCount: Count.infinity,
|
|
4879
|
+
format: TagFormat.plainText
|
|
4880
|
+
},
|
|
4881
|
+
{
|
|
4882
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
4883
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
4884
|
+
},
|
|
4885
|
+
{
|
|
4886
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.2: cascade-fired
|
|
4887
|
+
// `@example` on a `-` (incorrect choice) emits
|
|
4888
|
+
// `isExample: true` only — no `example` (BPG fixtures show
|
|
4889
|
+
// `isExample` on every choice, but `example` only on the
|
|
4890
|
+
// first correct via firstCorrectOnly cascade).
|
|
4891
|
+
// @card scope-shift writes choice-container isExample.
|
|
4892
|
+
key: ConfigKey.property_example,
|
|
4893
|
+
jsonKey: "example",
|
|
4894
|
+
exportJsonKey: [
|
|
4895
|
+
{
|
|
4896
|
+
"@keyonly": {
|
|
4897
|
+
isExample: true,
|
|
4898
|
+
example: "$parent.isCorrect",
|
|
4899
|
+
"@bit": { isExample: true },
|
|
4900
|
+
"@card": { isExample: true }
|
|
4901
|
+
}
|
|
4902
|
+
},
|
|
4903
|
+
{
|
|
4904
|
+
"@absent": {
|
|
4905
|
+
isExample: true,
|
|
4906
|
+
"@bit": { isExample: true },
|
|
4907
|
+
"@card": { isExample: true }
|
|
4908
|
+
}
|
|
4909
|
+
},
|
|
4910
|
+
{
|
|
4911
|
+
isExample: true,
|
|
4912
|
+
example: "$",
|
|
4913
|
+
"@bit": { isExample: true },
|
|
4914
|
+
"@card": { isExample: true }
|
|
4915
|
+
}
|
|
4916
|
+
],
|
|
4917
|
+
description: "An example for the true/false statement/question (incorrect entry \u2014 isExample only on cascade)",
|
|
4918
|
+
format: TagFormat.boolean,
|
|
4919
|
+
nullable: true
|
|
4920
|
+
}
|
|
4921
|
+
]
|
|
4922
|
+
}
|
|
4923
|
+
]
|
|
4924
|
+
},
|
|
4925
|
+
[ConfigKey.group_trueFalseResponses]: {
|
|
4926
|
+
type: GroupConfigType.standard,
|
|
4927
|
+
description: "True/False Responses chain",
|
|
4928
|
+
tags: [
|
|
4929
|
+
{
|
|
4930
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: true }] },
|
|
4931
|
+
key: ConfigKey.tag_true,
|
|
4932
|
+
description: "True value for a true/false statement/question",
|
|
4933
|
+
maxCount: Count.infinity,
|
|
4934
|
+
format: TagFormat.plainText,
|
|
4935
|
+
chain: [
|
|
4936
|
+
{
|
|
4937
|
+
key: ConfigKey.tag_true,
|
|
4938
|
+
jsonKey: "responses[]|set(isCorrect=true)",
|
|
4939
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: true }] },
|
|
4940
|
+
description: "True values for a true/false statement/question",
|
|
4941
|
+
maxCount: Count.infinity,
|
|
4942
|
+
format: TagFormat.plainText
|
|
4943
|
+
},
|
|
4944
|
+
{
|
|
4945
|
+
key: ConfigKey.tag_false,
|
|
4946
|
+
jsonKey: "responses[]|set(isCorrect=false)",
|
|
4947
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: false }] },
|
|
4948
|
+
description: "False values for a true/false statement/question",
|
|
4949
|
+
maxCount: Count.infinity,
|
|
4950
|
+
format: TagFormat.plainText
|
|
4951
|
+
},
|
|
4952
|
+
{
|
|
4953
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
4954
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
4955
|
+
},
|
|
4956
|
+
{
|
|
4957
|
+
// @card scope-shift writes response-container isExample.
|
|
4958
|
+
key: ConfigKey.property_example,
|
|
4959
|
+
jsonKey: "example",
|
|
4960
|
+
exportJsonKey: [
|
|
4961
|
+
{
|
|
4962
|
+
"@keyonly": {
|
|
4963
|
+
isExample: true,
|
|
4964
|
+
example: "$parent.isCorrect",
|
|
4965
|
+
"@bit": { isExample: true },
|
|
4966
|
+
"@card": { isExample: true }
|
|
4967
|
+
}
|
|
4968
|
+
},
|
|
4969
|
+
{
|
|
4970
|
+
"@absent": {
|
|
4971
|
+
isExample: "$parent.isCorrect",
|
|
4972
|
+
example: "$parent.isCorrect",
|
|
4973
|
+
"@bit": { isExample: "$parent.isCorrect" },
|
|
4974
|
+
"@card": { isExample: "$parent.isCorrect" }
|
|
4975
|
+
}
|
|
4976
|
+
},
|
|
4977
|
+
{
|
|
4978
|
+
isExample: true,
|
|
4979
|
+
example: "$",
|
|
4980
|
+
"@bit": { isExample: true },
|
|
4981
|
+
"@card": { isExample: true }
|
|
4982
|
+
}
|
|
4983
|
+
],
|
|
4984
|
+
description: "An example for the true/false statement/question",
|
|
4985
|
+
format: TagFormat.boolean,
|
|
4986
|
+
nullable: true
|
|
4987
|
+
}
|
|
4988
|
+
]
|
|
4989
|
+
},
|
|
4990
|
+
{
|
|
4991
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: false }] },
|
|
4992
|
+
key: ConfigKey.tag_false,
|
|
4993
|
+
description: "False value for a true/false statement/question",
|
|
4994
|
+
maxCount: Count.infinity,
|
|
4995
|
+
format: TagFormat.plainText,
|
|
4996
|
+
chain: [
|
|
4997
|
+
{
|
|
4998
|
+
key: ConfigKey.tag_true,
|
|
4999
|
+
jsonKey: "responses[]|set(isCorrect=true)",
|
|
5000
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: true }] },
|
|
5001
|
+
description: "True values for a true/false statement/question",
|
|
5002
|
+
maxCount: Count.infinity,
|
|
5003
|
+
format: TagFormat.plainText
|
|
5004
|
+
},
|
|
5005
|
+
{
|
|
5006
|
+
key: ConfigKey.tag_false,
|
|
5007
|
+
jsonKey: "responses[]|set(isCorrect=false)",
|
|
5008
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: false }] },
|
|
5009
|
+
description: "False values for a true/false statement/question",
|
|
5010
|
+
maxCount: Count.infinity,
|
|
5011
|
+
format: TagFormat.plainText
|
|
3748
5012
|
},
|
|
3749
5013
|
{
|
|
3750
5014
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3751
5015
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3752
5016
|
},
|
|
3753
5017
|
{
|
|
5018
|
+
// @card scope-shift writes response-container isExample.
|
|
3754
5019
|
key: ConfigKey.property_example,
|
|
3755
5020
|
jsonKey: "example",
|
|
5021
|
+
exportJsonKey: [
|
|
5022
|
+
{
|
|
5023
|
+
"@keyonly": {
|
|
5024
|
+
isExample: true,
|
|
5025
|
+
example: "$parent.isCorrect",
|
|
5026
|
+
"@bit": { isExample: true },
|
|
5027
|
+
"@card": { isExample: true }
|
|
5028
|
+
}
|
|
5029
|
+
},
|
|
5030
|
+
{
|
|
5031
|
+
"@absent": {
|
|
5032
|
+
isExample: true,
|
|
5033
|
+
example: "$parent.isCorrect",
|
|
5034
|
+
"@bit": { isExample: true },
|
|
5035
|
+
"@card": { isExample: true }
|
|
5036
|
+
}
|
|
5037
|
+
},
|
|
5038
|
+
{
|
|
5039
|
+
isExample: true,
|
|
5040
|
+
example: "$",
|
|
5041
|
+
"@bit": { isExample: true },
|
|
5042
|
+
"@card": { isExample: true }
|
|
5043
|
+
}
|
|
5044
|
+
],
|
|
3756
5045
|
description: "An example for the true/false statement/question",
|
|
5046
|
+
format: TagFormat.boolean,
|
|
5047
|
+
nullable: true
|
|
5048
|
+
}
|
|
5049
|
+
]
|
|
5050
|
+
}
|
|
5051
|
+
]
|
|
5052
|
+
},
|
|
5053
|
+
[ConfigKey.group_trueFalseInlineSelect]: {
|
|
5054
|
+
type: GroupConfigType.standard,
|
|
5055
|
+
description: "True/False chain composed inline (select body-bit). +/- tags are consume-only at bit level.",
|
|
5056
|
+
tags: [
|
|
5057
|
+
{
|
|
5058
|
+
exportJsonKey: {
|
|
5059
|
+
"@body-inline": {
|
|
5060
|
+
type: "select",
|
|
5061
|
+
attrs: { options: [{ text: "$", isCorrect: true }] }
|
|
5062
|
+
}
|
|
5063
|
+
},
|
|
5064
|
+
key: ConfigKey.tag_true,
|
|
5065
|
+
description: "True value for an inline select body bit",
|
|
5066
|
+
maxCount: Count.infinity,
|
|
5067
|
+
format: TagFormat.plainText,
|
|
5068
|
+
chain: [
|
|
5069
|
+
{
|
|
5070
|
+
key: ConfigKey.tag_true,
|
|
5071
|
+
exportJsonKey: {},
|
|
5072
|
+
description: "True values for an inline select body bit",
|
|
5073
|
+
maxCount: Count.infinity,
|
|
5074
|
+
format: TagFormat.plainText
|
|
5075
|
+
},
|
|
5076
|
+
{
|
|
5077
|
+
key: ConfigKey.tag_false,
|
|
5078
|
+
exportJsonKey: {},
|
|
5079
|
+
description: "False values for an inline select body bit",
|
|
5080
|
+
maxCount: Count.infinity,
|
|
5081
|
+
format: TagFormat.plainText
|
|
5082
|
+
},
|
|
5083
|
+
{
|
|
5084
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5085
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5086
|
+
},
|
|
5087
|
+
{
|
|
5088
|
+
// PLAN-083: cascade-fired `@example` from bit header fires
|
|
5089
|
+
// `isExample:true, example:true` on the FIRST CORRECT option
|
|
5090
|
+
// only (BPG `fillBooleanExample(select.options,
|
|
5091
|
+
// firstCorrectOnly=true)`). Mirrors group_trueFalseInlineHighlight.
|
|
5092
|
+
// Every rule also bubbles `@bit:{isExample:true}` (idempotent
|
|
5093
|
+
// OR — any cascade ⇒ bit marked) and
|
|
5094
|
+
// `@body-inline:{attrs:{isExample:true}}` (node-level marker
|
|
5095
|
+
// on the select node).
|
|
5096
|
+
key: ConfigKey.property_example,
|
|
5097
|
+
jsonKey: "example",
|
|
5098
|
+
exportJsonKey: [
|
|
5099
|
+
{
|
|
5100
|
+
"@keyonly": {
|
|
5101
|
+
isExample: true,
|
|
5102
|
+
example: "$parent.isCorrect",
|
|
5103
|
+
"@bit": { isExample: true },
|
|
5104
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5105
|
+
}
|
|
5106
|
+
},
|
|
5107
|
+
{
|
|
5108
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5109
|
+
maxEmits: 1,
|
|
5110
|
+
rule: {
|
|
5111
|
+
isExample: true,
|
|
5112
|
+
example: true,
|
|
5113
|
+
"@bit": { isExample: true },
|
|
5114
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5115
|
+
}
|
|
5116
|
+
},
|
|
5117
|
+
{
|
|
5118
|
+
isExample: true,
|
|
5119
|
+
example: "$",
|
|
5120
|
+
"@bit": { isExample: true },
|
|
5121
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5122
|
+
}
|
|
5123
|
+
],
|
|
5124
|
+
description: "An example for the inline select option (first correct only)",
|
|
5125
|
+
format: TagFormat.boolean,
|
|
5126
|
+
nullable: true
|
|
5127
|
+
}
|
|
5128
|
+
]
|
|
5129
|
+
},
|
|
5130
|
+
{
|
|
5131
|
+
exportJsonKey: {
|
|
5132
|
+
"@body-inline": {
|
|
5133
|
+
type: "select",
|
|
5134
|
+
attrs: { options: [{ text: "$", isCorrect: false }] }
|
|
5135
|
+
}
|
|
5136
|
+
},
|
|
5137
|
+
key: ConfigKey.tag_false,
|
|
5138
|
+
description: "False value for an inline select body bit",
|
|
5139
|
+
maxCount: Count.infinity,
|
|
5140
|
+
format: TagFormat.plainText,
|
|
5141
|
+
chain: [
|
|
5142
|
+
{
|
|
5143
|
+
key: ConfigKey.tag_true,
|
|
5144
|
+
exportJsonKey: {},
|
|
5145
|
+
description: "True values for an inline select body bit",
|
|
5146
|
+
maxCount: Count.infinity,
|
|
5147
|
+
format: TagFormat.plainText
|
|
5148
|
+
},
|
|
5149
|
+
{
|
|
5150
|
+
key: ConfigKey.tag_false,
|
|
5151
|
+
exportJsonKey: {},
|
|
5152
|
+
description: "False values for an inline select body bit",
|
|
5153
|
+
maxCount: Count.infinity,
|
|
5154
|
+
format: TagFormat.plainText
|
|
5155
|
+
},
|
|
5156
|
+
{
|
|
5157
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5158
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5159
|
+
},
|
|
5160
|
+
{
|
|
5161
|
+
// PLAN-083: identical to the `+` lead's chain @example —
|
|
5162
|
+
// cascade reaches the first correct option regardless of
|
|
5163
|
+
// which lead (+/-) opens the chain. Every firing rule bubbles
|
|
5164
|
+
// `@bit:{isExample:true}` and `@body-inline:{attrs:{isExample:true}}`.
|
|
5165
|
+
key: ConfigKey.property_example,
|
|
5166
|
+
jsonKey: "example",
|
|
5167
|
+
exportJsonKey: [
|
|
5168
|
+
{
|
|
5169
|
+
"@keyonly": {
|
|
5170
|
+
isExample: true,
|
|
5171
|
+
example: "$parent.isCorrect",
|
|
5172
|
+
"@bit": { isExample: true },
|
|
5173
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5174
|
+
}
|
|
5175
|
+
},
|
|
5176
|
+
{
|
|
5177
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5178
|
+
maxEmits: 1,
|
|
5179
|
+
rule: {
|
|
5180
|
+
isExample: true,
|
|
5181
|
+
example: true,
|
|
5182
|
+
"@bit": { isExample: true },
|
|
5183
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5184
|
+
}
|
|
5185
|
+
},
|
|
5186
|
+
{
|
|
5187
|
+
isExample: true,
|
|
5188
|
+
example: "$",
|
|
5189
|
+
"@bit": { isExample: true },
|
|
5190
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5191
|
+
}
|
|
5192
|
+
],
|
|
5193
|
+
description: "An example for the inline select option (first correct only)",
|
|
5194
|
+
format: TagFormat.boolean,
|
|
5195
|
+
nullable: true
|
|
5196
|
+
}
|
|
5197
|
+
]
|
|
5198
|
+
}
|
|
5199
|
+
]
|
|
5200
|
+
},
|
|
5201
|
+
[ConfigKey.group_trueFalseInlineHighlight]: {
|
|
5202
|
+
type: GroupConfigType.standard,
|
|
5203
|
+
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.',
|
|
5204
|
+
tags: [
|
|
5205
|
+
{
|
|
5206
|
+
exportJsonKey: {
|
|
5207
|
+
"@body-inline": {
|
|
5208
|
+
type: "highlight",
|
|
5209
|
+
attrs: { texts: [{ text: "$", isCorrect: true }] }
|
|
5210
|
+
}
|
|
5211
|
+
},
|
|
5212
|
+
key: ConfigKey.tag_true,
|
|
5213
|
+
description: "Highlighted span in the body (correct)",
|
|
5214
|
+
maxCount: Count.infinity,
|
|
5215
|
+
format: TagFormat.plainText,
|
|
5216
|
+
chain: [
|
|
5217
|
+
{
|
|
5218
|
+
key: ConfigKey.tag_true,
|
|
5219
|
+
exportJsonKey: {},
|
|
5220
|
+
description: "Highlighted span values (correct)",
|
|
5221
|
+
maxCount: Count.infinity,
|
|
5222
|
+
format: TagFormat.plainText
|
|
5223
|
+
},
|
|
5224
|
+
{
|
|
5225
|
+
key: ConfigKey.tag_false,
|
|
5226
|
+
exportJsonKey: {},
|
|
5227
|
+
description: "Highlighted span values (incorrect)",
|
|
5228
|
+
maxCount: Count.infinity,
|
|
5229
|
+
format: TagFormat.plainText
|
|
5230
|
+
},
|
|
5231
|
+
{
|
|
5232
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5233
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5234
|
+
},
|
|
5235
|
+
{
|
|
5236
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.13: cascade-fired
|
|
5237
|
+
// `@example` from the bit header fires `example: true` +
|
|
5238
|
+
// `isExample: true` on the FIRST correct highlight only
|
|
5239
|
+
// (BPG `fillBooleanExample(highlight.texts,
|
|
5240
|
+
// firstCorrectOnly=true)`). Incorrect highlights get
|
|
5241
|
+
// nothing (unlike choices, the highlight-text fixture
|
|
5242
|
+
// shows no `isExample` on incorrect entries).
|
|
5243
|
+
key: ConfigKey.property_example,
|
|
5244
|
+
jsonKey: "example",
|
|
5245
|
+
exportJsonKey: [
|
|
5246
|
+
{
|
|
5247
|
+
"@keyonly": {
|
|
5248
|
+
isExample: true,
|
|
5249
|
+
example: "$parent.isCorrect",
|
|
5250
|
+
"@bit": { isExample: true },
|
|
5251
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5252
|
+
}
|
|
5253
|
+
},
|
|
5254
|
+
{
|
|
5255
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5256
|
+
maxEmits: 1,
|
|
5257
|
+
rule: {
|
|
5258
|
+
isExample: true,
|
|
5259
|
+
example: true,
|
|
5260
|
+
"@bit": { isExample: true },
|
|
5261
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5262
|
+
}
|
|
5263
|
+
},
|
|
5264
|
+
{
|
|
5265
|
+
isExample: true,
|
|
5266
|
+
example: "$",
|
|
5267
|
+
"@bit": { isExample: true },
|
|
5268
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5269
|
+
}
|
|
5270
|
+
],
|
|
5271
|
+
description: "An example for the highlighted span (first correct only)",
|
|
5272
|
+
format: TagFormat.boolean,
|
|
5273
|
+
nullable: true
|
|
5274
|
+
}
|
|
5275
|
+
]
|
|
5276
|
+
},
|
|
5277
|
+
{
|
|
5278
|
+
// PLAN-083 follow-up (2026-05-22): mirror the select `-` lead shape
|
|
5279
|
+
// by writing `isCorrect: false`. Without it, `$parent.isCorrect` in
|
|
5280
|
+
// chain-child @example rules resolves to ParentPathMissing for `-`
|
|
5281
|
+
// entries (e.g. `[-fish][@example]`), so the @keyonly rule falls
|
|
5282
|
+
// through and nothing fires. The natural-default strip removes
|
|
5283
|
+
// `isCorrect: false` from the final texts entries (matches fixture).
|
|
5284
|
+
exportJsonKey: {
|
|
5285
|
+
"@body-inline": {
|
|
5286
|
+
type: "highlight",
|
|
5287
|
+
attrs: { texts: [{ text: "$", isCorrect: false }] }
|
|
5288
|
+
}
|
|
5289
|
+
},
|
|
5290
|
+
key: ConfigKey.tag_false,
|
|
5291
|
+
description: "Highlighted span in the body (incorrect)",
|
|
5292
|
+
maxCount: Count.infinity,
|
|
5293
|
+
format: TagFormat.plainText,
|
|
5294
|
+
chain: [
|
|
5295
|
+
{
|
|
5296
|
+
key: ConfigKey.tag_true,
|
|
5297
|
+
exportJsonKey: {},
|
|
5298
|
+
description: "Highlighted span values (correct)",
|
|
5299
|
+
maxCount: Count.infinity,
|
|
3757
5300
|
format: TagFormat.plainText
|
|
5301
|
+
},
|
|
5302
|
+
{
|
|
5303
|
+
key: ConfigKey.tag_false,
|
|
5304
|
+
exportJsonKey: {},
|
|
5305
|
+
description: "Highlighted span values (incorrect)",
|
|
5306
|
+
maxCount: Count.infinity,
|
|
5307
|
+
format: TagFormat.plainText
|
|
5308
|
+
},
|
|
5309
|
+
{
|
|
5310
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5311
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5312
|
+
},
|
|
5313
|
+
{
|
|
5314
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.13: cascade-fired
|
|
5315
|
+
// `@example` on a `-` (incorrect highlight) emits nothing
|
|
5316
|
+
// (highlight-text fixture has no `isExample` on incorrect
|
|
5317
|
+
// entries; firstCorrectOnly cascade skips them entirely).
|
|
5318
|
+
// No `@absent` rule.
|
|
5319
|
+
// PLAN-083: identical to the `+` lead's chain @example —
|
|
5320
|
+
// cascade reaches the first correct option regardless of
|
|
5321
|
+
// which lead (+/-) opens the chain.
|
|
5322
|
+
key: ConfigKey.property_example,
|
|
5323
|
+
jsonKey: "example",
|
|
5324
|
+
exportJsonKey: [
|
|
5325
|
+
{
|
|
5326
|
+
"@keyonly": {
|
|
5327
|
+
isExample: true,
|
|
5328
|
+
example: "$parent.isCorrect",
|
|
5329
|
+
"@bit": { isExample: true },
|
|
5330
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5331
|
+
}
|
|
5332
|
+
},
|
|
5333
|
+
{
|
|
5334
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5335
|
+
maxEmits: 1,
|
|
5336
|
+
rule: {
|
|
5337
|
+
isExample: true,
|
|
5338
|
+
example: true,
|
|
5339
|
+
"@bit": { isExample: true },
|
|
5340
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5341
|
+
}
|
|
5342
|
+
},
|
|
5343
|
+
{
|
|
5344
|
+
isExample: true,
|
|
5345
|
+
example: "$",
|
|
5346
|
+
"@bit": { isExample: true },
|
|
5347
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5348
|
+
}
|
|
5349
|
+
],
|
|
5350
|
+
description: "An example for the highlighted span (first correct only)",
|
|
5351
|
+
format: TagFormat.boolean,
|
|
5352
|
+
nullable: true
|
|
3758
5353
|
}
|
|
3759
5354
|
]
|
|
3760
5355
|
}
|
|
@@ -3767,6 +5362,7 @@ var GROUPS = {
|
|
|
3767
5362
|
{
|
|
3768
5363
|
key: ConfigKey.property_mark,
|
|
3769
5364
|
jsonKey: "marks.mark",
|
|
5365
|
+
exportJsonKey: { marks: [{ mark: "$" }] },
|
|
3770
5366
|
description: "The mark configuration",
|
|
3771
5367
|
format: TagFormat.plainText,
|
|
3772
5368
|
maxCount: Count.infinity,
|
|
@@ -3790,21 +5386,32 @@ var GROUPS = {
|
|
|
3790
5386
|
description: "Mark chain",
|
|
3791
5387
|
tags: [
|
|
3792
5388
|
{
|
|
5389
|
+
exportJsonKey: {
|
|
5390
|
+
"@body-inline": { type: "mark", attrs: { solution: "$" } }
|
|
5391
|
+
},
|
|
3793
5392
|
key: ConfigKey.tag_mark,
|
|
3794
5393
|
description: "The marked content",
|
|
3795
5394
|
maxCount: Count.infinity,
|
|
5395
|
+
format: TagFormat.plainText,
|
|
3796
5396
|
chain: [
|
|
3797
5397
|
{
|
|
3798
5398
|
key: ConfigKey.property_mark,
|
|
3799
5399
|
jsonKey: "mark",
|
|
5400
|
+
exportJsonKey: { mark: "$" },
|
|
3800
5401
|
description: "The mark configuration",
|
|
3801
5402
|
format: TagFormat.plainText
|
|
3802
5403
|
},
|
|
3803
5404
|
{
|
|
3804
5405
|
key: ConfigKey.property_example,
|
|
3805
5406
|
jsonKey: "example",
|
|
5407
|
+
exportJsonKey: [
|
|
5408
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
5409
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
5410
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
5411
|
+
],
|
|
3806
5412
|
description: "An example for the marked content",
|
|
3807
|
-
format: TagFormat.
|
|
5413
|
+
format: TagFormat.bitmarkText,
|
|
5414
|
+
nullable: true
|
|
3808
5415
|
}
|
|
3809
5416
|
]
|
|
3810
5417
|
}
|
|
@@ -3893,7 +5500,8 @@ var GROUPS = {
|
|
|
3893
5500
|
name: "Title",
|
|
3894
5501
|
description: "The title of the book",
|
|
3895
5502
|
maxCount: 2,
|
|
3896
|
-
jsonKey: "title|multi(count=2, key=subtitle)"
|
|
5503
|
+
jsonKey: "title|multi(count=2, key=subtitle)",
|
|
5504
|
+
exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
|
|
3897
5505
|
},
|
|
3898
5506
|
{
|
|
3899
5507
|
key: ConfigKey.property_subtype,
|
|
@@ -3909,6 +5517,7 @@ var GROUPS = {
|
|
|
3909
5517
|
{
|
|
3910
5518
|
key: ConfigKey.resource_coverImage,
|
|
3911
5519
|
jsonKey: "coverImage|resource(type=image, key=image)",
|
|
5520
|
+
exportJsonKey: { coverImage: { type: "image", image: { src: "$" } } },
|
|
3912
5521
|
description: "The cover image of the book",
|
|
3913
5522
|
chain: [
|
|
3914
5523
|
{
|
|
@@ -3926,6 +5535,7 @@ var GROUPS = {
|
|
|
3926
5535
|
{
|
|
3927
5536
|
key: ConfigKey.resource_backgroundImage,
|
|
3928
5537
|
jsonKey: "backgroundImage|resource(type=image, key=image)",
|
|
5538
|
+
exportJsonKey: { backgroundImage: { type: "image", image: { src: "$" } } },
|
|
3929
5539
|
description: "The background image of the book",
|
|
3930
5540
|
chain: [
|
|
3931
5541
|
{
|
|
@@ -4085,10 +5695,21 @@ var GROUPS = {
|
|
|
4085
5695
|
format: TagFormat.plainText,
|
|
4086
5696
|
chain: [
|
|
4087
5697
|
{
|
|
5698
|
+
exportJsonKey: { reference: "$" },
|
|
4088
5699
|
key: ConfigKey.tag_reference,
|
|
4089
5700
|
format: TagFormat.plainText,
|
|
4090
|
-
description: "The reference
|
|
4091
|
-
maxCount:
|
|
5701
|
+
description: "The reference for the book(s) in the learning path",
|
|
5702
|
+
maxCount: 1,
|
|
5703
|
+
chain: [
|
|
5704
|
+
{
|
|
5705
|
+
key: ConfigKey.tag_reference,
|
|
5706
|
+
jsonKey: "referenceEnd",
|
|
5707
|
+
exportJsonKey: { referenceEnd: "$" },
|
|
5708
|
+
format: TagFormat.plainText,
|
|
5709
|
+
description: "The referenceEnd for the book(s) in the learning path",
|
|
5710
|
+
maxCount: 1
|
|
5711
|
+
}
|
|
5712
|
+
]
|
|
4092
5713
|
}
|
|
4093
5714
|
]
|
|
4094
5715
|
}
|
|
@@ -4219,6 +5840,42 @@ var GROUPS = {
|
|
|
4219
5840
|
}
|
|
4220
5841
|
]
|
|
4221
5842
|
},
|
|
5843
|
+
[ConfigKey.group_backgroundWallpaper]: {
|
|
5844
|
+
type: GroupConfigType.standard,
|
|
5845
|
+
description: "Background wallpaper tags",
|
|
5846
|
+
tags: [
|
|
5847
|
+
{
|
|
5848
|
+
key: ConfigKey.resource_backgroundWallpaper,
|
|
5849
|
+
exportJsonKey: { backgroundWallpaper: { type: "image", image: { src: "$" } } },
|
|
5850
|
+
description: "Background wallpaper for the image, used to set a background for the image",
|
|
5851
|
+
chain: [
|
|
5852
|
+
{
|
|
5853
|
+
key: ConfigKey.group_resourceImageCommon,
|
|
5854
|
+
description: "Common resource image tags for images"
|
|
5855
|
+
}
|
|
5856
|
+
]
|
|
5857
|
+
}
|
|
5858
|
+
]
|
|
5859
|
+
},
|
|
5860
|
+
[ConfigKey.group_imageNoZoom]: {
|
|
5861
|
+
type: GroupConfigType.standard,
|
|
5862
|
+
description: "Image bit tags",
|
|
5863
|
+
tags: [
|
|
5864
|
+
{
|
|
5865
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
5866
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
5867
|
+
},
|
|
5868
|
+
{
|
|
5869
|
+
key: ConfigKey.group_resourceBitTags,
|
|
5870
|
+
description: "Resource bit tags for images, used to define additional properties for images"
|
|
5871
|
+
},
|
|
5872
|
+
{
|
|
5873
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
5874
|
+
description: "Resource image tags for images, used to attach images to the bit",
|
|
5875
|
+
minCount: 1
|
|
5876
|
+
}
|
|
5877
|
+
]
|
|
5878
|
+
},
|
|
4222
5879
|
//
|
|
4223
5880
|
// Resource groups
|
|
4224
5881
|
//
|
|
@@ -4228,6 +5885,8 @@ var GROUPS = {
|
|
|
4228
5885
|
tags: [
|
|
4229
5886
|
{
|
|
4230
5887
|
key: ConfigKey.resource_imagePlaceholder,
|
|
5888
|
+
jsonKey: "imagePlaceholder|resource(type=image, key=image)",
|
|
5889
|
+
exportJsonKey: { imagePlaceholder: { type: "image", image: { src: "$" } } },
|
|
4231
5890
|
description: "Placeholder image for the resource",
|
|
4232
5891
|
chain: [
|
|
4233
5892
|
{
|
|
@@ -4336,6 +5995,58 @@ var GROUPS = {
|
|
|
4336
5995
|
}
|
|
4337
5996
|
]
|
|
4338
5997
|
},
|
|
5998
|
+
[ConfigKey.group_resourceImageCommonNoZoom]: {
|
|
5999
|
+
type: GroupConfigType.standard,
|
|
6000
|
+
description: "Common properties for image resources where @zoomDisabled defaults to true",
|
|
6001
|
+
tags: [
|
|
6002
|
+
{
|
|
6003
|
+
key: ConfigKey.group_resourceCommon,
|
|
6004
|
+
description: "Common resource properties"
|
|
6005
|
+
},
|
|
6006
|
+
{
|
|
6007
|
+
key: ConfigKey.property_src1x,
|
|
6008
|
+
description: "The source URL for the image at 1x resolution",
|
|
6009
|
+
format: TagFormat.plainText
|
|
6010
|
+
},
|
|
6011
|
+
{
|
|
6012
|
+
key: ConfigKey.property_src2x,
|
|
6013
|
+
description: "The source URL for the image at 2x resolution",
|
|
6014
|
+
format: TagFormat.plainText
|
|
6015
|
+
},
|
|
6016
|
+
{
|
|
6017
|
+
key: ConfigKey.property_src3x,
|
|
6018
|
+
description: "The source URL for the image at 3x resolution",
|
|
6019
|
+
format: TagFormat.plainText
|
|
6020
|
+
},
|
|
6021
|
+
{
|
|
6022
|
+
key: ConfigKey.property_src4x,
|
|
6023
|
+
description: "The source URL for the image at 4x resolution",
|
|
6024
|
+
format: TagFormat.plainText
|
|
6025
|
+
},
|
|
6026
|
+
{
|
|
6027
|
+
key: ConfigKey.property_width,
|
|
6028
|
+
description: "The width of the image",
|
|
6029
|
+
format: TagFormat.number
|
|
6030
|
+
},
|
|
6031
|
+
{
|
|
6032
|
+
key: ConfigKey.property_height,
|
|
6033
|
+
description: "The height of the image",
|
|
6034
|
+
format: TagFormat.number
|
|
6035
|
+
},
|
|
6036
|
+
{
|
|
6037
|
+
key: ConfigKey.property_alt,
|
|
6038
|
+
description: "The alternative text for the image",
|
|
6039
|
+
format: TagFormat.plainText
|
|
6040
|
+
},
|
|
6041
|
+
// @zoomDisabled with a true default
|
|
6042
|
+
{
|
|
6043
|
+
key: ConfigKey.property_zoomDisabled,
|
|
6044
|
+
description: "If true, zooming is disabled for the image (defaults to true)",
|
|
6045
|
+
format: TagFormat.boolean,
|
|
6046
|
+
defaultValue: "true"
|
|
6047
|
+
}
|
|
6048
|
+
]
|
|
6049
|
+
},
|
|
4339
6050
|
[ConfigKey.group_resourceAudioCommon]: {
|
|
4340
6051
|
type: GroupConfigType.standard,
|
|
4341
6052
|
description: "Common properties for audio resources",
|
|
@@ -4412,6 +6123,7 @@ var GROUPS = {
|
|
|
4412
6123
|
{
|
|
4413
6124
|
key: ConfigKey.property_posterImage,
|
|
4414
6125
|
jsonKey: "posterImage.src",
|
|
6126
|
+
exportJsonKey: { posterImage: { src: "$" } },
|
|
4415
6127
|
description: "The poster image for the video",
|
|
4416
6128
|
format: TagFormat.plainText,
|
|
4417
6129
|
chain: [
|
|
@@ -4424,22 +6136,26 @@ var GROUPS = {
|
|
|
4424
6136
|
{
|
|
4425
6137
|
key: ConfigKey.property_src1x,
|
|
4426
6138
|
description: "The source URL for the video at 1x resolution",
|
|
4427
|
-
format: TagFormat.plainText
|
|
6139
|
+
format: TagFormat.plainText,
|
|
6140
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4428
6141
|
},
|
|
4429
6142
|
{
|
|
4430
6143
|
key: ConfigKey.property_src2x,
|
|
4431
6144
|
description: "The source URL for the video at 2x resolution",
|
|
4432
|
-
format: TagFormat.plainText
|
|
6145
|
+
format: TagFormat.plainText,
|
|
6146
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4433
6147
|
},
|
|
4434
6148
|
{
|
|
4435
6149
|
key: ConfigKey.property_src3x,
|
|
4436
6150
|
description: "The source URL for the video at 3x resolution",
|
|
4437
|
-
format: TagFormat.plainText
|
|
6151
|
+
format: TagFormat.plainText,
|
|
6152
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4438
6153
|
},
|
|
4439
6154
|
{
|
|
4440
6155
|
key: ConfigKey.property_src4x,
|
|
4441
6156
|
description: "The source URL for the video at 4x resolution",
|
|
4442
|
-
format: TagFormat.plainText
|
|
6157
|
+
format: TagFormat.plainText,
|
|
6158
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4443
6159
|
}
|
|
4444
6160
|
]
|
|
4445
6161
|
},
|
|
@@ -4452,6 +6168,7 @@ var GROUPS = {
|
|
|
4452
6168
|
tags: [
|
|
4453
6169
|
{
|
|
4454
6170
|
key: ConfigKey.resource_icon,
|
|
6171
|
+
exportJsonKey: { resource: { type: "icon", icon: { src: "$" } } },
|
|
4455
6172
|
description: "The icon resource",
|
|
4456
6173
|
chain: [
|
|
4457
6174
|
{
|
|
@@ -4468,6 +6185,7 @@ var GROUPS = {
|
|
|
4468
6185
|
tags: [
|
|
4469
6186
|
{
|
|
4470
6187
|
key: ConfigKey.resource_image,
|
|
6188
|
+
exportJsonKey: { resource: { type: "image", image: { src: "$" } } },
|
|
4471
6189
|
description: "The image resource",
|
|
4472
6190
|
chain: [
|
|
4473
6191
|
{
|
|
@@ -4478,12 +6196,30 @@ var GROUPS = {
|
|
|
4478
6196
|
}
|
|
4479
6197
|
]
|
|
4480
6198
|
},
|
|
6199
|
+
[ConfigKey.group_resourceImageNoZoom]: {
|
|
6200
|
+
type: GroupConfigType.resource,
|
|
6201
|
+
description: "Image resource where @zoomDisabled defaults to true",
|
|
6202
|
+
tags: [
|
|
6203
|
+
{
|
|
6204
|
+
key: ConfigKey.resource_image,
|
|
6205
|
+
exportJsonKey: { resource: { type: "image", image: { src: "$" } } },
|
|
6206
|
+
description: "The image resource (no-zoom default)",
|
|
6207
|
+
chain: [
|
|
6208
|
+
{
|
|
6209
|
+
key: ConfigKey.group_resourceImageCommonNoZoom,
|
|
6210
|
+
description: "Common image properties with @zoomDisabled defaulting to true"
|
|
6211
|
+
}
|
|
6212
|
+
]
|
|
6213
|
+
}
|
|
6214
|
+
]
|
|
6215
|
+
},
|
|
4481
6216
|
[ConfigKey.group_resourceImagePortrait]: {
|
|
4482
6217
|
type: GroupConfigType.resource,
|
|
4483
6218
|
description: "Portrait image resource",
|
|
4484
6219
|
tags: [
|
|
4485
6220
|
{
|
|
4486
6221
|
key: ConfigKey.resource_imagePortrait,
|
|
6222
|
+
exportJsonKey: { resource: { type: "image-portrait", imagePortrait: { src: "$" } } },
|
|
4487
6223
|
description: "The portrait image resource",
|
|
4488
6224
|
chain: [
|
|
4489
6225
|
{
|
|
@@ -4500,6 +6236,7 @@ var GROUPS = {
|
|
|
4500
6236
|
tags: [
|
|
4501
6237
|
{
|
|
4502
6238
|
key: ConfigKey.resource_imageLandscape,
|
|
6239
|
+
exportJsonKey: { resource: { type: "image-landscape", imageLandscape: { src: "$" } } },
|
|
4503
6240
|
description: "The landscape image resource",
|
|
4504
6241
|
chain: [
|
|
4505
6242
|
{
|
|
@@ -4516,6 +6253,7 @@ var GROUPS = {
|
|
|
4516
6253
|
tags: [
|
|
4517
6254
|
{
|
|
4518
6255
|
key: ConfigKey.resource_imageEmbed,
|
|
6256
|
+
exportJsonKey: { resource: { type: "image-embed", imageEmbed: { src: "$" } } },
|
|
4519
6257
|
description: "The embedded image resource",
|
|
4520
6258
|
chain: [
|
|
4521
6259
|
{
|
|
@@ -4532,6 +6270,7 @@ var GROUPS = {
|
|
|
4532
6270
|
tags: [
|
|
4533
6271
|
{
|
|
4534
6272
|
key: ConfigKey.resource_imageLink,
|
|
6273
|
+
exportJsonKey: { resource: { type: "image-link", imageLink: { url: "$" } } },
|
|
4535
6274
|
description: "The link to the image resource",
|
|
4536
6275
|
chain: [
|
|
4537
6276
|
{
|
|
@@ -4548,6 +6287,7 @@ var GROUPS = {
|
|
|
4548
6287
|
tags: [
|
|
4549
6288
|
{
|
|
4550
6289
|
key: ConfigKey.resource_audio,
|
|
6290
|
+
exportJsonKey: { resource: { type: "audio", audio: { src: "$" } } },
|
|
4551
6291
|
description: "The audio resource",
|
|
4552
6292
|
chain: [
|
|
4553
6293
|
{
|
|
@@ -4564,6 +6304,7 @@ var GROUPS = {
|
|
|
4564
6304
|
tags: [
|
|
4565
6305
|
{
|
|
4566
6306
|
key: ConfigKey.resource_audioEmbed,
|
|
6307
|
+
exportJsonKey: { resource: { type: "audio-embed", audioEmbed: { src: "$" } } },
|
|
4567
6308
|
description: "The embedded audio resource",
|
|
4568
6309
|
chain: [
|
|
4569
6310
|
{
|
|
@@ -4580,6 +6321,7 @@ var GROUPS = {
|
|
|
4580
6321
|
tags: [
|
|
4581
6322
|
{
|
|
4582
6323
|
key: ConfigKey.resource_audioLink,
|
|
6324
|
+
exportJsonKey: { resource: { type: "audio-link", audioLink: { url: "$" } } },
|
|
4583
6325
|
description: "The link to the audio resource",
|
|
4584
6326
|
chain: [
|
|
4585
6327
|
{
|
|
@@ -4596,6 +6338,7 @@ var GROUPS = {
|
|
|
4596
6338
|
tags: [
|
|
4597
6339
|
{
|
|
4598
6340
|
key: ConfigKey.resource_video,
|
|
6341
|
+
exportJsonKey: { resource: { type: "video", video: { src: "$" } } },
|
|
4599
6342
|
description: "The video resource",
|
|
4600
6343
|
chain: [
|
|
4601
6344
|
{
|
|
@@ -4612,6 +6355,7 @@ var GROUPS = {
|
|
|
4612
6355
|
tags: [
|
|
4613
6356
|
{
|
|
4614
6357
|
key: ConfigKey.resource_videoEmbed,
|
|
6358
|
+
exportJsonKey: { resource: { type: "video-embed", videoEmbed: { url: "$" } } },
|
|
4615
6359
|
description: "The embedded video resource",
|
|
4616
6360
|
chain: [
|
|
4617
6361
|
{
|
|
@@ -4628,6 +6372,7 @@ var GROUPS = {
|
|
|
4628
6372
|
tags: [
|
|
4629
6373
|
{
|
|
4630
6374
|
key: ConfigKey.resource_videoLink,
|
|
6375
|
+
exportJsonKey: { resource: { type: "video-link", videoLink: { url: "$" } } },
|
|
4631
6376
|
description: "The link to the video resource",
|
|
4632
6377
|
chain: [
|
|
4633
6378
|
{
|
|
@@ -4644,6 +6389,9 @@ var GROUPS = {
|
|
|
4644
6389
|
tags: [
|
|
4645
6390
|
{
|
|
4646
6391
|
key: ConfigKey.resource_stillImageFilmEmbed,
|
|
6392
|
+
exportJsonKey: {
|
|
6393
|
+
resource: { type: "still-image-film-embed", stillImageFilmEmbed: { url: "$" } }
|
|
6394
|
+
},
|
|
4647
6395
|
description: "The embedded still image film resource",
|
|
4648
6396
|
chain: [
|
|
4649
6397
|
{
|
|
@@ -4660,6 +6408,9 @@ var GROUPS = {
|
|
|
4660
6408
|
tags: [
|
|
4661
6409
|
{
|
|
4662
6410
|
key: ConfigKey.resource_stillImageFilmLink,
|
|
6411
|
+
exportJsonKey: {
|
|
6412
|
+
resource: { type: "still-image-film-link", stillImageFilmLink: { url: "$" } }
|
|
6413
|
+
},
|
|
4663
6414
|
description: "The link to the still image film resource",
|
|
4664
6415
|
chain: [
|
|
4665
6416
|
{
|
|
@@ -4676,6 +6427,7 @@ var GROUPS = {
|
|
|
4676
6427
|
tags: [
|
|
4677
6428
|
{
|
|
4678
6429
|
key: ConfigKey.resource_article,
|
|
6430
|
+
exportJsonKey: { resource: { type: "article", article: { body: "$" } } },
|
|
4679
6431
|
description: "The article resource",
|
|
4680
6432
|
chain: [
|
|
4681
6433
|
{
|
|
@@ -4692,6 +6444,7 @@ var GROUPS = {
|
|
|
4692
6444
|
tags: [
|
|
4693
6445
|
{
|
|
4694
6446
|
key: ConfigKey.resource_articleEmbed,
|
|
6447
|
+
exportJsonKey: { resource: { type: "article-embed", articleEmbed: { url: "$" } } },
|
|
4695
6448
|
description: "The embedded article resource",
|
|
4696
6449
|
chain: [
|
|
4697
6450
|
{
|
|
@@ -4708,6 +6461,7 @@ var GROUPS = {
|
|
|
4708
6461
|
tags: [
|
|
4709
6462
|
{
|
|
4710
6463
|
key: ConfigKey.resource_articleLink,
|
|
6464
|
+
exportJsonKey: { resource: { type: "article-link", articleLink: { url: "$" } } },
|
|
4711
6465
|
description: "The link to the article resource",
|
|
4712
6466
|
chain: [
|
|
4713
6467
|
{
|
|
@@ -4724,6 +6478,7 @@ var GROUPS = {
|
|
|
4724
6478
|
tags: [
|
|
4725
6479
|
{
|
|
4726
6480
|
key: ConfigKey.resource_document,
|
|
6481
|
+
exportJsonKey: { resource: { type: "document", document: { url: "$" } } },
|
|
4727
6482
|
description: "The document resource",
|
|
4728
6483
|
chain: [
|
|
4729
6484
|
{
|
|
@@ -4740,6 +6495,7 @@ var GROUPS = {
|
|
|
4740
6495
|
tags: [
|
|
4741
6496
|
{
|
|
4742
6497
|
key: ConfigKey.resource_documentEmbed,
|
|
6498
|
+
exportJsonKey: { resource: { type: "document-embed", documentEmbed: { url: "$" } } },
|
|
4743
6499
|
description: "The embedded document resource",
|
|
4744
6500
|
chain: [
|
|
4745
6501
|
{
|
|
@@ -4756,6 +6512,7 @@ var GROUPS = {
|
|
|
4756
6512
|
tags: [
|
|
4757
6513
|
{
|
|
4758
6514
|
key: ConfigKey.resource_documentLink,
|
|
6515
|
+
exportJsonKey: { resource: { type: "document-link", documentLink: { url: "$" } } },
|
|
4759
6516
|
description: "The link to the document resource",
|
|
4760
6517
|
chain: [
|
|
4761
6518
|
{
|
|
@@ -4772,6 +6529,7 @@ var GROUPS = {
|
|
|
4772
6529
|
tags: [
|
|
4773
6530
|
{
|
|
4774
6531
|
key: ConfigKey.resource_documentDownload,
|
|
6532
|
+
exportJsonKey: { resource: { type: "document-download", documentDownload: { url: "$" } } },
|
|
4775
6533
|
description: "The downloadable document resource",
|
|
4776
6534
|
chain: [
|
|
4777
6535
|
{
|
|
@@ -4788,6 +6546,7 @@ var GROUPS = {
|
|
|
4788
6546
|
tags: [
|
|
4789
6547
|
{
|
|
4790
6548
|
key: ConfigKey.resource_appLink,
|
|
6549
|
+
exportJsonKey: { resource: { type: "app-link", appLink: { url: "$" } } },
|
|
4791
6550
|
description: "The link to the app resource",
|
|
4792
6551
|
chain: [
|
|
4793
6552
|
{
|
|
@@ -4804,6 +6563,7 @@ var GROUPS = {
|
|
|
4804
6563
|
tags: [
|
|
4805
6564
|
{
|
|
4806
6565
|
key: ConfigKey.resource_websiteLink,
|
|
6566
|
+
exportJsonKey: { resource: { type: "website-link", websiteLink: { url: "$" } } },
|
|
4807
6567
|
description: "The link to the website resource",
|
|
4808
6568
|
chain: [
|
|
4809
6569
|
{
|
|
@@ -4862,6 +6622,7 @@ var GROUPS = {
|
|
|
4862
6622
|
{
|
|
4863
6623
|
key: ConfigKey.resource_previewImage,
|
|
4864
6624
|
jsonKey: "previewImage|resource(type=image, key=image)",
|
|
6625
|
+
exportJsonKey: { previewImage: { type: "image", image: { src: "$" } } },
|
|
4865
6626
|
description: "The preview image resource",
|
|
4866
6627
|
chain: [
|
|
4867
6628
|
{
|
|
@@ -4879,6 +6640,7 @@ var GROUPS = {
|
|
|
4879
6640
|
{
|
|
4880
6641
|
key: ConfigKey.resource_previewVideo,
|
|
4881
6642
|
jsonKey: "previewVideo|resource(type=video, key=video)",
|
|
6643
|
+
exportJsonKey: { previewVideo: { type: "video", video: { src: "$" } } },
|
|
4882
6644
|
description: "The preview video resource",
|
|
4883
6645
|
chain: [
|
|
4884
6646
|
{
|
|
@@ -4943,20 +6705,53 @@ var ConfigHydrator = class {
|
|
|
4943
6705
|
_side.name,
|
|
4944
6706
|
_side.repeat ?? false,
|
|
4945
6707
|
variantsOfSide,
|
|
4946
|
-
_side.jsonKey
|
|
6708
|
+
_side.jsonKey,
|
|
6709
|
+
_side.exportJsonKey,
|
|
6710
|
+
Object.prototype.hasOwnProperty.call(_side, "exportJsonKey")
|
|
4947
6711
|
);
|
|
4948
6712
|
sides.push(sideConfig);
|
|
4949
6713
|
}
|
|
4950
6714
|
const cardSetConfig = new CardSetConfig(
|
|
4951
6715
|
_cardSet,
|
|
4952
6716
|
_cardSetConfig.jsonKey,
|
|
4953
|
-
_cardSetConfig.
|
|
6717
|
+
_cardSetConfig.exportJsonKey,
|
|
6718
|
+
Object.prototype.hasOwnProperty.call(_cardSetConfig, "exportJsonKey"),
|
|
6719
|
+
this.hydrateCardSections(_cardSetConfig.sections),
|
|
4954
6720
|
sides
|
|
4955
6721
|
);
|
|
4956
6722
|
return cardSetConfig;
|
|
4957
6723
|
}
|
|
6724
|
+
hydrateCardSections(sections) {
|
|
6725
|
+
if (!sections) return void 0;
|
|
6726
|
+
const out = {};
|
|
6727
|
+
for (const [k, v] of Object.entries(sections)) {
|
|
6728
|
+
out[k] = {
|
|
6729
|
+
jsonKey: v.jsonKey,
|
|
6730
|
+
exportJsonKey: v.exportJsonKey,
|
|
6731
|
+
hasExportJsonKey: Object.prototype.hasOwnProperty.call(v, "exportJsonKey"),
|
|
6732
|
+
isDefault: v.isDefault,
|
|
6733
|
+
sideJsonKey: v.sideJsonKey,
|
|
6734
|
+
sideExportJsonKey: v.sideExportJsonKey,
|
|
6735
|
+
hasSideExportJsonKey: Object.prototype.hasOwnProperty.call(v, "sideExportJsonKey"),
|
|
6736
|
+
// PLAN-085: cardinality fields pass through; defaults applied
|
|
6737
|
+
// downstream by the config consumer (Rust treats `0` / undefined
|
|
6738
|
+
// as unbounded).
|
|
6739
|
+
minCount: v.minCount,
|
|
6740
|
+
maxCount: v.maxCount
|
|
6741
|
+
};
|
|
6742
|
+
}
|
|
6743
|
+
return out;
|
|
6744
|
+
}
|
|
4958
6745
|
hydrateTagConfig(_tag) {
|
|
4959
|
-
const {
|
|
6746
|
+
const {
|
|
6747
|
+
key: _configKey,
|
|
6748
|
+
maxCount,
|
|
6749
|
+
minCount,
|
|
6750
|
+
chain: _chain,
|
|
6751
|
+
deprecated,
|
|
6752
|
+
jsonKey,
|
|
6753
|
+
exportJsonKey
|
|
6754
|
+
} = _tag;
|
|
4960
6755
|
const configKey = (0, import_superenum15.Enum)(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
|
|
4961
6756
|
if (!configKey) throw new Error(`No tag key found for config key '${configKey}'`);
|
|
4962
6757
|
const tag = (0, import_superenum15.Enum)(Tag).fromValue(configKey);
|
|
@@ -4971,6 +6766,9 @@ var ConfigHydrator = class {
|
|
|
4971
6766
|
maxCount: maxCount ?? MAX_COUNT_DEFAULT,
|
|
4972
6767
|
minCount: minCount ?? MIN_COUNT_DEFAULT,
|
|
4973
6768
|
chain,
|
|
6769
|
+
jsonKey,
|
|
6770
|
+
exportJsonKey,
|
|
6771
|
+
hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
|
|
4974
6772
|
deprecated
|
|
4975
6773
|
});
|
|
4976
6774
|
return {
|
|
@@ -4989,7 +6787,8 @@ var ConfigHydrator = class {
|
|
|
4989
6787
|
format,
|
|
4990
6788
|
values,
|
|
4991
6789
|
defaultValue,
|
|
4992
|
-
jsonKey
|
|
6790
|
+
jsonKey,
|
|
6791
|
+
exportJsonKey
|
|
4993
6792
|
} = _tag;
|
|
4994
6793
|
const configKey = (0, import_superenum15.Enum)(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
|
|
4995
6794
|
if (!configKey) throw new Error(`No property key found for config key '${configKey}'`);
|
|
@@ -5005,6 +6804,8 @@ var ConfigHydrator = class {
|
|
|
5005
6804
|
minCount: minCount ?? MIN_COUNT_DEFAULT,
|
|
5006
6805
|
chain,
|
|
5007
6806
|
jsonKey,
|
|
6807
|
+
exportJsonKey,
|
|
6808
|
+
hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
|
|
5008
6809
|
format,
|
|
5009
6810
|
values,
|
|
5010
6811
|
defaultValue,
|
|
@@ -5017,7 +6818,15 @@ var ConfigHydrator = class {
|
|
|
5017
6818
|
};
|
|
5018
6819
|
}
|
|
5019
6820
|
hydrateResourceTagConfig(_tag) {
|
|
5020
|
-
const {
|
|
6821
|
+
const {
|
|
6822
|
+
key: _configKey,
|
|
6823
|
+
maxCount,
|
|
6824
|
+
minCount,
|
|
6825
|
+
chain: _chain,
|
|
6826
|
+
deprecated,
|
|
6827
|
+
jsonKey,
|
|
6828
|
+
exportJsonKey
|
|
6829
|
+
} = _tag;
|
|
5021
6830
|
const configKey = (0, import_superenum15.Enum)(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
|
|
5022
6831
|
if (!configKey) throw new Error(`No resource key found for config key '${configKey}'`);
|
|
5023
6832
|
const tag = _configKey.substring(1);
|
|
@@ -5032,6 +6841,8 @@ var ConfigHydrator = class {
|
|
|
5032
6841
|
minCount: minCount ?? MIN_COUNT_DEFAULT,
|
|
5033
6842
|
chain,
|
|
5034
6843
|
jsonKey,
|
|
6844
|
+
exportJsonKey,
|
|
6845
|
+
hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
|
|
5035
6846
|
deprecated
|
|
5036
6847
|
});
|
|
5037
6848
|
return {
|
|
@@ -5063,14 +6874,25 @@ var ConfigHydrator = class {
|
|
|
5063
6874
|
};
|
|
5064
6875
|
}
|
|
5065
6876
|
hydrateCardVariantConfig(_variant) {
|
|
5066
|
-
const {
|
|
6877
|
+
const {
|
|
6878
|
+
tags: _tags,
|
|
6879
|
+
bodyAllowed,
|
|
6880
|
+
bodyRequired,
|
|
6881
|
+
repeatCount,
|
|
6882
|
+
jsonKey,
|
|
6883
|
+
exportJsonKey,
|
|
6884
|
+
format
|
|
6885
|
+
} = _variant;
|
|
5067
6886
|
const tags2 = this.hydrateTagsConfig(_tags);
|
|
5068
6887
|
const cardSetConfig = new CardVariantConfig(
|
|
5069
6888
|
tags2.tags,
|
|
5070
6889
|
bodyAllowed,
|
|
5071
6890
|
bodyRequired,
|
|
5072
6891
|
repeatCount,
|
|
5073
|
-
jsonKey
|
|
6892
|
+
jsonKey,
|
|
6893
|
+
exportJsonKey,
|
|
6894
|
+
Object.prototype.hasOwnProperty.call(_variant, "exportJsonKey"),
|
|
6895
|
+
format
|
|
5074
6896
|
);
|
|
5075
6897
|
return cardSetConfig;
|
|
5076
6898
|
}
|
|
@@ -5108,6 +6930,7 @@ var BITS = {
|
|
|
5108
6930
|
description: "Common tags for quiz bits"
|
|
5109
6931
|
},
|
|
5110
6932
|
{
|
|
6933
|
+
exportJsonKey: { title: "$" },
|
|
5111
6934
|
key: ConfigKey.tag_title,
|
|
5112
6935
|
description: "The title of the flashcard quiz"
|
|
5113
6936
|
},
|
|
@@ -5116,6 +6939,21 @@ var BITS = {
|
|
|
5116
6939
|
description: "The flashcard set to use for the app flashcards",
|
|
5117
6940
|
format: TagFormat.plainText,
|
|
5118
6941
|
maxCount: Count.infinity
|
|
6942
|
+
},
|
|
6943
|
+
{
|
|
6944
|
+
// Override inherited @example from group_standardTags: string root
|
|
6945
|
+
// example. Bare/synthesized emits `example: "true"` (a text literal
|
|
6946
|
+
// that field-coerces to a paragraph "true" in bitmark+ contexts);
|
|
6947
|
+
// valued [@example:text] emits the user's text via `$`.
|
|
6948
|
+
key: ConfigKey.property_example,
|
|
6949
|
+
exportJsonKey: [
|
|
6950
|
+
{ "@keyonly": { isExample: true, example: "true" } },
|
|
6951
|
+
{ "@absent": { isExample: true, example: "true" } },
|
|
6952
|
+
{ isExample: true, example: "$" }
|
|
6953
|
+
],
|
|
6954
|
+
description: "The example text for the bit",
|
|
6955
|
+
format: TagFormat.plainText,
|
|
6956
|
+
nullable: true
|
|
5119
6957
|
}
|
|
5120
6958
|
],
|
|
5121
6959
|
rootExampleType: ExampleType.string
|
|
@@ -5197,6 +7035,7 @@ var BITS = {
|
|
|
5197
7035
|
description: "Article bit, used for articles / paragraphs",
|
|
5198
7036
|
tags: [
|
|
5199
7037
|
{
|
|
7038
|
+
exportJsonKey: { title: "$" },
|
|
5200
7039
|
key: ConfigKey.tag_title,
|
|
5201
7040
|
description: "The title of the article"
|
|
5202
7041
|
}
|
|
@@ -5304,7 +7143,8 @@ var BITS = {
|
|
|
5304
7143
|
key: ConfigKey.tag_title,
|
|
5305
7144
|
description: "Title and subtitle of the catalog item",
|
|
5306
7145
|
maxCount: 2,
|
|
5307
|
-
jsonKey: "title|multi(count=2, key=subtitle)"
|
|
7146
|
+
jsonKey: "title|multi(count=2, key=subtitle)",
|
|
7147
|
+
exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
|
|
5308
7148
|
},
|
|
5309
7149
|
{
|
|
5310
7150
|
key: ConfigKey.property_coverImage,
|
|
@@ -5314,6 +7154,7 @@ var BITS = {
|
|
|
5314
7154
|
{
|
|
5315
7155
|
key: ConfigKey.resource_coverImage,
|
|
5316
7156
|
jsonKey: "coverImage|resource(type=image, key=image)",
|
|
7157
|
+
exportJsonKey: { coverImage: { type: "image", image: { src: "$" } } },
|
|
5317
7158
|
description: "Cover image of the catalog item",
|
|
5318
7159
|
chain: [
|
|
5319
7160
|
{
|
|
@@ -5441,6 +7282,18 @@ var BITS = {
|
|
|
5441
7282
|
key: ConfigKey.group_previewVideos,
|
|
5442
7283
|
description: "Array of preview videos for the catalog item",
|
|
5443
7284
|
maxCount: Count.infinity
|
|
7285
|
+
},
|
|
7286
|
+
{
|
|
7287
|
+
// Override inherited @example from group_standardTags: string root example.
|
|
7288
|
+
key: ConfigKey.property_example,
|
|
7289
|
+
exportJsonKey: [
|
|
7290
|
+
{ "@keyonly": { isExample: true, example: "true" } },
|
|
7291
|
+
{ "@absent": { isExample: true, example: "true" } },
|
|
7292
|
+
{ isExample: true, example: "$" }
|
|
7293
|
+
],
|
|
7294
|
+
description: "The example text for the bit",
|
|
7295
|
+
format: TagFormat.plainText,
|
|
7296
|
+
nullable: true
|
|
5444
7297
|
}
|
|
5445
7298
|
],
|
|
5446
7299
|
rootExampleType: ExampleType.string
|
|
@@ -5454,7 +7307,8 @@ var BITS = {
|
|
|
5454
7307
|
key: ConfigKey.tag_title,
|
|
5455
7308
|
description: "Title and subtitle of the catalog item",
|
|
5456
7309
|
maxCount: 2,
|
|
5457
|
-
jsonKey: "title|multi(count=2, key=subtitle)"
|
|
7310
|
+
jsonKey: "title|multi(count=2, key=subtitle)",
|
|
7311
|
+
exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
|
|
5458
7312
|
},
|
|
5459
7313
|
{
|
|
5460
7314
|
key: ConfigKey.property_coverImage,
|
|
@@ -5464,6 +7318,7 @@ var BITS = {
|
|
|
5464
7318
|
{
|
|
5465
7319
|
key: ConfigKey.resource_coverImage,
|
|
5466
7320
|
jsonKey: "coverImage|resource(type=image, key=image)",
|
|
7321
|
+
exportJsonKey: { coverImage: { type: "image", image: { src: "$" } } },
|
|
5467
7322
|
description: "Cover image of the catalog item",
|
|
5468
7323
|
chain: [
|
|
5469
7324
|
{
|
|
@@ -5591,6 +7446,18 @@ var BITS = {
|
|
|
5591
7446
|
key: ConfigKey.group_previewVideos,
|
|
5592
7447
|
description: "Array of preview videos for the catalog item",
|
|
5593
7448
|
maxCount: Count.infinity
|
|
7449
|
+
},
|
|
7450
|
+
{
|
|
7451
|
+
// Override inherited @example from group_standardTags: string root example.
|
|
7452
|
+
key: ConfigKey.property_example,
|
|
7453
|
+
exportJsonKey: [
|
|
7454
|
+
{ "@keyonly": { isExample: true, example: "true" } },
|
|
7455
|
+
{ "@absent": { isExample: true, example: "true" } },
|
|
7456
|
+
{ isExample: true, example: "$" }
|
|
7457
|
+
],
|
|
7458
|
+
description: "The example text for the bit",
|
|
7459
|
+
format: TagFormat.plainText,
|
|
7460
|
+
nullable: true
|
|
5594
7461
|
}
|
|
5595
7462
|
],
|
|
5596
7463
|
rootExampleType: ExampleType.string
|
|
@@ -5604,7 +7471,8 @@ var BITS = {
|
|
|
5604
7471
|
key: ConfigKey.tag_title,
|
|
5605
7472
|
description: "Title and subtitle of the catalog item",
|
|
5606
7473
|
maxCount: 2,
|
|
5607
|
-
jsonKey: "title|multi(count=2, key=subtitle)"
|
|
7474
|
+
jsonKey: "title|multi(count=2, key=subtitle)",
|
|
7475
|
+
exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
|
|
5608
7476
|
},
|
|
5609
7477
|
{
|
|
5610
7478
|
key: ConfigKey.property_coverImage,
|
|
@@ -5730,6 +7598,18 @@ var BITS = {
|
|
|
5730
7598
|
key: ConfigKey.group_previewVideos,
|
|
5731
7599
|
description: "Array of preview videos for the catalog item",
|
|
5732
7600
|
maxCount: Count.infinity
|
|
7601
|
+
},
|
|
7602
|
+
{
|
|
7603
|
+
// Override inherited @example from group_standardTags: string root example.
|
|
7604
|
+
key: ConfigKey.property_example,
|
|
7605
|
+
exportJsonKey: [
|
|
7606
|
+
{ "@keyonly": { isExample: true, example: "true" } },
|
|
7607
|
+
{ "@absent": { isExample: true, example: "true" } },
|
|
7608
|
+
{ isExample: true, example: "$" }
|
|
7609
|
+
],
|
|
7610
|
+
description: "The example text for the bit",
|
|
7611
|
+
format: TagFormat.plainText,
|
|
7612
|
+
nullable: true
|
|
5733
7613
|
}
|
|
5734
7614
|
],
|
|
5735
7615
|
rootExampleType: ExampleType.string
|
|
@@ -5931,11 +7811,13 @@ var BITS = {
|
|
|
5931
7811
|
description: "Bit alias, used to create an alias for a bit",
|
|
5932
7812
|
tags: [
|
|
5933
7813
|
{
|
|
7814
|
+
exportJsonKey: { reference: "$" },
|
|
5934
7815
|
key: ConfigKey.tag_reference,
|
|
5935
7816
|
format: TagFormat.plainText,
|
|
5936
7817
|
description: "The reference to the bit that this alias points to"
|
|
5937
7818
|
},
|
|
5938
7819
|
{
|
|
7820
|
+
exportJsonKey: { anchor: "$" },
|
|
5939
7821
|
key: ConfigKey.tag_anchor,
|
|
5940
7822
|
format: TagFormat.plainText,
|
|
5941
7823
|
description: "The anchor for the bit alias, used for linking"
|
|
@@ -6137,7 +8019,8 @@ var BITS = {
|
|
|
6137
8019
|
description: "The title of the book cover",
|
|
6138
8020
|
maxCount: 2,
|
|
6139
8021
|
// title & subtitle
|
|
6140
|
-
jsonKey: "title|multi(count=2, key=subtitle)"
|
|
8022
|
+
jsonKey: "title|multi(count=2, key=subtitle)",
|
|
8023
|
+
exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
|
|
6141
8024
|
},
|
|
6142
8025
|
{
|
|
6143
8026
|
key: ConfigKey.property_coverColor,
|
|
@@ -6281,6 +8164,7 @@ var BITS = {
|
|
|
6281
8164
|
description: "Chapter bit, used to define chapters in books or articles",
|
|
6282
8165
|
tags: [
|
|
6283
8166
|
{
|
|
8167
|
+
exportJsonKey: { anchor: "$" },
|
|
6284
8168
|
key: ConfigKey.tag_anchor,
|
|
6285
8169
|
format: TagFormat.plainText,
|
|
6286
8170
|
description: "The anchor for the chapter, used for linking"
|
|
@@ -6288,7 +8172,8 @@ var BITS = {
|
|
|
6288
8172
|
{
|
|
6289
8173
|
key: ConfigKey.tag_title,
|
|
6290
8174
|
description: "The title of the chapter",
|
|
6291
|
-
jsonKey: "title|setMulti(level)"
|
|
8175
|
+
jsonKey: "title|setMulti(level)",
|
|
8176
|
+
exportJsonKey: { title: "$", level: "$level" }
|
|
6292
8177
|
},
|
|
6293
8178
|
{
|
|
6294
8179
|
key: ConfigKey.property_toc,
|
|
@@ -6319,8 +8204,31 @@ var BITS = {
|
|
|
6319
8204
|
description: "Tags for gaps in cloze and multiple choice text bits"
|
|
6320
8205
|
},
|
|
6321
8206
|
{
|
|
6322
|
-
key: ConfigKey.
|
|
8207
|
+
key: ConfigKey.group_trueFalseInlineSelect,
|
|
6323
8208
|
description: "Tags for true/false questions in cloze and multiple choice text bits"
|
|
8209
|
+
},
|
|
8210
|
+
{
|
|
8211
|
+
// Bit-level @isCaseSensitive — empty exportJsonKey (no bit-level emission);
|
|
8212
|
+
// defaultValue 'true' phantom-fires onto the ancestor stack so the gap chain's
|
|
8213
|
+
// `@absent: $ancestor` rule resolves to true. Mirrors BPG Builder.ts:1643-1652
|
|
8214
|
+
// `pushDownTree(... 'isCaseSensitive', data.isCaseSensitive ?? true)` for cloze bits.
|
|
8215
|
+
key: ConfigKey.property_isCaseSensitive,
|
|
8216
|
+
exportJsonKey: {},
|
|
8217
|
+
description: "If the cloze answers are case sensitive",
|
|
8218
|
+
format: TagFormat.boolean,
|
|
8219
|
+
defaultValue: "true"
|
|
8220
|
+
},
|
|
8221
|
+
{
|
|
8222
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
8223
|
+
key: ConfigKey.property_example,
|
|
8224
|
+
exportJsonKey: [
|
|
8225
|
+
{ "@keyonly": { isExample: true } },
|
|
8226
|
+
{ "@absent": { isExample: true } },
|
|
8227
|
+
{ isExample: true, example: "$" }
|
|
8228
|
+
],
|
|
8229
|
+
description: "The example(s) for the bit",
|
|
8230
|
+
format: TagFormat.bitmarkText,
|
|
8231
|
+
nullable: true
|
|
6324
8232
|
}
|
|
6325
8233
|
]
|
|
6326
8234
|
},
|
|
@@ -6341,6 +8249,7 @@ var BITS = {
|
|
|
6341
8249
|
},
|
|
6342
8250
|
{
|
|
6343
8251
|
key: ConfigKey.property_isCaseSensitive,
|
|
8252
|
+
exportJsonKey: {},
|
|
6344
8253
|
description: "If the cloze answers are case sensitive",
|
|
6345
8254
|
format: TagFormat.boolean,
|
|
6346
8255
|
defaultValue: "true"
|
|
@@ -6358,18 +8267,56 @@ var BITS = {
|
|
|
6358
8267
|
{
|
|
6359
8268
|
key: ConfigKey.group_gap,
|
|
6360
8269
|
description: "Tags for gaps in cloze bits"
|
|
8270
|
+
},
|
|
8271
|
+
{
|
|
8272
|
+
// Override inherited @example: cloze is in OLD parser's
|
|
8273
|
+
// `isTopLevelExample` allow-list, so [@example] at bit-header
|
|
8274
|
+
// emits `isExample: true`.
|
|
8275
|
+
key: ConfigKey.property_example,
|
|
8276
|
+
exportJsonKey: [
|
|
8277
|
+
{ "@keyonly": { isExample: true } },
|
|
8278
|
+
{ "@absent": { isExample: true } },
|
|
8279
|
+
{ isExample: true, example: "$" }
|
|
8280
|
+
],
|
|
8281
|
+
description: "The example(s) for the bit",
|
|
8282
|
+
format: TagFormat.bitmarkText,
|
|
8283
|
+
nullable: true
|
|
6361
8284
|
}
|
|
6362
8285
|
]
|
|
6363
8286
|
},
|
|
6364
8287
|
[BitType2.clozeInstructionGrouped]: {
|
|
6365
8288
|
since: "1.3.0",
|
|
6366
8289
|
baseBitType: BitType2.cloze,
|
|
6367
|
-
description: "Cloze instruction grouped bit, used for cloze questions with grouped instructions"
|
|
8290
|
+
description: "Cloze instruction grouped bit, used for cloze questions with grouped instructions",
|
|
8291
|
+
tags: [
|
|
8292
|
+
{
|
|
8293
|
+
key: ConfigKey.property_quizCountItems,
|
|
8294
|
+
description: "The number of items in the cloze quiz (instruction-grouped default: true)",
|
|
8295
|
+
format: TagFormat.boolean,
|
|
8296
|
+
defaultValue: "true"
|
|
8297
|
+
}
|
|
8298
|
+
// Note: quizStrikethroughSolutions defaults to false for instruction-grouped per OLD
|
|
8299
|
+
// JsonGenerator.ts:1689-1690, which equals the Boolean natural default → no override needed.
|
|
8300
|
+
]
|
|
6368
8301
|
},
|
|
6369
8302
|
[BitType2.clozeSolutionGrouped]: {
|
|
6370
8303
|
since: "1.3.0",
|
|
6371
8304
|
baseBitType: BitType2.cloze,
|
|
6372
|
-
description: "Cloze solution grouped bit, used for cloze questions with grouped solutions"
|
|
8305
|
+
description: "Cloze solution grouped bit, used for cloze questions with grouped solutions",
|
|
8306
|
+
tags: [
|
|
8307
|
+
{
|
|
8308
|
+
key: ConfigKey.property_quizCountItems,
|
|
8309
|
+
description: "The number of items in the cloze quiz (solution-grouped default: true)",
|
|
8310
|
+
format: TagFormat.boolean,
|
|
8311
|
+
defaultValue: "true"
|
|
8312
|
+
},
|
|
8313
|
+
{
|
|
8314
|
+
key: ConfigKey.property_quizStrikethroughSolutions,
|
|
8315
|
+
description: "If the cloze solutions should be strikethrough (solution-grouped default: true)",
|
|
8316
|
+
format: TagFormat.boolean,
|
|
8317
|
+
defaultValue: "true"
|
|
8318
|
+
}
|
|
8319
|
+
]
|
|
6373
8320
|
},
|
|
6374
8321
|
[BitType2.clozeSeveral]: {
|
|
6375
8322
|
since: "3.5.0",
|
|
@@ -6405,6 +8352,17 @@ var BITS = {
|
|
|
6405
8352
|
{
|
|
6406
8353
|
key: ConfigKey.group_quizCommon,
|
|
6407
8354
|
description: "Common tags for quiz bits"
|
|
8355
|
+
},
|
|
8356
|
+
{
|
|
8357
|
+
// PLAN-084 (R12): bit-level @isCaseSensitive — empty exportJsonKey
|
|
8358
|
+
// (no bit-level emission); defaultValue 'true' phantom-fires onto
|
|
8359
|
+
// the ancestor stack so each listItem's gap chain `@absent: $ancestor`
|
|
8360
|
+
// rule resolves to true. Mirrors the cloze bit (bits.ts:1326-1336).
|
|
8361
|
+
key: ConfigKey.property_isCaseSensitive,
|
|
8362
|
+
exportJsonKey: {},
|
|
8363
|
+
description: "If the cloze answers are case sensitive",
|
|
8364
|
+
format: TagFormat.boolean,
|
|
8365
|
+
defaultValue: "true"
|
|
6408
8366
|
}
|
|
6409
8367
|
],
|
|
6410
8368
|
cardSet: CardSetConfigKey.clozeList
|
|
@@ -6438,6 +8396,11 @@ var BITS = {
|
|
|
6438
8396
|
description: "Formula bit, used for mathematical formulas in articles or documents",
|
|
6439
8397
|
textFormatDefault: TextFormat2.latex
|
|
6440
8398
|
},
|
|
8399
|
+
[BitType2.formulaImage]: {
|
|
8400
|
+
since: "5.23.0",
|
|
8401
|
+
baseBitType: BitType2.formula,
|
|
8402
|
+
description: "Formula image bit, used for mathematical formulas rendered as images"
|
|
8403
|
+
},
|
|
6441
8404
|
[BitType2.smartStandardFormula]: {
|
|
6442
8405
|
since: "3.11.0",
|
|
6443
8406
|
baseBitType: BitType2.formula,
|
|
@@ -6566,6 +8529,7 @@ var BITS = {
|
|
|
6566
8529
|
tags: [
|
|
6567
8530
|
{
|
|
6568
8531
|
key: ConfigKey.group_person,
|
|
8532
|
+
exportJsonKey: { partner: { name: "$" } },
|
|
6569
8533
|
description: "Tags for the person in the conversation"
|
|
6570
8534
|
}
|
|
6571
8535
|
]
|
|
@@ -6790,6 +8754,7 @@ var BITS = {
|
|
|
6790
8754
|
{
|
|
6791
8755
|
key: ConfigKey.property_servings,
|
|
6792
8756
|
jsonKey: "servings.servings",
|
|
8757
|
+
exportJsonKey: { servings: { servings: "$" } },
|
|
6793
8758
|
description: "The number of servings for the ingredients",
|
|
6794
8759
|
format: TagFormat.number,
|
|
6795
8760
|
chain: [
|
|
@@ -6815,6 +8780,7 @@ var BITS = {
|
|
|
6815
8780
|
format: TagFormat.boolean
|
|
6816
8781
|
},
|
|
6817
8782
|
{
|
|
8783
|
+
exportJsonKey: { hint: "$" },
|
|
6818
8784
|
key: ConfigKey.tag_hint,
|
|
6819
8785
|
description: "Hint for the ingredient, used to provide additional information",
|
|
6820
8786
|
format: TagFormat.plainText
|
|
@@ -6992,6 +8958,18 @@ var BITS = {
|
|
|
6992
8958
|
description: "Reference for the essay, used to link to external resources",
|
|
6993
8959
|
format: TagFormat.plainText,
|
|
6994
8960
|
maxCount: Count.infinity
|
|
8961
|
+
},
|
|
8962
|
+
{
|
|
8963
|
+
// Override inherited @example from group_standardTags: string root example.
|
|
8964
|
+
key: ConfigKey.property_example,
|
|
8965
|
+
exportJsonKey: [
|
|
8966
|
+
{ "@keyonly": { isExample: true, example: "true" } },
|
|
8967
|
+
{ "@absent": { isExample: true, example: "true" } },
|
|
8968
|
+
{ isExample: true, example: "$" }
|
|
8969
|
+
],
|
|
8970
|
+
description: "The example text for the essay bit",
|
|
8971
|
+
format: TagFormat.plainText,
|
|
8972
|
+
nullable: true
|
|
6995
8973
|
}
|
|
6996
8974
|
],
|
|
6997
8975
|
rootExampleType: ExampleType.string
|
|
@@ -7012,8 +8990,21 @@ var BITS = {
|
|
|
7012
8990
|
description: "Example bit, used to provide examples in articles or books",
|
|
7013
8991
|
tags: [
|
|
7014
8992
|
{
|
|
8993
|
+
exportJsonKey: { title: "$" },
|
|
7015
8994
|
key: ConfigKey.tag_title,
|
|
7016
8995
|
description: "The title of the example"
|
|
8996
|
+
},
|
|
8997
|
+
{
|
|
8998
|
+
// Override inherited @example from group_standardTags: string root example.
|
|
8999
|
+
key: ConfigKey.property_example,
|
|
9000
|
+
exportJsonKey: [
|
|
9001
|
+
{ "@keyonly": { isExample: true, example: "true" } },
|
|
9002
|
+
{ "@absent": { isExample: true, example: "true" } },
|
|
9003
|
+
{ isExample: true, example: "$" }
|
|
9004
|
+
],
|
|
9005
|
+
description: "The example text for the example bit",
|
|
9006
|
+
format: TagFormat.plainText,
|
|
9007
|
+
nullable: true
|
|
7017
9008
|
}
|
|
7018
9009
|
],
|
|
7019
9010
|
rootExampleType: ExampleType.string
|
|
@@ -7099,7 +9090,19 @@ var BITS = {
|
|
|
7099
9090
|
[BitType2.articleAi]: {
|
|
7100
9091
|
since: "1.3.0",
|
|
7101
9092
|
baseBitType: BitType2.article,
|
|
7102
|
-
description: "Article AI bit, used to create AI-generated articles"
|
|
9093
|
+
description: "Article AI bit, used to create AI-generated articles",
|
|
9094
|
+
tags: [
|
|
9095
|
+
{
|
|
9096
|
+
// Shadows the inherited @aiGenerated from the standard group: this
|
|
9097
|
+
// bit type forces aiGenerated:true regardless of source value or
|
|
9098
|
+
// absence. Literal `true` in the export pattern ignores `$`.
|
|
9099
|
+
key: ConfigKey.property_aiGenerated,
|
|
9100
|
+
description: "AI-generated flag, forced true for article-ai bits",
|
|
9101
|
+
format: TagFormat.boolean,
|
|
9102
|
+
defaultValue: "true",
|
|
9103
|
+
exportJsonKey: { aiGenerated: true }
|
|
9104
|
+
}
|
|
9105
|
+
]
|
|
7103
9106
|
},
|
|
7104
9107
|
[BitType2.articleAttachment]: {
|
|
7105
9108
|
since: "1.3.0",
|
|
@@ -7424,7 +9427,19 @@ var BITS = {
|
|
|
7424
9427
|
[BitType2.noteAi]: {
|
|
7425
9428
|
since: "1.3.0",
|
|
7426
9429
|
baseBitType: BitType2.note,
|
|
7427
|
-
description: "Note AI bit, used to create AI-generated notes in articles or books"
|
|
9430
|
+
description: "Note AI bit, used to create AI-generated notes in articles or books",
|
|
9431
|
+
tags: [
|
|
9432
|
+
{
|
|
9433
|
+
// Shadows the inherited @aiGenerated from the standard group: this
|
|
9434
|
+
// bit type forces aiGenerated:true regardless of source value or
|
|
9435
|
+
// absence. Literal `true` in the export pattern ignores `$`.
|
|
9436
|
+
key: ConfigKey.property_aiGenerated,
|
|
9437
|
+
description: "AI-generated flag, forced true for article-ai bits",
|
|
9438
|
+
format: TagFormat.boolean,
|
|
9439
|
+
defaultValue: "true",
|
|
9440
|
+
exportJsonKey: { aiGenerated: true }
|
|
9441
|
+
}
|
|
9442
|
+
]
|
|
7428
9443
|
},
|
|
7429
9444
|
[BitType2.notebookArticle]: {
|
|
7430
9445
|
since: "1.3.0",
|
|
@@ -7549,7 +9564,19 @@ var BITS = {
|
|
|
7549
9564
|
[BitType2.summaryAi]: {
|
|
7550
9565
|
since: "1.3.0",
|
|
7551
9566
|
baseBitType: BitType2.summary,
|
|
7552
|
-
description: "AI-generated summary bit"
|
|
9567
|
+
description: "AI-generated summary bit",
|
|
9568
|
+
tags: [
|
|
9569
|
+
{
|
|
9570
|
+
// Shadows the inherited @aiGenerated from the standard group: this
|
|
9571
|
+
// bit type forces aiGenerated:true regardless of source value or
|
|
9572
|
+
// absence. Literal `true` in the export pattern ignores `$`.
|
|
9573
|
+
key: ConfigKey.property_aiGenerated,
|
|
9574
|
+
description: "AI-generated flag, forced true for article-ai bits",
|
|
9575
|
+
format: TagFormat.boolean,
|
|
9576
|
+
defaultValue: "true",
|
|
9577
|
+
exportJsonKey: { aiGenerated: true }
|
|
9578
|
+
}
|
|
9579
|
+
]
|
|
7553
9580
|
},
|
|
7554
9581
|
[BitType2.videoTranscript]: {
|
|
7555
9582
|
since: "1.3.0",
|
|
@@ -7823,7 +9850,7 @@ var BITS = {
|
|
|
7823
9850
|
description: "Product ID for the module product, used to link to a specific product",
|
|
7824
9851
|
format: TagFormat.plainText,
|
|
7825
9852
|
minCount: 1,
|
|
7826
|
-
maxCount:
|
|
9853
|
+
maxCount: 1
|
|
7827
9854
|
}
|
|
7828
9855
|
]
|
|
7829
9856
|
},
|
|
@@ -7876,9 +9903,13 @@ var BITS = {
|
|
|
7876
9903
|
description: "Resource bit tags for logo grave images, used to define additional properties"
|
|
7877
9904
|
},
|
|
7878
9905
|
{
|
|
7879
|
-
// Image resource
|
|
7880
|
-
|
|
9906
|
+
// Image resource — fully-expanded shape so each `&image` emission
|
|
9907
|
+
// produces a complete `{type, image: {src}}` object inside the
|
|
9908
|
+
// `images[]` array. Chain attrs like `[@zoomDisabled]` fold under
|
|
9909
|
+
// `images[].image` via the `[]` last-element-merge semantic.
|
|
9910
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
7881
9911
|
description: "Resource image tags for logo grave images, used to attach images",
|
|
9912
|
+
exportJsonKey: { images: [{ type: "image", image: { src: "$" } }] },
|
|
7882
9913
|
minCount: 1,
|
|
7883
9914
|
maxCount: Count.infinity
|
|
7884
9915
|
}
|
|
@@ -8042,15 +10073,27 @@ var BITS = {
|
|
|
8042
10073
|
format: TagFormat.plainText,
|
|
8043
10074
|
chain: [
|
|
8044
10075
|
{
|
|
10076
|
+
exportJsonKey: { reference: "$" },
|
|
8045
10077
|
key: ConfigKey.tag_reference,
|
|
8046
10078
|
format: TagFormat.plainText,
|
|
8047
10079
|
description: "Reference tag for the book, used to link to the book in the system",
|
|
8048
|
-
maxCount:
|
|
10080
|
+
maxCount: 1,
|
|
10081
|
+
chain: [
|
|
10082
|
+
{
|
|
10083
|
+
key: ConfigKey.tag_reference,
|
|
10084
|
+
jsonKey: "referenceEnd",
|
|
10085
|
+
exportJsonKey: { referenceEnd: "$" },
|
|
10086
|
+
format: TagFormat.plainText,
|
|
10087
|
+
description: "End reference tag for the book, used to specify a range",
|
|
10088
|
+
maxCount: 1
|
|
10089
|
+
}
|
|
10090
|
+
]
|
|
8049
10091
|
}
|
|
8050
10092
|
]
|
|
8051
10093
|
},
|
|
8052
10094
|
{
|
|
8053
10095
|
/* Allow incorrectly chained reference tag */
|
|
10096
|
+
exportJsonKey: { reference: "$" },
|
|
8054
10097
|
key: ConfigKey.tag_reference,
|
|
8055
10098
|
format: TagFormat.plainText,
|
|
8056
10099
|
description: "Reference tag for the book, used to link to the book in the system"
|
|
@@ -8097,18 +10140,41 @@ var BITS = {
|
|
|
8097
10140
|
format: TagFormat.plainText,
|
|
8098
10141
|
chain: [
|
|
8099
10142
|
{
|
|
10143
|
+
exportJsonKey: { reference: "$" },
|
|
8100
10144
|
key: ConfigKey.tag_reference,
|
|
8101
10145
|
format: TagFormat.plainText,
|
|
8102
10146
|
description: "Reference tag for the book, used to link to the book in the system",
|
|
8103
|
-
maxCount:
|
|
10147
|
+
maxCount: 1,
|
|
10148
|
+
chain: [
|
|
10149
|
+
{
|
|
10150
|
+
key: ConfigKey.tag_reference,
|
|
10151
|
+
jsonKey: "referenceEnd",
|
|
10152
|
+
exportJsonKey: { referenceEnd: "$" },
|
|
10153
|
+
format: TagFormat.plainText,
|
|
10154
|
+
description: "End reference tag for the book, used to specify a range",
|
|
10155
|
+
maxCount: 1
|
|
10156
|
+
}
|
|
10157
|
+
]
|
|
8104
10158
|
}
|
|
8105
10159
|
]
|
|
8106
10160
|
},
|
|
8107
10161
|
{
|
|
8108
10162
|
/* Allow incorrectly chained reference tag */
|
|
10163
|
+
exportJsonKey: { reference: "$" },
|
|
8109
10164
|
key: ConfigKey.tag_reference,
|
|
8110
10165
|
format: TagFormat.plainText,
|
|
8111
|
-
description: "Reference tag for the book, used to link to the book in the system"
|
|
10166
|
+
description: "Reference tag for the book, used to link to the book in the system",
|
|
10167
|
+
maxCount: 1,
|
|
10168
|
+
chain: [
|
|
10169
|
+
{
|
|
10170
|
+
key: ConfigKey.tag_reference,
|
|
10171
|
+
jsonKey: "referenceEnd",
|
|
10172
|
+
exportJsonKey: { referenceEnd: "$" },
|
|
10173
|
+
format: TagFormat.plainText,
|
|
10174
|
+
description: "End reference tag for the book, used to specify a range",
|
|
10175
|
+
maxCount: 1
|
|
10176
|
+
}
|
|
10177
|
+
]
|
|
8112
10178
|
},
|
|
8113
10179
|
{
|
|
8114
10180
|
key: ConfigKey.property_buttonCaption,
|
|
@@ -8133,14 +10199,29 @@ var BITS = {
|
|
|
8133
10199
|
tags: [
|
|
8134
10200
|
{
|
|
8135
10201
|
key: ConfigKey.property_book,
|
|
10202
|
+
// Starter-array shape: each `[@book:value]` chain appends a fresh
|
|
10203
|
+
// `{ book, reference }` entry. The chained `►` (tag_reference) lands
|
|
10204
|
+
// inside the most-recently-appended entry as `reference: $`.
|
|
10205
|
+
exportJsonKey: { book: [{ book: "$" }] },
|
|
8136
10206
|
description: "Book reference for the page, used to link to a specific book",
|
|
8137
10207
|
maxCount: Count.infinity,
|
|
8138
10208
|
chain: [
|
|
8139
10209
|
{
|
|
10210
|
+
exportJsonKey: { reference: "$" },
|
|
8140
10211
|
key: ConfigKey.tag_reference,
|
|
8141
10212
|
format: TagFormat.plainText,
|
|
8142
10213
|
description: "Reference tag for the book, used to link to the book in the system",
|
|
8143
|
-
maxCount:
|
|
10214
|
+
maxCount: 1,
|
|
10215
|
+
chain: [
|
|
10216
|
+
{
|
|
10217
|
+
key: ConfigKey.tag_reference,
|
|
10218
|
+
jsonKey: "referenceEnd",
|
|
10219
|
+
exportJsonKey: { referenceEnd: "$" },
|
|
10220
|
+
format: TagFormat.plainText,
|
|
10221
|
+
description: "End reference tag for the book, used to specify a range",
|
|
10222
|
+
maxCount: 1
|
|
10223
|
+
}
|
|
10224
|
+
]
|
|
8144
10225
|
}
|
|
8145
10226
|
]
|
|
8146
10227
|
},
|
|
@@ -8189,7 +10270,9 @@ var BITS = {
|
|
|
8189
10270
|
format: TagFormat.plainText
|
|
8190
10271
|
}
|
|
8191
10272
|
],
|
|
8192
|
-
|
|
10273
|
+
// page-footer emits cards under `sections` (vs `listItems` for the
|
|
10274
|
+
// sibling exampleList / assignmentList bits) — see JsonGenerator.ts.
|
|
10275
|
+
cardSet: CardSetConfigKey.pageFooterSections
|
|
8193
10276
|
},
|
|
8194
10277
|
[BitType2.legend]: {
|
|
8195
10278
|
since: "3.12.0",
|
|
@@ -8231,6 +10314,20 @@ var BITS = {
|
|
|
8231
10314
|
since: "1.34.0",
|
|
8232
10315
|
baseBitType: BitType2._standard,
|
|
8233
10316
|
description: "Definition list bit, used to create lists of definitions in articles or books",
|
|
10317
|
+
tags: [
|
|
10318
|
+
{
|
|
10319
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10320
|
+
key: ConfigKey.property_example,
|
|
10321
|
+
exportJsonKey: [
|
|
10322
|
+
{ "@keyonly": { isExample: true } },
|
|
10323
|
+
{ "@absent": { isExample: true } },
|
|
10324
|
+
{ isExample: true, example: "$" }
|
|
10325
|
+
],
|
|
10326
|
+
description: "The example(s) for the bit",
|
|
10327
|
+
format: TagFormat.bitmarkText,
|
|
10328
|
+
nullable: true
|
|
10329
|
+
}
|
|
10330
|
+
],
|
|
8234
10331
|
cardSet: CardSetConfigKey.definitionList
|
|
8235
10332
|
},
|
|
8236
10333
|
[BitType2.metaSearchDefaultTerms]: {
|
|
@@ -8253,6 +10350,18 @@ var BITS = {
|
|
|
8253
10350
|
{
|
|
8254
10351
|
key: ConfigKey.group_quizCommon,
|
|
8255
10352
|
description: "Common quiz tags for flashcards"
|
|
10353
|
+
},
|
|
10354
|
+
{
|
|
10355
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10356
|
+
key: ConfigKey.property_example,
|
|
10357
|
+
exportJsonKey: [
|
|
10358
|
+
{ "@keyonly": { isExample: true } },
|
|
10359
|
+
{ "@absent": { isExample: true } },
|
|
10360
|
+
{ isExample: true, example: "$" }
|
|
10361
|
+
],
|
|
10362
|
+
description: "The example(s) for the bit",
|
|
10363
|
+
format: TagFormat.bitmarkText,
|
|
10364
|
+
nullable: true
|
|
8256
10365
|
}
|
|
8257
10366
|
],
|
|
8258
10367
|
cardSet: CardSetConfigKey.flashcard
|
|
@@ -8260,7 +10369,11 @@ var BITS = {
|
|
|
8260
10369
|
[BitType2.flashcard1]: {
|
|
8261
10370
|
since: "1.3.0",
|
|
8262
10371
|
baseBitType: BitType2.flashcard,
|
|
8263
|
-
description: "Flashcard 1 bit"
|
|
10372
|
+
description: "Flashcard 1 bit",
|
|
10373
|
+
// PLAN-085: use the flashcard1 cardset (sections.default.maxCount=1)
|
|
10374
|
+
// instead of inheriting `flashcard`'s unbounded cardset, since this
|
|
10375
|
+
// bit type structurally allows only a single card.
|
|
10376
|
+
cardSet: CardSetConfigKey.flashcard1
|
|
8264
10377
|
},
|
|
8265
10378
|
[BitType2.qAndACard]: {
|
|
8266
10379
|
since: "3.25.0",
|
|
@@ -8295,8 +10408,24 @@ var BITS = {
|
|
|
8295
10408
|
description: "Common quiz tags for highlighted text"
|
|
8296
10409
|
},
|
|
8297
10410
|
{
|
|
8298
|
-
|
|
8299
|
-
|
|
10411
|
+
// Dedicated highlight inline-select chain: tag_true / tag_false
|
|
10412
|
+
// emit `{type:"highlight", attrs:{texts:[{text,isCorrect?}]}}`
|
|
10413
|
+
// inline body nodes via @body-inline. Bit shares no tag IDs with
|
|
10414
|
+
// multiple-choice / multiple-choice-1 (which use group_trueFalse).
|
|
10415
|
+
key: ConfigKey.group_trueFalseInlineHighlight,
|
|
10416
|
+
description: "True/False quiz tags for highlighted text (inline body nodes)"
|
|
10417
|
+
},
|
|
10418
|
+
{
|
|
10419
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10420
|
+
key: ConfigKey.property_example,
|
|
10421
|
+
exportJsonKey: [
|
|
10422
|
+
{ "@keyonly": { isExample: true } },
|
|
10423
|
+
{ "@absent": { isExample: true } },
|
|
10424
|
+
{ isExample: true, example: "$" }
|
|
10425
|
+
],
|
|
10426
|
+
description: "The example(s) for the bit",
|
|
10427
|
+
format: TagFormat.bitmarkText,
|
|
10428
|
+
nullable: true
|
|
8300
10429
|
}
|
|
8301
10430
|
]
|
|
8302
10431
|
},
|
|
@@ -8306,14 +10435,8 @@ var BITS = {
|
|
|
8306
10435
|
description: "Image bit, used to create images in articles or books",
|
|
8307
10436
|
tags: [
|
|
8308
10437
|
{
|
|
8309
|
-
key: ConfigKey.
|
|
8310
|
-
description: "Background wallpaper for
|
|
8311
|
-
chain: [
|
|
8312
|
-
{
|
|
8313
|
-
key: ConfigKey.group_resourceImageCommon,
|
|
8314
|
-
description: "Common resource image tags for images"
|
|
8315
|
-
}
|
|
8316
|
-
]
|
|
10438
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
10439
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
8317
10440
|
},
|
|
8318
10441
|
{
|
|
8319
10442
|
key: ConfigKey.group_resourceBitTags,
|
|
@@ -8416,8 +10539,15 @@ var BITS = {
|
|
|
8416
10539
|
},
|
|
8417
10540
|
[BitType2.imageSeparator]: {
|
|
8418
10541
|
since: "1.4.15",
|
|
8419
|
-
baseBitType: BitType2.
|
|
8420
|
-
description: "Image separator bit, used to create separators in articles or books"
|
|
10542
|
+
baseBitType: BitType2._standard,
|
|
10543
|
+
description: "Image separator bit, used to create separators in articles or books",
|
|
10544
|
+
tags: [
|
|
10545
|
+
{
|
|
10546
|
+
key: ConfigKey.group_imageNoZoom,
|
|
10547
|
+
description: "Image no zoom tags for images, used to define whether images should have zoom functionality"
|
|
10548
|
+
}
|
|
10549
|
+
],
|
|
10550
|
+
resourceAttachmentAllowed: false
|
|
8421
10551
|
},
|
|
8422
10552
|
[BitType2.imageSeparatorAlt]: {
|
|
8423
10553
|
since: "1.16.0",
|
|
@@ -8456,15 +10586,20 @@ var BITS = {
|
|
|
8456
10586
|
},
|
|
8457
10587
|
[BitType2.pageBanner]: {
|
|
8458
10588
|
since: "1.4.3",
|
|
8459
|
-
baseBitType: BitType2.
|
|
10589
|
+
baseBitType: BitType2._standard,
|
|
8460
10590
|
description: "Page banner bit, used to create banners for pages in articles or books",
|
|
8461
10591
|
tags: [
|
|
8462
10592
|
{
|
|
8463
10593
|
key: ConfigKey.property_slug,
|
|
8464
10594
|
description: "Slug for the page banner, used to identify the banner in the system",
|
|
8465
10595
|
format: TagFormat.plainText
|
|
10596
|
+
},
|
|
10597
|
+
{
|
|
10598
|
+
key: ConfigKey.group_imageNoZoom,
|
|
10599
|
+
description: "Image no zoom tags for images, used to define whether images should have zoom functionality"
|
|
8466
10600
|
}
|
|
8467
|
-
]
|
|
10601
|
+
],
|
|
10602
|
+
resourceAttachmentAllowed: false
|
|
8468
10603
|
},
|
|
8469
10604
|
[BitType2.pageHero]: {
|
|
8470
10605
|
since: "1.11.0",
|
|
@@ -8479,7 +10614,7 @@ var BITS = {
|
|
|
8479
10614
|
},
|
|
8480
10615
|
[BitType2.tableImage]: {
|
|
8481
10616
|
since: "1.5.15",
|
|
8482
|
-
baseBitType: BitType2.
|
|
10617
|
+
baseBitType: BitType2.tableExtended,
|
|
8483
10618
|
description: "Table image bit, used to create images in tables in articles or books",
|
|
8484
10619
|
tags: [
|
|
8485
10620
|
{
|
|
@@ -8488,14 +10623,8 @@ var BITS = {
|
|
|
8488
10623
|
format: TagFormat.bitmarkText
|
|
8489
10624
|
},
|
|
8490
10625
|
{
|
|
8491
|
-
key: ConfigKey.
|
|
8492
|
-
description: "Background wallpaper for
|
|
8493
|
-
chain: [
|
|
8494
|
-
{
|
|
8495
|
-
key: ConfigKey.group_resourceImageCommon,
|
|
8496
|
-
description: "Common resource image tags for images"
|
|
8497
|
-
}
|
|
8498
|
-
]
|
|
10626
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
10627
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
8499
10628
|
},
|
|
8500
10629
|
{
|
|
8501
10630
|
key: ConfigKey.group_resourceBitTags,
|
|
@@ -8638,9 +10767,10 @@ var BITS = {
|
|
|
8638
10767
|
description: "Resource bit tags for logo grave images, used to define additional properties"
|
|
8639
10768
|
},
|
|
8640
10769
|
{
|
|
8641
|
-
// Image resource
|
|
8642
|
-
key: ConfigKey.
|
|
10770
|
+
// Image resource — fully-expanded shape (see BitType.extractorImage).
|
|
10771
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
8643
10772
|
description: "Resource image tags for logo grave images, used to attach images",
|
|
10773
|
+
exportJsonKey: { logos: [{ type: "image", image: { src: "$" } }] },
|
|
8644
10774
|
minCount: 1,
|
|
8645
10775
|
maxCount: Count.infinity
|
|
8646
10776
|
}
|
|
@@ -8650,7 +10780,17 @@ var BITS = {
|
|
|
8650
10780
|
[BitType2.prototypeImages]: {
|
|
8651
10781
|
since: "1.6.1",
|
|
8652
10782
|
baseBitType: BitType2.imagesLogoGrave,
|
|
8653
|
-
description: "Prototype images bit, used to create prototype images in articles or books"
|
|
10783
|
+
description: "Prototype images bit, used to create prototype images in articles or books",
|
|
10784
|
+
tags: [
|
|
10785
|
+
{
|
|
10786
|
+
// Override inherited `logos` wrapper with `images` for this bit type.
|
|
10787
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
10788
|
+
description: "Resource image tags for prototype images",
|
|
10789
|
+
exportJsonKey: { images: [{ type: "image", image: { src: "$" } }] },
|
|
10790
|
+
minCount: 1,
|
|
10791
|
+
maxCount: Count.infinity
|
|
10792
|
+
}
|
|
10793
|
+
]
|
|
8654
10794
|
},
|
|
8655
10795
|
[BitType2.internalLink]: {
|
|
8656
10796
|
since: "1.3.0",
|
|
@@ -8658,6 +10798,7 @@ var BITS = {
|
|
|
8658
10798
|
description: "Internal link bit, used to create links to other bits in articles or books",
|
|
8659
10799
|
tags: [
|
|
8660
10800
|
{
|
|
10801
|
+
exportJsonKey: { reference: "$" },
|
|
8661
10802
|
key: ConfigKey.tag_reference,
|
|
8662
10803
|
format: TagFormat.plainText,
|
|
8663
10804
|
description: "Reference tag for the internal link, used to link to the target bit"
|
|
@@ -8676,8 +10817,21 @@ var BITS = {
|
|
|
8676
10817
|
},
|
|
8677
10818
|
{
|
|
8678
10819
|
key: ConfigKey.property_reasonableNumOfChars,
|
|
10820
|
+
exportJsonKey: {},
|
|
8679
10821
|
description: "Reasonable number of characters for the interview, used to limit input size",
|
|
8680
10822
|
format: TagFormat.number
|
|
10823
|
+
},
|
|
10824
|
+
{
|
|
10825
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10826
|
+
key: ConfigKey.property_example,
|
|
10827
|
+
exportJsonKey: [
|
|
10828
|
+
{ "@keyonly": { isExample: true } },
|
|
10829
|
+
{ "@absent": { isExample: true } },
|
|
10830
|
+
{ isExample: true, example: "$" }
|
|
10831
|
+
],
|
|
10832
|
+
description: "The example(s) for the bit",
|
|
10833
|
+
format: TagFormat.bitmarkText,
|
|
10834
|
+
nullable: true
|
|
8681
10835
|
}
|
|
8682
10836
|
],
|
|
8683
10837
|
cardSet: CardSetConfigKey.questions
|
|
@@ -9036,6 +11190,18 @@ var BITS = {
|
|
|
9036
11190
|
{
|
|
9037
11191
|
key: ConfigKey.group_mark,
|
|
9038
11192
|
description: "Mark tags, used to define the content of marks"
|
|
11193
|
+
},
|
|
11194
|
+
{
|
|
11195
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11196
|
+
key: ConfigKey.property_example,
|
|
11197
|
+
exportJsonKey: [
|
|
11198
|
+
{ "@keyonly": { isExample: true } },
|
|
11199
|
+
{ "@absent": { isExample: true } },
|
|
11200
|
+
{ isExample: true, example: "$" }
|
|
11201
|
+
],
|
|
11202
|
+
description: "The example(s) for the bit",
|
|
11203
|
+
format: TagFormat.bitmarkText,
|
|
11204
|
+
nullable: true
|
|
9039
11205
|
}
|
|
9040
11206
|
]
|
|
9041
11207
|
},
|
|
@@ -9051,9 +11217,27 @@ var BITS = {
|
|
|
9051
11217
|
},
|
|
9052
11218
|
{
|
|
9053
11219
|
key: ConfigKey.property_isCaseSensitive,
|
|
11220
|
+
exportJsonKey: {},
|
|
9054
11221
|
description: "Case sensitivity for matching pairs, used to define if matches are case-sensitive",
|
|
9055
11222
|
format: TagFormat.boolean,
|
|
9056
11223
|
defaultValue: "true"
|
|
11224
|
+
},
|
|
11225
|
+
{
|
|
11226
|
+
// Override inherited @example: in `isTopLevelExample` allow-list
|
|
11227
|
+
// (covers match, matchAll, matchReverse, matchAllReverse,
|
|
11228
|
+
// matchSolutionGrouped, matchMatrix, matchAudio, matchPicture).
|
|
11229
|
+
// Bit-level fires emit only `isExample`; the @example value (when
|
|
11230
|
+
// provided) is recorded in the ancestor stack and consumed by
|
|
11231
|
+
// per-pair/per-cell variant overrides — not surfaced at bit scope.
|
|
11232
|
+
key: ConfigKey.property_example,
|
|
11233
|
+
exportJsonKey: [
|
|
11234
|
+
{ "@keyonly": { isExample: true } },
|
|
11235
|
+
{ "@absent": { isExample: true } },
|
|
11236
|
+
{ isExample: true }
|
|
11237
|
+
],
|
|
11238
|
+
description: "The example(s) for the bit",
|
|
11239
|
+
format: TagFormat.bitmarkText,
|
|
11240
|
+
nullable: true
|
|
9057
11241
|
}
|
|
9058
11242
|
],
|
|
9059
11243
|
cardSet: CardSetConfigKey.matchPairs
|
|
@@ -9103,6 +11287,7 @@ var BITS = {
|
|
|
9103
11287
|
tags: [
|
|
9104
11288
|
{
|
|
9105
11289
|
key: ConfigKey.property_reasonableNumOfChars,
|
|
11290
|
+
exportJsonKey: {},
|
|
9106
11291
|
description: "Reasonable number of characters for feedback, used to limit input size",
|
|
9107
11292
|
format: TagFormat.number
|
|
9108
11293
|
}
|
|
@@ -9137,6 +11322,18 @@ var BITS = {
|
|
|
9137
11322
|
{
|
|
9138
11323
|
key: ConfigKey.group_trueFalse,
|
|
9139
11324
|
description: "True/False tags for multiple choice 1 questions"
|
|
11325
|
+
},
|
|
11326
|
+
{
|
|
11327
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11328
|
+
key: ConfigKey.property_example,
|
|
11329
|
+
exportJsonKey: [
|
|
11330
|
+
{ "@keyonly": { isExample: true } },
|
|
11331
|
+
{ "@absent": { isExample: true } },
|
|
11332
|
+
{ isExample: true, example: "$" }
|
|
11333
|
+
],
|
|
11334
|
+
description: "The example(s) for the bit",
|
|
11335
|
+
format: TagFormat.bitmarkText,
|
|
11336
|
+
nullable: true
|
|
9140
11337
|
}
|
|
9141
11338
|
]
|
|
9142
11339
|
},
|
|
@@ -9158,8 +11355,20 @@ var BITS = {
|
|
|
9158
11355
|
{
|
|
9159
11356
|
key: ConfigKey.group_trueFalse,
|
|
9160
11357
|
description: "True/False tags for multiple choice questions"
|
|
9161
|
-
}
|
|
11358
|
+
},
|
|
9162
11359
|
// This is actually for multiple-choice-1, but we support it here as well (as many bits are wrong)
|
|
11360
|
+
{
|
|
11361
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11362
|
+
key: ConfigKey.property_example,
|
|
11363
|
+
exportJsonKey: [
|
|
11364
|
+
{ "@keyonly": { isExample: true } },
|
|
11365
|
+
{ "@absent": { isExample: true } },
|
|
11366
|
+
{ isExample: true, example: "$" }
|
|
11367
|
+
],
|
|
11368
|
+
description: "The example(s) for the bit",
|
|
11369
|
+
format: TagFormat.bitmarkText,
|
|
11370
|
+
nullable: true
|
|
11371
|
+
}
|
|
9163
11372
|
],
|
|
9164
11373
|
cardSet: CardSetConfigKey.quiz
|
|
9165
11374
|
},
|
|
@@ -9179,8 +11388,20 @@ var BITS = {
|
|
|
9179
11388
|
description: "Common quiz tags for multiple choice text questions"
|
|
9180
11389
|
},
|
|
9181
11390
|
{
|
|
9182
|
-
key: ConfigKey.
|
|
11391
|
+
key: ConfigKey.group_trueFalseInlineSelect,
|
|
9183
11392
|
description: "True/False tags for multiple choice text questions"
|
|
11393
|
+
},
|
|
11394
|
+
{
|
|
11395
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11396
|
+
key: ConfigKey.property_example,
|
|
11397
|
+
exportJsonKey: [
|
|
11398
|
+
{ "@keyonly": { isExample: true } },
|
|
11399
|
+
{ "@absent": { isExample: true } },
|
|
11400
|
+
{ isExample: true, example: "$" }
|
|
11401
|
+
],
|
|
11402
|
+
description: "The example(s) for the bit",
|
|
11403
|
+
format: TagFormat.bitmarkText,
|
|
11404
|
+
nullable: true
|
|
9184
11405
|
}
|
|
9185
11406
|
]
|
|
9186
11407
|
},
|
|
@@ -9205,8 +11426,20 @@ var BITS = {
|
|
|
9205
11426
|
description: "Common quiz tags for multiple response 1 questions"
|
|
9206
11427
|
},
|
|
9207
11428
|
{
|
|
9208
|
-
key: ConfigKey.
|
|
11429
|
+
key: ConfigKey.group_trueFalseResponses,
|
|
9209
11430
|
description: "True/False tags for multiple response 1 questions"
|
|
11431
|
+
},
|
|
11432
|
+
{
|
|
11433
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11434
|
+
key: ConfigKey.property_example,
|
|
11435
|
+
exportJsonKey: [
|
|
11436
|
+
{ "@keyonly": { isExample: true } },
|
|
11437
|
+
{ "@absent": { isExample: true } },
|
|
11438
|
+
{ isExample: true, example: "$" }
|
|
11439
|
+
],
|
|
11440
|
+
description: "The example(s) for the bit",
|
|
11441
|
+
format: TagFormat.bitmarkText,
|
|
11442
|
+
nullable: true
|
|
9210
11443
|
}
|
|
9211
11444
|
]
|
|
9212
11445
|
},
|
|
@@ -9226,12 +11459,24 @@ var BITS = {
|
|
|
9226
11459
|
description: "Common quiz tags for multiple response questions"
|
|
9227
11460
|
},
|
|
9228
11461
|
{
|
|
9229
|
-
key: ConfigKey.
|
|
11462
|
+
key: ConfigKey.group_trueFalseResponses,
|
|
9230
11463
|
description: "True/False tags for multiple response questions"
|
|
9231
|
-
}
|
|
11464
|
+
},
|
|
9232
11465
|
// This is actually for multiple-response-1, but we support it here as well (as many bits are wrong)
|
|
11466
|
+
{
|
|
11467
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11468
|
+
key: ConfigKey.property_example,
|
|
11469
|
+
exportJsonKey: [
|
|
11470
|
+
{ "@keyonly": { isExample: true } },
|
|
11471
|
+
{ "@absent": { isExample: true } },
|
|
11472
|
+
{ isExample: true, example: "$" }
|
|
11473
|
+
],
|
|
11474
|
+
description: "The example(s) for the bit",
|
|
11475
|
+
format: TagFormat.bitmarkText,
|
|
11476
|
+
nullable: true
|
|
11477
|
+
}
|
|
9233
11478
|
],
|
|
9234
|
-
cardSet: CardSetConfigKey.
|
|
11479
|
+
cardSet: CardSetConfigKey.quizResponses
|
|
9235
11480
|
},
|
|
9236
11481
|
[BitType2.coachSelfReflectionMultipleResponse]: {
|
|
9237
11482
|
since: "1.3.0",
|
|
@@ -9244,6 +11489,7 @@ var BITS = {
|
|
|
9244
11489
|
description: "Page bit, used to create pages in articles or books",
|
|
9245
11490
|
tags: [
|
|
9246
11491
|
{
|
|
11492
|
+
exportJsonKey: { title: "$" },
|
|
9247
11493
|
key: ConfigKey.tag_title,
|
|
9248
11494
|
description: "Title of the page, used to display the page title"
|
|
9249
11495
|
},
|
|
@@ -9480,6 +11726,8 @@ var BITS = {
|
|
|
9480
11726
|
},
|
|
9481
11727
|
{
|
|
9482
11728
|
key: ConfigKey.resource_platformIcon,
|
|
11729
|
+
jsonKey: "platformIcon|resource(type=image, key=image)",
|
|
11730
|
+
exportJsonKey: { platformIcon: { type: "image", image: { src: "$" } } },
|
|
9483
11731
|
description: "The platform icon",
|
|
9484
11732
|
chain: [
|
|
9485
11733
|
{
|
|
@@ -9515,6 +11763,8 @@ var BITS = {
|
|
|
9515
11763
|
tags: [
|
|
9516
11764
|
{
|
|
9517
11765
|
key: ConfigKey.resource_platformLogo,
|
|
11766
|
+
jsonKey: "platformLogo|resource(type=image, key=image)",
|
|
11767
|
+
exportJsonKey: { platformLogo: { type: "image", image: { src: "$" } } },
|
|
9518
11768
|
description: "The platform logo",
|
|
9519
11769
|
chain: [
|
|
9520
11770
|
{
|
|
@@ -9603,6 +11853,7 @@ var BITS = {
|
|
|
9603
11853
|
{
|
|
9604
11854
|
key: ConfigKey.resource_platformBackgroundImage,
|
|
9605
11855
|
jsonKey: "platformBackgroundImage|resource(type=image, key=image)",
|
|
11856
|
+
exportJsonKey: { platformBackgroundImage: { type: "image", image: { src: "$" } } },
|
|
9606
11857
|
description: "The platform section chat background image",
|
|
9607
11858
|
chain: [
|
|
9608
11859
|
{
|
|
@@ -9696,6 +11947,7 @@ var BITS = {
|
|
|
9696
11947
|
description: "Review note bit, used to create review notes in articles or books",
|
|
9697
11948
|
tags: [
|
|
9698
11949
|
{
|
|
11950
|
+
exportJsonKey: { title: "$" },
|
|
9699
11951
|
key: ConfigKey.tag_title,
|
|
9700
11952
|
description: "Title of the review note, used to display the note title"
|
|
9701
11953
|
},
|
|
@@ -9714,6 +11966,18 @@ var BITS = {
|
|
|
9714
11966
|
key: ConfigKey.property_resolvedBy,
|
|
9715
11967
|
description: "Resolved by for the review note, used to define who resolved the note",
|
|
9716
11968
|
format: TagFormat.plainText
|
|
11969
|
+
},
|
|
11970
|
+
{
|
|
11971
|
+
// Override inherited @example from group_standardTags: string root example.
|
|
11972
|
+
key: ConfigKey.property_example,
|
|
11973
|
+
exportJsonKey: [
|
|
11974
|
+
{ "@keyonly": { isExample: true, example: "true" } },
|
|
11975
|
+
{ "@absent": { isExample: true, example: "true" } },
|
|
11976
|
+
{ isExample: true, example: "$" }
|
|
11977
|
+
],
|
|
11978
|
+
description: "The example text for the review note bit",
|
|
11979
|
+
format: TagFormat.plainText,
|
|
11980
|
+
nullable: true
|
|
9717
11981
|
}
|
|
9718
11982
|
],
|
|
9719
11983
|
rootExampleType: ExampleType.string
|
|
@@ -9766,11 +12030,13 @@ var BITS = {
|
|
|
9766
12030
|
tags: [
|
|
9767
12031
|
// Not sure if these are actually valid here, but include them as they are in the test bit.
|
|
9768
12032
|
{
|
|
12033
|
+
exportJsonKey: { anchor: "$" },
|
|
9769
12034
|
key: ConfigKey.tag_anchor,
|
|
9770
12035
|
format: TagFormat.plainText,
|
|
9771
12036
|
description: "Anchor for the sample solution, used to link to the solution"
|
|
9772
12037
|
},
|
|
9773
12038
|
{
|
|
12039
|
+
exportJsonKey: { reference: "$" },
|
|
9774
12040
|
key: ConfigKey.tag_reference,
|
|
9775
12041
|
format: TagFormat.plainText,
|
|
9776
12042
|
description: "Reference for the sample solution, used to link to the source of the solution"
|
|
@@ -9786,6 +12052,20 @@ var BITS = {
|
|
|
9786
12052
|
{
|
|
9787
12053
|
key: ConfigKey.group_quizCommon,
|
|
9788
12054
|
description: "Common quiz tags for sequences"
|
|
12055
|
+
},
|
|
12056
|
+
{
|
|
12057
|
+
// Override inherited @example from group_standardTags: this bit has
|
|
12058
|
+
// a boolean root example (rootExampleType: boolean), so bit-level
|
|
12059
|
+
// [@example] writes `example: true` in addition to `isExample: true`.
|
|
12060
|
+
key: ConfigKey.property_example,
|
|
12061
|
+
exportJsonKey: [
|
|
12062
|
+
{ "@keyonly": { isExample: true, example: true } },
|
|
12063
|
+
{ "@absent": { isExample: true, example: true } },
|
|
12064
|
+
{ isExample: true, example: "$" }
|
|
12065
|
+
],
|
|
12066
|
+
description: "The example flag for the bit (boolean)",
|
|
12067
|
+
format: TagFormat.boolean,
|
|
12068
|
+
nullable: true
|
|
9789
12069
|
}
|
|
9790
12070
|
],
|
|
9791
12071
|
cardSet: CardSetConfigKey.elements,
|
|
@@ -9893,6 +12173,7 @@ var BITS = {
|
|
|
9893
12173
|
{
|
|
9894
12174
|
key: ConfigKey.property_ratingLevelStart,
|
|
9895
12175
|
jsonKey: "ratingLevelStart.level",
|
|
12176
|
+
exportJsonKey: { ratingLevelStart: { level: "$" } },
|
|
9896
12177
|
description: "Start level for the rating survey, used to define the lowest rating",
|
|
9897
12178
|
format: TagFormat.number,
|
|
9898
12179
|
chain: [
|
|
@@ -9906,6 +12187,7 @@ var BITS = {
|
|
|
9906
12187
|
{
|
|
9907
12188
|
key: ConfigKey.property_ratingLevelEnd,
|
|
9908
12189
|
jsonKey: "ratingLevelEnd.level",
|
|
12190
|
+
exportJsonKey: { ratingLevelEnd: { level: "$" } },
|
|
9909
12191
|
description: "End level for the rating survey, used to define the highest rating",
|
|
9910
12192
|
format: TagFormat.number,
|
|
9911
12193
|
chain: [
|
|
@@ -10057,14 +12339,8 @@ var BITS = {
|
|
|
10057
12339
|
format: TagFormat.bitmarkText
|
|
10058
12340
|
},
|
|
10059
12341
|
{
|
|
10060
|
-
key: ConfigKey.
|
|
10061
|
-
description: "Background wallpaper for
|
|
10062
|
-
chain: [
|
|
10063
|
-
{
|
|
10064
|
-
key: ConfigKey.group_resourceImageCommon,
|
|
10065
|
-
description: "Common resource image tags for images"
|
|
10066
|
-
}
|
|
10067
|
-
]
|
|
12342
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
12343
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
10068
12344
|
},
|
|
10069
12345
|
{
|
|
10070
12346
|
key: ConfigKey.group_resourceBitTags,
|
|
@@ -10441,12 +12717,48 @@ var BITS = {
|
|
|
10441
12717
|
format: TagFormat.plainText
|
|
10442
12718
|
},
|
|
10443
12719
|
{
|
|
12720
|
+
// PLAN-067 Edit #1: true-false-1's `+` / `-` emit a flat
|
|
12721
|
+
// `{ statement, isCorrect }` at bit root (single-statement bit),
|
|
12722
|
+
// not a `choices[]` array. Format is bitmarkText so the statement
|
|
12723
|
+
// body renders as a ProseMirror tree, matching reference fixtures.
|
|
12724
|
+
exportJsonKey: { statement: "$", isCorrect: true },
|
|
10444
12725
|
key: ConfigKey.tag_true,
|
|
10445
|
-
description: "Tag for the true option in the true/false question"
|
|
12726
|
+
description: "Tag for the true option in the true/false question",
|
|
12727
|
+
format: TagFormat.bitmarkText
|
|
10446
12728
|
},
|
|
10447
12729
|
{
|
|
12730
|
+
exportJsonKey: { statement: "$", isCorrect: false },
|
|
10448
12731
|
key: ConfigKey.tag_false,
|
|
10449
|
-
description: "Tag for the false option in the true/false question"
|
|
12732
|
+
description: "Tag for the false option in the true/false question",
|
|
12733
|
+
format: TagFormat.bitmarkText
|
|
12734
|
+
},
|
|
12735
|
+
{
|
|
12736
|
+
// Override inherited @example from group_standardTags: boolean root
|
|
12737
|
+
// example. Note: the legacy reference parser ties the bare-form
|
|
12738
|
+
// example value to `statement.isCorrect`, but the statement is not
|
|
12739
|
+
// yet emitted when this tag fires at bit-header. The pattern below
|
|
12740
|
+
// emits a literal `true` for bare/synthesized and `$` for valued —
|
|
12741
|
+
// sufficient for `[+...]` (correct) statements which dominate the
|
|
12742
|
+
// fixtures; `[-...]` (incorrect) bits with bare `[@example]` would
|
|
12743
|
+
// need either a runtime extension or an explicit `[@example:false]`.
|
|
12744
|
+
//
|
|
12745
|
+
// Format is `boolean` so `[@example:false]` coerces to JSON `false`
|
|
12746
|
+
// (a natural default that gets stripped in optimised mode, matching
|
|
12747
|
+
// BPG's `rootExampleType: boolean`). PlainText would emit the
|
|
12748
|
+
// STRING `"false"` which doesn't strip.
|
|
12749
|
+
key: ConfigKey.property_example,
|
|
12750
|
+
exportJsonKey: [
|
|
12751
|
+
{ "@keyonly": { isExample: true, example: true } },
|
|
12752
|
+
{ "@absent": { isExample: true, example: true } },
|
|
12753
|
+
// `[@example:false]`: emit `isExample: true` only — `example: false`
|
|
12754
|
+
// is the natural default for boolean, stripped in optimised mode.
|
|
12755
|
+
// Mirrors BPG `removeUnwantedProperties` `ignoreAllFalse: true`.
|
|
12756
|
+
{ "@value=false": { isExample: true } },
|
|
12757
|
+
{ isExample: true, example: "$" }
|
|
12758
|
+
],
|
|
12759
|
+
description: "The example flag for the bit (boolean)",
|
|
12760
|
+
format: TagFormat.boolean,
|
|
12761
|
+
nullable: true
|
|
10450
12762
|
}
|
|
10451
12763
|
],
|
|
10452
12764
|
rootExampleType: ExampleType.boolean
|
|
@@ -10470,6 +12782,18 @@ var BITS = {
|
|
|
10470
12782
|
key: ConfigKey.property_labelFalse,
|
|
10471
12783
|
description: "Label for the false option in the true/false question",
|
|
10472
12784
|
format: TagFormat.plainText
|
|
12785
|
+
},
|
|
12786
|
+
{
|
|
12787
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
12788
|
+
key: ConfigKey.property_example,
|
|
12789
|
+
exportJsonKey: [
|
|
12790
|
+
{ "@keyonly": { isExample: true } },
|
|
12791
|
+
{ "@absent": { isExample: true } },
|
|
12792
|
+
{ isExample: true, example: "$" }
|
|
12793
|
+
],
|
|
12794
|
+
description: "The example(s) for the bit",
|
|
12795
|
+
format: TagFormat.bitmarkText,
|
|
12796
|
+
nullable: true
|
|
10473
12797
|
}
|
|
10474
12798
|
],
|
|
10475
12799
|
cardSet: CardSetConfigKey.statements
|
|
@@ -10659,6 +12983,11 @@ var BITS = {
|
|
|
10659
12983
|
baseBitType: BitType2.vendorStripePricingTable,
|
|
10660
12984
|
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",
|
|
10661
12985
|
tags: [
|
|
12986
|
+
{
|
|
12987
|
+
key: ConfigKey.property_stripePricingTableDescriptiveName,
|
|
12988
|
+
description: "Descriptive name for the Stripe pricing table",
|
|
12989
|
+
format: TagFormat.plainText
|
|
12990
|
+
},
|
|
10662
12991
|
{
|
|
10663
12992
|
key: ConfigKey.property_printOnRequestCustomerId,
|
|
10664
12993
|
description: "Print-on-request customer ID, used to identify the customer for the print-on-request flow",
|
|
@@ -11029,6 +13358,8 @@ var Config = class {
|
|
|
11029
13358
|
maxCount: 1,
|
|
11030
13359
|
chain: tag.chain,
|
|
11031
13360
|
jsonKey: tag.jsonKey,
|
|
13361
|
+
exportJsonKey: tag.exportJsonKey,
|
|
13362
|
+
hasExportJsonKey: tag.hasExportJsonKey,
|
|
11032
13363
|
deprecated: tag.deprecated
|
|
11033
13364
|
});
|
|
11034
13365
|
finalResourceTags[k] = newTag;
|
|
@@ -11133,7 +13464,7 @@ var instance2 = new Config();
|
|
|
11133
13464
|
// src/generated/package_info.ts
|
|
11134
13465
|
var PACKAGE_INFO = {
|
|
11135
13466
|
"name": "@gmb/bitmark-parser-generator",
|
|
11136
|
-
"version": "5.
|
|
13467
|
+
"version": "5.24.0",
|
|
11137
13468
|
"author": "Get More Brain Ltd",
|
|
11138
13469
|
"license": "ISC",
|
|
11139
13470
|
"description": "A bitmark parser and generator using Peggy.js"
|
|
@@ -11727,6 +14058,8 @@ var NodeType = {
|
|
|
11727
14058
|
gmbExternalShopItems: "gmbExternalShopItems",
|
|
11728
14059
|
groupTag: "groupTag",
|
|
11729
14060
|
groupTagValue: "groupTagValue",
|
|
14061
|
+
gUri: "gUri",
|
|
14062
|
+
gUriValue: "gUriValue",
|
|
11730
14063
|
handInAcceptFileType: "handInAcceptFileType",
|
|
11731
14064
|
handInAcceptFileTypeValue: "handInAcceptFileTypeValue",
|
|
11732
14065
|
handInInstruction: "handInInstruction",
|
|
@@ -12069,6 +14402,8 @@ var NodeType = {
|
|
|
12069
14402
|
solution: "solution",
|
|
12070
14403
|
solutions: "solutions",
|
|
12071
14404
|
solutionsValue: "solutionsValue",
|
|
14405
|
+
sourceBB: "sourceBB",
|
|
14406
|
+
sourceBBValue: "sourceBBValue",
|
|
12072
14407
|
sourceDocument: "sourceDocument",
|
|
12073
14408
|
sourceDocumentValue: "sourceDocumentValue",
|
|
12074
14409
|
sourceRL: "sourceRL",
|
|
@@ -12094,6 +14429,8 @@ var NodeType = {
|
|
|
12094
14429
|
stillImageFilmLink: "stillImageFilmLink",
|
|
12095
14430
|
stripePricingTableId: "stripePricingTableId",
|
|
12096
14431
|
stripePricingTableIdValue: "stripePricingTableIdValue",
|
|
14432
|
+
stripePricingTableDescriptiveName: "stripePricingTableDescriptiveName",
|
|
14433
|
+
stripePricingTableDescriptiveNameValue: "stripePricingTableDescriptiveNameValue",
|
|
12097
14434
|
stripePublishableKey: "stripePublishableKey",
|
|
12098
14435
|
stripePublishableKeyValue: "stripePublishableKeyValue",
|
|
12099
14436
|
subject: "subject",
|
|
@@ -24949,6 +27286,7 @@ var Builder = class extends BaseBuilder {
|
|
|
24949
27286
|
isCommented: data.isCommented,
|
|
24950
27287
|
// Properties
|
|
24951
27288
|
id: this.toAstProperty(bitType, ConfigKey.property_id, data.id, options),
|
|
27289
|
+
gUri: this.toAstProperty(bitType, ConfigKey.property_gUri, data.gUri, options),
|
|
24952
27290
|
internalComment: this.toAstProperty(
|
|
24953
27291
|
bitType,
|
|
24954
27292
|
ConfigKey.property_internalComment,
|
|
@@ -25160,6 +27498,7 @@ var Builder = class extends BaseBuilder {
|
|
|
25160
27498
|
data.extractorInternal,
|
|
25161
27499
|
options
|
|
25162
27500
|
),
|
|
27501
|
+
sourceBB: this.normaliseSourceBB(data.sourceBB),
|
|
25163
27502
|
levelCEFRp: this.toAstProperty(
|
|
25164
27503
|
bitType,
|
|
25165
27504
|
ConfigKey.property_levelCEFRp,
|
|
@@ -25517,6 +27856,12 @@ var Builder = class extends BaseBuilder {
|
|
|
25517
27856
|
data.stripePricingTableId,
|
|
25518
27857
|
options
|
|
25519
27858
|
),
|
|
27859
|
+
stripePricingTableDescriptiveName: this.toAstProperty(
|
|
27860
|
+
bitType,
|
|
27861
|
+
ConfigKey.property_stripePricingTableDescriptiveName,
|
|
27862
|
+
data.stripePricingTableDescriptiveName,
|
|
27863
|
+
options
|
|
27864
|
+
),
|
|
25520
27865
|
stripePublishableKey: this.toAstProperty(
|
|
25521
27866
|
bitType,
|
|
25522
27867
|
ConfigKey.property_stripePublishableKey,
|
|
@@ -26180,6 +28525,19 @@ var Builder = class extends BaseBuilder {
|
|
|
26180
28525
|
nodes = Object.values(combinedNodes);
|
|
26181
28526
|
return nodes.length > 0 ? nodes : void 0;
|
|
26182
28527
|
}
|
|
28528
|
+
/**
|
|
28529
|
+
* Normalise a sourceBB input into the AST shape (always number[][]).
|
|
28530
|
+
* Accepts a single 4-number tuple or an array of tuples; returns undefined when empty.
|
|
28531
|
+
*/
|
|
28532
|
+
normaliseSourceBB(data) {
|
|
28533
|
+
if (data == null) return void 0;
|
|
28534
|
+
if (!Array.isArray(data) || data.length === 0) return void 0;
|
|
28535
|
+
const isNested = data.some(Array.isArray);
|
|
28536
|
+
const tuples = (isNested ? data : [data]).filter(
|
|
28537
|
+
(t) => Array.isArray(t) && t.length === 4 && t.every((n) => typeof n === "number")
|
|
28538
|
+
);
|
|
28539
|
+
return tuples.length > 0 ? tuples : void 0;
|
|
28540
|
+
}
|
|
26183
28541
|
/**
|
|
26184
28542
|
* Build groupTag node
|
|
26185
28543
|
*
|
|
@@ -28499,6 +30857,23 @@ var BitmarkGenerator = class extends AstWalkerGenerator {
|
|
|
28499
30857
|
format: TagFormat.plainText
|
|
28500
30858
|
});
|
|
28501
30859
|
}
|
|
30860
|
+
// bitmarkAst -> bits -> bitsValue -> sourceBB
|
|
30861
|
+
enter_sourceBB(node, route) {
|
|
30862
|
+
const parent = this.getParentNode(route);
|
|
30863
|
+
if (parent?.key !== NodeType.bitsValue) return false;
|
|
30864
|
+
const tuples = node.value;
|
|
30865
|
+
if (!Array.isArray(tuples) || tuples.length === 0) return false;
|
|
30866
|
+
this.writeProperty(
|
|
30867
|
+
"sourceBB",
|
|
30868
|
+
tuples.map((t) => t.join(", ")),
|
|
30869
|
+
route,
|
|
30870
|
+
{
|
|
30871
|
+
format: TagFormat.plainText,
|
|
30872
|
+
array: true
|
|
30873
|
+
}
|
|
30874
|
+
);
|
|
30875
|
+
return false;
|
|
30876
|
+
}
|
|
28502
30877
|
// bitmarkAst -> bits -> bitsValue -> questions -> questionsValue -> additionalSolutions -> additionalSolutionsValue
|
|
28503
30878
|
leaf_additionalSolutionsValue(node, route) {
|
|
28504
30879
|
const parent = this.getParentNode(route, 2);
|
|
@@ -30622,6 +32997,16 @@ var JsonGenerator = class extends AstWalkerGenerator {
|
|
|
30622
32997
|
enter_ratingLevelEnd(node, route) {
|
|
30623
32998
|
return this.standardHandler(node, route, NodeType.bitsValue, { array: false });
|
|
30624
32999
|
}
|
|
33000
|
+
// bitmarkAst -> bits -> bitsValue -> sourceBB
|
|
33001
|
+
enter_sourceBB(node, route) {
|
|
33002
|
+
const tuples = node.value;
|
|
33003
|
+
const parent = this.getParentNode(route);
|
|
33004
|
+
if (parent?.key !== NodeType.bitsValue) return false;
|
|
33005
|
+
if (tuples && tuples.length > 0) {
|
|
33006
|
+
this.bitJson.sourceBB = tuples.length === 1 ? tuples[0] : tuples;
|
|
33007
|
+
}
|
|
33008
|
+
return false;
|
|
33009
|
+
}
|
|
30625
33010
|
// bitmarkAst -> bits -> bitsValue -> productId
|
|
30626
33011
|
enter_productId(node, route) {
|
|
30627
33012
|
const productIds = node.value;
|
|
@@ -33704,6 +36089,7 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
33704
36089
|
const cardSetType = bitConfig.cardSet?.configKey;
|
|
33705
36090
|
switch (cardSetType) {
|
|
33706
36091
|
case CardSetConfigKey.flashcard:
|
|
36092
|
+
case CardSetConfigKey.flashcard1:
|
|
33707
36093
|
case CardSetConfigKey.definitionList:
|
|
33708
36094
|
result = parseFlashcardOrDefinitionList(context, bitType, processedCardSet);
|
|
33709
36095
|
break;
|
|
@@ -33717,6 +36103,7 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
33717
36103
|
result = parseFeedback(context, bitType, processedCardSet);
|
|
33718
36104
|
break;
|
|
33719
36105
|
case CardSetConfigKey.quiz:
|
|
36106
|
+
case CardSetConfigKey.quizResponses:
|
|
33720
36107
|
result = parseQuiz(context, bitType, processedCardSet, choicesV1, responsesV1);
|
|
33721
36108
|
break;
|
|
33722
36109
|
case CardSetConfigKey.questions:
|
|
@@ -33743,6 +36130,7 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
33743
36130
|
break;
|
|
33744
36131
|
case CardSetConfigKey.clozeList:
|
|
33745
36132
|
case CardSetConfigKey.exampleBitList:
|
|
36133
|
+
case CardSetConfigKey.pageFooterSections:
|
|
33746
36134
|
case CardSetConfigKey.bookReferenceList:
|
|
33747
36135
|
result = parseCardBits(context, bitType, textFormat, processedCardSet);
|
|
33748
36136
|
break;
|
|
@@ -35300,6 +37688,17 @@ function propertyContentProcessor(context, contentDepth, tagsConfig, content, ta
|
|
|
35300
37688
|
format: TextFormat2.bitmarkText,
|
|
35301
37689
|
location: TextLocation2.tag
|
|
35302
37690
|
});
|
|
37691
|
+
case TagFormat.coordinates:
|
|
37692
|
+
const coordRaw = instance3.unbreakscape(v2, {
|
|
37693
|
+
format: TextFormat2.plainText,
|
|
37694
|
+
location: TextLocation2.tag
|
|
37695
|
+
});
|
|
37696
|
+
if (coordRaw == null) return void 0;
|
|
37697
|
+
const coordParts = coordRaw.split(",").map((p) => instance6.asNumber(p.trim()));
|
|
37698
|
+
if (coordParts.length !== 4 || coordParts.some((n) => n == null)) {
|
|
37699
|
+
return void 0;
|
|
37700
|
+
}
|
|
37701
|
+
return coordParts;
|
|
35303
37702
|
}
|
|
35304
37703
|
}
|
|
35305
37704
|
return instance3.unbreakscape(v2, {
|
|
@@ -35336,6 +37735,8 @@ function propertyContentProcessor(context, contentDepth, tagsConfig, content, ta
|
|
|
35336
37735
|
minCount: 1,
|
|
35337
37736
|
chain: void 0,
|
|
35338
37737
|
jsonKey: void 0,
|
|
37738
|
+
exportJsonKey: void 0,
|
|
37739
|
+
hasExportJsonKey: false,
|
|
35339
37740
|
format: TagFormat.bitmarkText,
|
|
35340
37741
|
values: void 0,
|
|
35341
37742
|
defaultValue: void 0,
|
|
@@ -35346,19 +37747,18 @@ function propertyContentProcessor(context, contentDepth, tagsConfig, content, ta
|
|
|
35346
37747
|
}
|
|
35347
37748
|
|
|
35348
37749
|
// src/parser/bitmark/peg/contentProcessors/ReferenceTagContentProcessor.ts
|
|
35349
|
-
function referenceTagContentProcessor(
|
|
35350
|
-
const { value } = content;
|
|
37750
|
+
function referenceTagContentProcessor(context, _contentDepth, tagsConfig, content, target) {
|
|
37751
|
+
const { value, chain } = content;
|
|
35351
37752
|
const trimmedStringValue = stringUtils.trimmedString(value);
|
|
35352
|
-
|
|
35353
|
-
|
|
35354
|
-
|
|
35355
|
-
|
|
35356
|
-
|
|
35357
|
-
|
|
35358
|
-
|
|
35359
|
-
|
|
35360
|
-
|
|
35361
|
-
});
|
|
37753
|
+
target.reference = instance3.unbreakscape(trimmedStringValue, {
|
|
37754
|
+
format: TextFormat2.bitmarkText,
|
|
37755
|
+
location: TextLocation2.tag
|
|
37756
|
+
});
|
|
37757
|
+
if (Array.isArray(chain) && chain.length > 0) {
|
|
37758
|
+
const sub = context.bitContentProcessor(ContentDepth.Chain, tagsConfig, chain);
|
|
37759
|
+
if (sub.reference != null) {
|
|
37760
|
+
target.referenceEnd = sub.reference;
|
|
37761
|
+
}
|
|
35362
37762
|
}
|
|
35363
37763
|
}
|
|
35364
37764
|
|
|
@@ -36044,7 +38444,6 @@ var BitmarkPegParserProcessor = class {
|
|
|
36044
38444
|
result.markConfig = [];
|
|
36045
38445
|
result.extraProperties = {};
|
|
36046
38446
|
result.internalComments = [];
|
|
36047
|
-
let seenReference = false;
|
|
36048
38447
|
let inFooter = false;
|
|
36049
38448
|
const bodyParts = [];
|
|
36050
38449
|
let bodyTextPart = instance3.EMPTY_STRING;
|
|
@@ -36080,15 +38479,7 @@ var BitmarkPegParserProcessor = class {
|
|
|
36080
38479
|
defaultTagContentProcessor(this.context, contentDepth, tagsConfig, content, result);
|
|
36081
38480
|
break;
|
|
36082
38481
|
case TypeKey.Reference:
|
|
36083
|
-
referenceTagContentProcessor(
|
|
36084
|
-
this.context,
|
|
36085
|
-
contentDepth,
|
|
36086
|
-
tagsConfig,
|
|
36087
|
-
content,
|
|
36088
|
-
result,
|
|
36089
|
-
seenReference
|
|
36090
|
-
);
|
|
36091
|
-
seenReference = true;
|
|
38482
|
+
referenceTagContentProcessor(this.context, contentDepth, tagsConfig, content, result);
|
|
36092
38483
|
break;
|
|
36093
38484
|
case TypeKey.Title:
|
|
36094
38485
|
titleTagContentProcessor(this.context, contentDepth, tagsConfig, content, result);
|
|
@@ -40468,6 +42859,117 @@ var JsonStringGenerator = class {
|
|
|
40468
42859
|
}
|
|
40469
42860
|
};
|
|
40470
42861
|
|
|
42862
|
+
// src/utils/BoundingBox.ts
|
|
42863
|
+
function toBbox(arr) {
|
|
42864
|
+
if (!Array.isArray(arr) || arr.length !== 4) return null;
|
|
42865
|
+
if (!arr.every(Number.isFinite)) return null;
|
|
42866
|
+
return [arr[0], arr[1], arr[2], arr[3]];
|
|
42867
|
+
}
|
|
42868
|
+
function parseSourceBB(sourceBB) {
|
|
42869
|
+
if (sourceBB == null) return [];
|
|
42870
|
+
if (!Array.isArray(sourceBB) || sourceBB.length === 0) return [];
|
|
42871
|
+
const isNested = sourceBB.some(Array.isArray);
|
|
42872
|
+
const candidates = isNested ? sourceBB : [sourceBB];
|
|
42873
|
+
const out = [];
|
|
42874
|
+
for (const candidate of candidates) {
|
|
42875
|
+
const box = toBbox(candidate);
|
|
42876
|
+
if (box) out.push(box);
|
|
42877
|
+
}
|
|
42878
|
+
return out;
|
|
42879
|
+
}
|
|
42880
|
+
function boundingBoxIntersects(a, b) {
|
|
42881
|
+
return a[0] < b[2] && a[2] > b[0] && a[1] < b[3] && a[3] > b[1];
|
|
42882
|
+
}
|
|
42883
|
+
function boundingBoxUnion(boxes) {
|
|
42884
|
+
if (boxes.length === 0) return null;
|
|
42885
|
+
let [x0, y0, x1, y1] = boxes[0];
|
|
42886
|
+
for (let i = 1; i < boxes.length; i++) {
|
|
42887
|
+
const b = boxes[i];
|
|
42888
|
+
if (b[0] < x0) x0 = b[0];
|
|
42889
|
+
if (b[1] < y0) y0 = b[1];
|
|
42890
|
+
if (b[2] > x1) x1 = b[2];
|
|
42891
|
+
if (b[3] > y1) y1 = b[3];
|
|
42892
|
+
}
|
|
42893
|
+
return [x0, y0, x1, y1];
|
|
42894
|
+
}
|
|
42895
|
+
var BoundingBoxIndex = class _BoundingBoxIndex {
|
|
42896
|
+
constructor(entries) {
|
|
42897
|
+
__publicField(this, "_entries");
|
|
42898
|
+
__publicField(this, "bitmarkParser", new BitmarkParserGenerator());
|
|
42899
|
+
this._entries = entries;
|
|
42900
|
+
}
|
|
42901
|
+
/**
|
|
42902
|
+
* Build an index from already-parsed bits. Bits without a parseable
|
|
42903
|
+
* `sourceBB` are dropped. Order of the input is preserved.
|
|
42904
|
+
*
|
|
42905
|
+
* Pass `options.sourceRL` to scope the index to a single source page —
|
|
42906
|
+
* bits whose `sourceRL` doesn't match (or is absent) are excluded.
|
|
42907
|
+
*/
|
|
42908
|
+
static fromBits(wrappers, options) {
|
|
42909
|
+
const filterSourceRL = options?.sourceRL;
|
|
42910
|
+
const entries = [];
|
|
42911
|
+
for (const wrapper of wrappers) {
|
|
42912
|
+
if (!wrapper?.bit) continue;
|
|
42913
|
+
if (filterSourceRL !== void 0 && wrapper.bit.sourceRL !== filterSourceRL) {
|
|
42914
|
+
continue;
|
|
42915
|
+
}
|
|
42916
|
+
const boxes = parseSourceBB(wrapper.bit.sourceBB);
|
|
42917
|
+
if (boxes.length === 0) continue;
|
|
42918
|
+
entries.push({ bit: wrapper.bit, wrapper, boxes });
|
|
42919
|
+
}
|
|
42920
|
+
return new _BoundingBoxIndex(entries);
|
|
42921
|
+
}
|
|
42922
|
+
/** All bits with at least one valid `sourceBB`, in input order. */
|
|
42923
|
+
get entries() {
|
|
42924
|
+
return this._entries;
|
|
42925
|
+
}
|
|
42926
|
+
/**
|
|
42927
|
+
* Bits whose ANY `sourceBB` box intersects `query` (strict overlap —
|
|
42928
|
+
* touching-only edges do NOT count as an intersection).
|
|
42929
|
+
*/
|
|
42930
|
+
intersecting(query) {
|
|
42931
|
+
const matches = [];
|
|
42932
|
+
for (const entry of this._entries) {
|
|
42933
|
+
if (entry.boxes.some((box) => boundingBoxIntersects(query, box))) {
|
|
42934
|
+
matches.push(entry);
|
|
42935
|
+
}
|
|
42936
|
+
}
|
|
42937
|
+
return matches;
|
|
42938
|
+
}
|
|
42939
|
+
/**
|
|
42940
|
+
* Flat list of every individual `sourceBB` box that intersects `query`.
|
|
42941
|
+
* For a multi-box bit, only the boxes that themselves intersected are
|
|
42942
|
+
* returned.
|
|
42943
|
+
*/
|
|
42944
|
+
intersectingBoxes(query) {
|
|
42945
|
+
const matches = [];
|
|
42946
|
+
for (const entry of this._entries) {
|
|
42947
|
+
for (const box of entry.boxes) {
|
|
42948
|
+
if (boundingBoxIntersects(query, box)) matches.push(box);
|
|
42949
|
+
}
|
|
42950
|
+
}
|
|
42951
|
+
return matches;
|
|
42952
|
+
}
|
|
42953
|
+
/**
|
|
42954
|
+
* Smallest axis-aligned box that fully encloses every individual `sourceBB`
|
|
42955
|
+
* box that intersected the query. For a multi-box bit, only the boxes that
|
|
42956
|
+
* themselves intersected contribute to the union — non-intersecting boxes
|
|
42957
|
+
* from the same bit are ignored. Returns `null` if no box matches.
|
|
42958
|
+
*/
|
|
42959
|
+
enclosingBoundingBox(query) {
|
|
42960
|
+
return boundingBoxUnion(this.intersectingBoxes(query));
|
|
42961
|
+
}
|
|
42962
|
+
/** Render selected bits back to bitmark text. Empty input returns `''`. */
|
|
42963
|
+
toBitmark(entries) {
|
|
42964
|
+
if (entries.length === 0) return "";
|
|
42965
|
+
const wrappers = entries.map((e) => e.wrapper);
|
|
42966
|
+
return this.bitmarkParser.convert(wrappers, {
|
|
42967
|
+
outputFormat: Output.bitmark,
|
|
42968
|
+
bitmarkOptions: { prettifyJson: true }
|
|
42969
|
+
});
|
|
42970
|
+
}
|
|
42971
|
+
};
|
|
42972
|
+
|
|
40471
42973
|
// src/index.ts
|
|
40472
42974
|
init();
|
|
40473
42975
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -40481,6 +42983,7 @@ init();
|
|
|
40481
42983
|
BitmarkStringGenerator,
|
|
40482
42984
|
BitmarkVersion,
|
|
40483
42985
|
BodyTextFormat,
|
|
42986
|
+
BoundingBoxIndex,
|
|
40484
42987
|
Builder,
|
|
40485
42988
|
CardSetVersion,
|
|
40486
42989
|
InfoFormat,
|