@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
|
@@ -278,6 +278,7 @@ var BitType2 = {
|
|
|
278
278
|
footNote: "foot-note",
|
|
279
279
|
formFreeText: "form-free-text",
|
|
280
280
|
formula: "formula",
|
|
281
|
+
formulaImage: "formula-image",
|
|
281
282
|
gapText: "gap-text",
|
|
282
283
|
gapTextInstructionGrouped: "gap-text-instruction-grouped",
|
|
283
284
|
glossaryTerm: "glossary-term",
|
|
@@ -702,8 +703,10 @@ var TagFormat = {
|
|
|
702
703
|
// If the value is treated as a boolean
|
|
703
704
|
invertedBoolean: "invertedBoolean",
|
|
704
705
|
// If the value is treated as a boolean with the value inverted (e.g. isLongAnswer ==> isShortAnswer = false)
|
|
705
|
-
enumeration: "enumeration"
|
|
706
|
+
enumeration: "enumeration",
|
|
706
707
|
// If the value is treated as an enumeration (the value is a string that must be one of a predefined set of values)
|
|
708
|
+
coordinates: "coordinates"
|
|
709
|
+
// Comma-separated list of 4 numbers (e.g. bounding-box x, y, x1, y1)
|
|
707
710
|
};
|
|
708
711
|
|
|
709
712
|
// src/model/enum/TextFormat.ts
|
|
@@ -726,10 +729,12 @@ var TextFormat2 = {
|
|
|
726
729
|
import "@ncoderz/superenum";
|
|
727
730
|
var CardSetConfigKey = {
|
|
728
731
|
flashcard: "flashcard",
|
|
732
|
+
flashcard1: "flashcard1",
|
|
729
733
|
definitionList: "definitionList",
|
|
730
734
|
elements: "elements",
|
|
731
735
|
statements: "statements",
|
|
732
736
|
quiz: "quiz",
|
|
737
|
+
quizResponses: "quizResponses",
|
|
733
738
|
feedback: "feedback",
|
|
734
739
|
questions: "questions",
|
|
735
740
|
matchPairs: "matchPairs",
|
|
@@ -741,6 +746,7 @@ var CardSetConfigKey = {
|
|
|
741
746
|
pronunciationTable: "pronunciationTable",
|
|
742
747
|
botActionResponses: "botActionResponses",
|
|
743
748
|
exampleBitList: "exampleBitList",
|
|
749
|
+
pageFooterSections: "pageFooterSections",
|
|
744
750
|
clozeList: "clozeList",
|
|
745
751
|
ingredients: "ingredients",
|
|
746
752
|
// DEPRECATED - TO BE REMOVED IN THE FUTURE
|
|
@@ -788,7 +794,11 @@ var AbstractTagConfig = class {
|
|
|
788
794
|
// Default: 0
|
|
789
795
|
__publicField(this, "chain");
|
|
790
796
|
__publicField(this, "jsonKey");
|
|
791
|
-
//
|
|
797
|
+
// Legacy string-form jsonKey
|
|
798
|
+
__publicField(this, "exportJsonKey");
|
|
799
|
+
// New JSON-pattern jsonKey (export-only)
|
|
800
|
+
__publicField(this, "hasExportJsonKey");
|
|
801
|
+
// True iff exportJsonKey was explicitly set
|
|
792
802
|
__publicField(this, "deprecated");
|
|
793
803
|
this.type = params.type;
|
|
794
804
|
this.configKey = params.configKey;
|
|
@@ -797,6 +807,8 @@ var AbstractTagConfig = class {
|
|
|
797
807
|
this.minCount = params.minCount;
|
|
798
808
|
this.chain = params.chain;
|
|
799
809
|
this.jsonKey = params.jsonKey;
|
|
810
|
+
this.exportJsonKey = params.exportJsonKey;
|
|
811
|
+
this.hasExportJsonKey = params.hasExportJsonKey;
|
|
800
812
|
this.deprecated = params.deprecated;
|
|
801
813
|
}
|
|
802
814
|
};
|
|
@@ -806,7 +818,6 @@ var MarkupTagConfig = class extends AbstractTagConfig {
|
|
|
806
818
|
constructor(params) {
|
|
807
819
|
super({
|
|
808
820
|
type: BitTagConfigKeyType.tag,
|
|
809
|
-
jsonKey: void 0,
|
|
810
821
|
...params
|
|
811
822
|
});
|
|
812
823
|
__publicField(this, "type", BitTagConfigKeyType.tag);
|
|
@@ -918,8 +929,8 @@ var ResourceTagConfig = class extends AbstractTagConfig {
|
|
|
918
929
|
|
|
919
930
|
// src/model/config/CardVariantConfig.ts
|
|
920
931
|
var CardVariantConfig = class {
|
|
921
|
-
//
|
|
922
|
-
constructor(tags2, bodyAllowed, bodyRequired, repeatCount, jsonKey) {
|
|
932
|
+
// Body text format. Default: bitmark++
|
|
933
|
+
constructor(tags2, bodyAllowed, bodyRequired, repeatCount, jsonKey, exportJsonKey, hasExportJsonKey = false, format) {
|
|
923
934
|
__publicField(this, "tags");
|
|
924
935
|
__publicField(this, "bodyAllowed");
|
|
925
936
|
// Default: true
|
|
@@ -929,11 +940,19 @@ var CardVariantConfig = class {
|
|
|
929
940
|
// Default: 1
|
|
930
941
|
// JSON mapping fields
|
|
931
942
|
__publicField(this, "jsonKey");
|
|
943
|
+
// JSON path for body text (legacy)
|
|
944
|
+
__publicField(this, "exportJsonKey");
|
|
945
|
+
// New JSON-pattern jsonKey
|
|
946
|
+
__publicField(this, "hasExportJsonKey");
|
|
947
|
+
__publicField(this, "format");
|
|
932
948
|
this.tags = tags2;
|
|
933
949
|
this.bodyAllowed = bodyAllowed == null ? true : bodyAllowed;
|
|
934
950
|
this.bodyRequired = bodyRequired;
|
|
935
951
|
this.repeatCount = repeatCount;
|
|
936
952
|
this.jsonKey = jsonKey;
|
|
953
|
+
this.exportJsonKey = exportJsonKey;
|
|
954
|
+
this.hasExportJsonKey = hasExportJsonKey;
|
|
955
|
+
this.format = format;
|
|
937
956
|
}
|
|
938
957
|
toString(options) {
|
|
939
958
|
const opts = Object.assign({}, options);
|
|
@@ -957,14 +976,18 @@ ${tag.toString(opts)}`;
|
|
|
957
976
|
|
|
958
977
|
// src/model/config/CardSideConfig.ts
|
|
959
978
|
var CardSideConfig = class {
|
|
960
|
-
constructor(name, repeat, variants, jsonKey) {
|
|
979
|
+
constructor(name, repeat, variants, jsonKey, exportJsonKey, hasExportJsonKey = false) {
|
|
961
980
|
__publicField(this, "name");
|
|
962
981
|
__publicField(this, "repeat");
|
|
963
982
|
__publicField(this, "jsonKey");
|
|
983
|
+
__publicField(this, "exportJsonKey");
|
|
984
|
+
__publicField(this, "hasExportJsonKey");
|
|
964
985
|
__publicField(this, "variants");
|
|
965
986
|
this.name = name;
|
|
966
987
|
this.repeat = repeat;
|
|
967
988
|
this.jsonKey = jsonKey;
|
|
989
|
+
this.exportJsonKey = exportJsonKey;
|
|
990
|
+
this.hasExportJsonKey = hasExportJsonKey;
|
|
968
991
|
this.variants = variants;
|
|
969
992
|
}
|
|
970
993
|
toString(options) {
|
|
@@ -986,13 +1009,17 @@ var CardSideConfig = class {
|
|
|
986
1009
|
|
|
987
1010
|
// src/model/config/CardSetConfig.ts
|
|
988
1011
|
var CardSetConfig = class {
|
|
989
|
-
constructor(configKey, jsonKey, sections, sides) {
|
|
1012
|
+
constructor(configKey, jsonKey, exportJsonKey, hasExportJsonKey, sections, sides) {
|
|
990
1013
|
__publicField(this, "configKey");
|
|
991
1014
|
__publicField(this, "jsonKey");
|
|
1015
|
+
__publicField(this, "exportJsonKey");
|
|
1016
|
+
__publicField(this, "hasExportJsonKey");
|
|
992
1017
|
__publicField(this, "sections");
|
|
993
1018
|
__publicField(this, "sides");
|
|
994
1019
|
this.configKey = configKey;
|
|
995
1020
|
this.jsonKey = jsonKey;
|
|
1021
|
+
this.exportJsonKey = exportJsonKey;
|
|
1022
|
+
this.hasExportJsonKey = hasExportJsonKey;
|
|
996
1023
|
this.sections = sections;
|
|
997
1024
|
this.sides = sides;
|
|
998
1025
|
}
|
|
@@ -1136,12 +1163,17 @@ var groupKeys = {
|
|
|
1136
1163
|
group_standardAllBits: "group_standardAllBits",
|
|
1137
1164
|
group_standardItemLead: "group_standardItemLead",
|
|
1138
1165
|
group_standardItemLeadInstructionHint: "group_standardItemLeadInstructionHint",
|
|
1166
|
+
group_standardInstructionHint: "group_standardInstructionHint",
|
|
1139
1167
|
group_standardTags: "group_standardTags",
|
|
1168
|
+
group_standardTagsNoItemLead: "group_standardTagsNoItemLead",
|
|
1140
1169
|
group_imageSource: "group_imageSource",
|
|
1141
1170
|
group_technicalTerm: "group_technicalTerm",
|
|
1142
1171
|
group_person: "group_person",
|
|
1143
1172
|
group_gap: "group_gap",
|
|
1144
1173
|
group_trueFalse: "group_trueFalse",
|
|
1174
|
+
group_trueFalseInlineHighlight: "group_trueFalseInlineHighlight",
|
|
1175
|
+
group_trueFalseInlineSelect: "group_trueFalseInlineSelect",
|
|
1176
|
+
group_trueFalseResponses: "group_trueFalseResponses",
|
|
1145
1177
|
group_markConfig: "group_markConfig",
|
|
1146
1178
|
group_mark: "group_mark",
|
|
1147
1179
|
group_bookCommon: "group_bookCommon",
|
|
@@ -1149,14 +1181,18 @@ var groupKeys = {
|
|
|
1149
1181
|
group_advertisingCommon: "group_advertisingCommon",
|
|
1150
1182
|
group_platformStylesCommon: "group_platformStylesCommon",
|
|
1151
1183
|
group_quizCommon: "group_quizCommon",
|
|
1184
|
+
group_backgroundWallpaper: "group_backgroundWallpaper",
|
|
1185
|
+
group_imageNoZoom: "group_imageNoZoom",
|
|
1152
1186
|
group_resourceBitTags: "group_resourceBitTags",
|
|
1153
1187
|
group_resourceCommon: "group_resourceCommon",
|
|
1154
1188
|
group_resourceImageCommon: "group_resourceImageCommon",
|
|
1189
|
+
group_resourceImageCommonNoZoom: "group_resourceImageCommonNoZoom",
|
|
1155
1190
|
group_resourceAudioCommon: "group_resourceAudioCommon",
|
|
1156
1191
|
group_resourceVideoCommon: "group_resourceVideoCommon",
|
|
1157
1192
|
group_resourceIcon: "group_resourceIcon",
|
|
1158
1193
|
// Alias for image
|
|
1159
1194
|
group_resourceImage: "group_resourceImage",
|
|
1195
|
+
group_resourceImageNoZoom: "group_resourceImageNoZoom",
|
|
1160
1196
|
group_resourceImageEmbed: "group_resourceImageEmbed",
|
|
1161
1197
|
group_resourceImageLink: "group_resourceImageLink",
|
|
1162
1198
|
group_resourceImageResponsive: "group_resourceImageResponsive",
|
|
@@ -1287,6 +1323,7 @@ var propertyKeys = {
|
|
|
1287
1323
|
property_formula: "@formula",
|
|
1288
1324
|
property_fullName: "@fullName",
|
|
1289
1325
|
property_groupTag: "@groupTag",
|
|
1326
|
+
property_gUri: "@gUri",
|
|
1290
1327
|
property_handInAcceptFileType: "@handInAcceptFileType",
|
|
1291
1328
|
property_handInInstruction: "@handInInstruction",
|
|
1292
1329
|
property_handInRequirement: "@handInRequirement",
|
|
@@ -1422,6 +1459,7 @@ var propertyKeys = {
|
|
|
1422
1459
|
property_siteName: "@siteName",
|
|
1423
1460
|
property_size: "@size",
|
|
1424
1461
|
property_slug: "@slug",
|
|
1462
|
+
property_sourceBB: "@sourceBB",
|
|
1425
1463
|
property_sourceDocument: "@sourceDocument",
|
|
1426
1464
|
property_sourceRL: "@sourceRL",
|
|
1427
1465
|
property_spaceId: "@spaceId",
|
|
@@ -1431,6 +1469,7 @@ var propertyKeys = {
|
|
|
1431
1469
|
property_src4x: "@src4x",
|
|
1432
1470
|
property_srcAlt: "@srcAlt",
|
|
1433
1471
|
property_stripePricingTableId: "@stripePricingTableId",
|
|
1472
|
+
property_stripePricingTableDescriptiveName: "@stripePricingTableDescriptiveName",
|
|
1434
1473
|
property_stripePublishableKey: "@stripePublishableKey",
|
|
1435
1474
|
property_subject: "@subject",
|
|
1436
1475
|
property_subtype: "@subtype",
|
|
@@ -2175,25 +2214,159 @@ var CARDSETS = {
|
|
|
2175
2214
|
//
|
|
2176
2215
|
[CardSetConfigKey.flashcard]: {
|
|
2177
2216
|
jsonKey: "cards",
|
|
2217
|
+
exportJsonKey: { cards: "$" },
|
|
2218
|
+
sides: [
|
|
2219
|
+
{
|
|
2220
|
+
name: "question",
|
|
2221
|
+
variants: [
|
|
2222
|
+
{
|
|
2223
|
+
jsonKey: "question.text",
|
|
2224
|
+
exportJsonKey: [{ "@absent": { question: {} } }, { question: { text: "$" } }],
|
|
2225
|
+
tags: [
|
|
2226
|
+
{
|
|
2227
|
+
key: ConfigKey.group_standardTags,
|
|
2228
|
+
description: "Standard tags for the flashcard."
|
|
2229
|
+
},
|
|
2230
|
+
{
|
|
2231
|
+
exportJsonKey: { title: "$" },
|
|
2232
|
+
key: ConfigKey.tag_title,
|
|
2233
|
+
description: "Title of the flashcard."
|
|
2234
|
+
},
|
|
2235
|
+
{
|
|
2236
|
+
key: ConfigKey.group_resourceIcon,
|
|
2237
|
+
description: "Icon resource for the flashcard.",
|
|
2238
|
+
jsonKey: "question.icon|resource(type=image, key=image)",
|
|
2239
|
+
exportJsonKey: { question: { icon: { type: "image", image: { src: "$" } } } }
|
|
2240
|
+
},
|
|
2241
|
+
{
|
|
2242
|
+
key: ConfigKey.property_example,
|
|
2243
|
+
exportJsonKey: [
|
|
2244
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2245
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2246
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2247
|
+
],
|
|
2248
|
+
description: "Example marker for the flashcard question.",
|
|
2249
|
+
format: TagFormat.bitmarkText,
|
|
2250
|
+
nullable: true
|
|
2251
|
+
}
|
|
2252
|
+
]
|
|
2253
|
+
}
|
|
2254
|
+
]
|
|
2255
|
+
},
|
|
2256
|
+
{
|
|
2257
|
+
name: "answer",
|
|
2258
|
+
variants: [
|
|
2259
|
+
{
|
|
2260
|
+
jsonKey: "answer.text",
|
|
2261
|
+
exportJsonKey: [{ "@absent": { answer: {} } }, { answer: { text: "$" } }],
|
|
2262
|
+
tags: [
|
|
2263
|
+
{
|
|
2264
|
+
key: ConfigKey.group_standardTags,
|
|
2265
|
+
description: "Standard tags for the flashcard."
|
|
2266
|
+
},
|
|
2267
|
+
{
|
|
2268
|
+
exportJsonKey: { title: "$" },
|
|
2269
|
+
key: ConfigKey.tag_title,
|
|
2270
|
+
description: "Title of the flashcard."
|
|
2271
|
+
},
|
|
2272
|
+
{
|
|
2273
|
+
key: ConfigKey.group_resourceIcon,
|
|
2274
|
+
description: "Icon resource for the flashcard.",
|
|
2275
|
+
jsonKey: "answer.icon|resource(type=image, key=image)",
|
|
2276
|
+
exportJsonKey: { answer: { icon: { type: "image", image: { src: "$" } } } }
|
|
2277
|
+
},
|
|
2278
|
+
{
|
|
2279
|
+
key: ConfigKey.property_example,
|
|
2280
|
+
exportJsonKey: [
|
|
2281
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2282
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2283
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2284
|
+
],
|
|
2285
|
+
description: "Example marker for the flashcard answer.",
|
|
2286
|
+
format: TagFormat.bitmarkText,
|
|
2287
|
+
nullable: true
|
|
2288
|
+
}
|
|
2289
|
+
]
|
|
2290
|
+
},
|
|
2291
|
+
{
|
|
2292
|
+
jsonKey: "alternativeAnswers[].text",
|
|
2293
|
+
exportJsonKey: { alternativeAnswers: [{ text: "$" }] },
|
|
2294
|
+
tags: [
|
|
2295
|
+
{
|
|
2296
|
+
key: ConfigKey.group_standardTags,
|
|
2297
|
+
description: "Standard tags for the flashcard."
|
|
2298
|
+
},
|
|
2299
|
+
{
|
|
2300
|
+
exportJsonKey: { title: "$" },
|
|
2301
|
+
key: ConfigKey.tag_title,
|
|
2302
|
+
description: "Title of the flashcard."
|
|
2303
|
+
},
|
|
2304
|
+
{
|
|
2305
|
+
key: ConfigKey.group_resourceIcon,
|
|
2306
|
+
description: "Icon resource for the flashcard.",
|
|
2307
|
+
jsonKey: "alternativeAnswers[].icon|resource(type=image, key=image)",
|
|
2308
|
+
exportJsonKey: {
|
|
2309
|
+
alternativeAnswers: [{ icon: { type: "image", image: { src: "$" } } }]
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
],
|
|
2313
|
+
repeatCount: Count.infinity
|
|
2314
|
+
}
|
|
2315
|
+
]
|
|
2316
|
+
}
|
|
2317
|
+
]
|
|
2318
|
+
},
|
|
2319
|
+
//
|
|
2320
|
+
// flashcard1 — single-card variant of flashcard. Same shape, but capped
|
|
2321
|
+
// at one card via `sections.default.maxCount = 1` (PLAN-085). Used by
|
|
2322
|
+
// the `flashcard-1` bit type; the multi-card `flashcard` and
|
|
2323
|
+
// `q-and-a-card` bit types continue to use the unbounded `flashcard`
|
|
2324
|
+
// cardset.
|
|
2325
|
+
//
|
|
2326
|
+
[CardSetConfigKey.flashcard1]: {
|
|
2327
|
+
jsonKey: "cards",
|
|
2328
|
+
exportJsonKey: { cards: "$" },
|
|
2329
|
+
sections: {
|
|
2330
|
+
default: {
|
|
2331
|
+
jsonKey: "cards",
|
|
2332
|
+
exportJsonKey: { cards: "$" },
|
|
2333
|
+
isDefault: true,
|
|
2334
|
+
maxCount: 1
|
|
2335
|
+
}
|
|
2336
|
+
},
|
|
2178
2337
|
sides: [
|
|
2179
2338
|
{
|
|
2180
2339
|
name: "question",
|
|
2181
2340
|
variants: [
|
|
2182
2341
|
{
|
|
2183
2342
|
jsonKey: "question.text",
|
|
2343
|
+
exportJsonKey: [{ "@absent": { question: {} } }, { question: { text: "$" } }],
|
|
2184
2344
|
tags: [
|
|
2185
2345
|
{
|
|
2186
2346
|
key: ConfigKey.group_standardTags,
|
|
2187
2347
|
description: "Standard tags for the flashcard."
|
|
2188
2348
|
},
|
|
2189
2349
|
{
|
|
2350
|
+
exportJsonKey: { title: "$" },
|
|
2190
2351
|
key: ConfigKey.tag_title,
|
|
2191
2352
|
description: "Title of the flashcard."
|
|
2192
2353
|
},
|
|
2193
2354
|
{
|
|
2194
2355
|
key: ConfigKey.group_resourceIcon,
|
|
2195
2356
|
description: "Icon resource for the flashcard.",
|
|
2196
|
-
jsonKey: "question.icon|resource(type=image, key=image)"
|
|
2357
|
+
jsonKey: "question.icon|resource(type=image, key=image)",
|
|
2358
|
+
exportJsonKey: { question: { icon: { type: "image", image: { src: "$" } } } }
|
|
2359
|
+
},
|
|
2360
|
+
{
|
|
2361
|
+
key: ConfigKey.property_example,
|
|
2362
|
+
exportJsonKey: [
|
|
2363
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2364
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2365
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2366
|
+
],
|
|
2367
|
+
description: "Example marker for the flashcard question.",
|
|
2368
|
+
format: TagFormat.bitmarkText,
|
|
2369
|
+
nullable: true
|
|
2197
2370
|
}
|
|
2198
2371
|
]
|
|
2199
2372
|
}
|
|
@@ -2204,37 +2377,56 @@ var CARDSETS = {
|
|
|
2204
2377
|
variants: [
|
|
2205
2378
|
{
|
|
2206
2379
|
jsonKey: "answer.text",
|
|
2380
|
+
exportJsonKey: [{ "@absent": { answer: {} } }, { answer: { text: "$" } }],
|
|
2207
2381
|
tags: [
|
|
2208
2382
|
{
|
|
2209
2383
|
key: ConfigKey.group_standardTags,
|
|
2210
2384
|
description: "Standard tags for the flashcard."
|
|
2211
2385
|
},
|
|
2212
2386
|
{
|
|
2387
|
+
exportJsonKey: { title: "$" },
|
|
2213
2388
|
key: ConfigKey.tag_title,
|
|
2214
2389
|
description: "Title of the flashcard."
|
|
2215
2390
|
},
|
|
2216
2391
|
{
|
|
2217
2392
|
key: ConfigKey.group_resourceIcon,
|
|
2218
2393
|
description: "Icon resource for the flashcard.",
|
|
2219
|
-
jsonKey: "answer.icon|resource(type=image, key=image)"
|
|
2394
|
+
jsonKey: "answer.icon|resource(type=image, key=image)",
|
|
2395
|
+
exportJsonKey: { answer: { icon: { type: "image", image: { src: "$" } } } }
|
|
2396
|
+
},
|
|
2397
|
+
{
|
|
2398
|
+
key: ConfigKey.property_example,
|
|
2399
|
+
exportJsonKey: [
|
|
2400
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2401
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2402
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2403
|
+
],
|
|
2404
|
+
description: "Example marker for the flashcard answer.",
|
|
2405
|
+
format: TagFormat.bitmarkText,
|
|
2406
|
+
nullable: true
|
|
2220
2407
|
}
|
|
2221
2408
|
]
|
|
2222
2409
|
},
|
|
2223
2410
|
{
|
|
2224
2411
|
jsonKey: "alternativeAnswers[].text",
|
|
2412
|
+
exportJsonKey: { alternativeAnswers: [{ text: "$" }] },
|
|
2225
2413
|
tags: [
|
|
2226
2414
|
{
|
|
2227
2415
|
key: ConfigKey.group_standardTags,
|
|
2228
2416
|
description: "Standard tags for the flashcard."
|
|
2229
2417
|
},
|
|
2230
2418
|
{
|
|
2419
|
+
exportJsonKey: { title: "$" },
|
|
2231
2420
|
key: ConfigKey.tag_title,
|
|
2232
2421
|
description: "Title of the flashcard."
|
|
2233
2422
|
},
|
|
2234
2423
|
{
|
|
2235
2424
|
key: ConfigKey.group_resourceIcon,
|
|
2236
2425
|
description: "Icon resource for the flashcard.",
|
|
2237
|
-
jsonKey: "alternativeAnswers[].icon|resource(type=image, key=image)"
|
|
2426
|
+
jsonKey: "alternativeAnswers[].icon|resource(type=image, key=image)",
|
|
2427
|
+
exportJsonKey: {
|
|
2428
|
+
alternativeAnswers: [{ icon: { type: "image", image: { src: "$" } } }]
|
|
2429
|
+
}
|
|
2238
2430
|
}
|
|
2239
2431
|
],
|
|
2240
2432
|
repeatCount: Count.infinity
|
|
@@ -2248,12 +2440,14 @@ var CARDSETS = {
|
|
|
2248
2440
|
//
|
|
2249
2441
|
[CardSetConfigKey.definitionList]: {
|
|
2250
2442
|
jsonKey: "definitions",
|
|
2443
|
+
exportJsonKey: { definitions: "$" },
|
|
2251
2444
|
sides: [
|
|
2252
2445
|
{
|
|
2253
2446
|
name: "term",
|
|
2254
2447
|
variants: [
|
|
2255
2448
|
{
|
|
2256
2449
|
jsonKey: "term.text",
|
|
2450
|
+
exportJsonKey: [{ "@absent": { term: {} } }, { term: { text: "$" } }],
|
|
2257
2451
|
tags: [
|
|
2258
2452
|
{
|
|
2259
2453
|
key: ConfigKey.group_standardTags,
|
|
@@ -2263,13 +2457,26 @@ var CARDSETS = {
|
|
|
2263
2457
|
key: ConfigKey.tag_title,
|
|
2264
2458
|
description: "Title of the definition.",
|
|
2265
2459
|
format: TagFormat.plainText,
|
|
2266
|
-
jsonKey: "^heading.forKeys"
|
|
2460
|
+
jsonKey: "^heading.forKeys",
|
|
2461
|
+
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2267
2462
|
},
|
|
2268
2463
|
{
|
|
2269
2464
|
key: ConfigKey.group_resourceIcon,
|
|
2270
2465
|
description: "Icon resource for the definition.",
|
|
2271
2466
|
format: TagFormat.plainText,
|
|
2272
|
-
jsonKey: "term.icon|resource(type=image, key=image)"
|
|
2467
|
+
jsonKey: "term.icon|resource(type=image, key=image)",
|
|
2468
|
+
exportJsonKey: { term: { icon: { type: "image", image: { src: "$" } } } }
|
|
2469
|
+
},
|
|
2470
|
+
{
|
|
2471
|
+
key: ConfigKey.property_example,
|
|
2472
|
+
exportJsonKey: [
|
|
2473
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2474
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2475
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2476
|
+
],
|
|
2477
|
+
description: "Example marker for the definition term.",
|
|
2478
|
+
format: TagFormat.bitmarkText,
|
|
2479
|
+
nullable: true
|
|
2273
2480
|
}
|
|
2274
2481
|
]
|
|
2275
2482
|
}
|
|
@@ -2280,6 +2487,7 @@ var CARDSETS = {
|
|
|
2280
2487
|
variants: [
|
|
2281
2488
|
{
|
|
2282
2489
|
jsonKey: "definition.text",
|
|
2490
|
+
exportJsonKey: [{ "@absent": { definition: {} } }, { definition: { text: "$" } }],
|
|
2283
2491
|
tags: [
|
|
2284
2492
|
{
|
|
2285
2493
|
key: ConfigKey.group_standardTags,
|
|
@@ -2289,30 +2497,48 @@ var CARDSETS = {
|
|
|
2289
2497
|
key: ConfigKey.tag_title,
|
|
2290
2498
|
description: "Title of the definition.",
|
|
2291
2499
|
format: TagFormat.plainText,
|
|
2292
|
-
jsonKey: "^heading.forValues"
|
|
2500
|
+
jsonKey: "^heading.forValues",
|
|
2501
|
+
exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
|
|
2293
2502
|
},
|
|
2294
2503
|
{
|
|
2295
2504
|
key: ConfigKey.group_resourceIcon,
|
|
2296
2505
|
description: "Icon resource for the definition.",
|
|
2297
|
-
jsonKey: "definition.icon|resource(type=image, key=image)"
|
|
2506
|
+
jsonKey: "definition.icon|resource(type=image, key=image)",
|
|
2507
|
+
exportJsonKey: { definition: { icon: { type: "image", image: { src: "$" } } } }
|
|
2508
|
+
},
|
|
2509
|
+
{
|
|
2510
|
+
key: ConfigKey.property_example,
|
|
2511
|
+
exportJsonKey: [
|
|
2512
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2513
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2514
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2515
|
+
],
|
|
2516
|
+
description: "Example marker for the definition.",
|
|
2517
|
+
format: TagFormat.bitmarkText,
|
|
2518
|
+
nullable: true
|
|
2298
2519
|
}
|
|
2299
2520
|
]
|
|
2300
2521
|
},
|
|
2301
2522
|
{
|
|
2302
2523
|
jsonKey: "alternativeDefinitions[].text",
|
|
2524
|
+
exportJsonKey: { alternativeDefinitions: [{ text: "$" }] },
|
|
2303
2525
|
tags: [
|
|
2304
2526
|
{
|
|
2305
2527
|
key: ConfigKey.group_standardTags,
|
|
2306
2528
|
description: "Standard tags for the definition."
|
|
2307
2529
|
},
|
|
2308
2530
|
{
|
|
2531
|
+
exportJsonKey: { title: "$" },
|
|
2309
2532
|
key: ConfigKey.tag_title,
|
|
2310
2533
|
description: "Title of the definition."
|
|
2311
2534
|
},
|
|
2312
2535
|
{
|
|
2313
2536
|
key: ConfigKey.group_resourceIcon,
|
|
2314
2537
|
description: "Icon resource for the definition.",
|
|
2315
|
-
jsonKey: "alternativeDefinitions[].icon|resource(type=image, key=image)"
|
|
2538
|
+
jsonKey: "alternativeDefinitions[].icon|resource(type=image, key=image)",
|
|
2539
|
+
exportJsonKey: {
|
|
2540
|
+
alternativeDefinitions: [{ icon: { type: "image", image: { src: "$" } } }]
|
|
2541
|
+
}
|
|
2316
2542
|
}
|
|
2317
2543
|
],
|
|
2318
2544
|
repeatCount: Count.infinity
|
|
@@ -2326,37 +2552,96 @@ var CARDSETS = {
|
|
|
2326
2552
|
//
|
|
2327
2553
|
[CardSetConfigKey.matchPairs]: {
|
|
2328
2554
|
jsonKey: "pairs",
|
|
2555
|
+
exportJsonKey: { pairs: "$" },
|
|
2329
2556
|
sides: [
|
|
2330
2557
|
{
|
|
2331
2558
|
name: "key",
|
|
2332
2559
|
variants: [
|
|
2333
2560
|
{
|
|
2334
2561
|
jsonKey: "key",
|
|
2562
|
+
exportJsonKey: { key: "$" },
|
|
2563
|
+
format: TextFormat2.plainText,
|
|
2335
2564
|
tags: [
|
|
2336
2565
|
{
|
|
2337
2566
|
key: ConfigKey.group_standardTags,
|
|
2338
2567
|
description: "Standard tags for the match pair."
|
|
2339
2568
|
},
|
|
2569
|
+
{
|
|
2570
|
+
// Pair-level example: emit `isExample` alongside `example`
|
|
2571
|
+
// (matches OLD parser's per-pair allow-list behaviour).
|
|
2572
|
+
//
|
|
2573
|
+
// PLAN-074: a valued cascade source (`[@example:V]` anywhere
|
|
2574
|
+
// in the cardset) fills each pair's `example` with `V`
|
|
2575
|
+
// once per pair from the keys-side cascade fire (single
|
|
2576
|
+
// parsed_variant per pair — no per-value duplication).
|
|
2577
|
+
//
|
|
2578
|
+
// PLAN-076 NOTE: matchPairs (TAG 415) KEEPS `example: '$'`
|
|
2579
|
+
// at the pair-object level. BPG `parseMatchPairs`
|
|
2580
|
+
// (`CardContentProcessor.ts:714-723`) emits ONE example
|
|
2581
|
+
// per PAIR (the `exampleCard` accumulator), placed at the
|
|
2582
|
+
// pair object. Unlike matchMatrix (per-cell example),
|
|
2583
|
+
// matchPairs has no nested per-cell layer, so the pair-key
|
|
2584
|
+
// `[@example:V]` must double-emit as the visible field.
|
|
2585
|
+
// Confirmed via `chaining` fixture: `match-solution-grouped`
|
|
2586
|
+
// expects `example: "packen"` at pair-object level from
|
|
2587
|
+
// `die Koffer[%1][@example:packen]`. Original PLAN-076
|
|
2588
|
+
// draft applied to both keys-side tags; the matchPairs
|
|
2589
|
+
// half was reverted after fixture parity testing.
|
|
2590
|
+
key: ConfigKey.property_example,
|
|
2591
|
+
exportJsonKey: [
|
|
2592
|
+
{ "@keyonly": { isExample: true, "@bit": { isExample: true } } },
|
|
2593
|
+
{
|
|
2594
|
+
predicates: ["@absent", { $cascade: "*" }],
|
|
2595
|
+
rule: {
|
|
2596
|
+
isExample: true,
|
|
2597
|
+
example: "$cascade",
|
|
2598
|
+
"@bit": { isExample: true }
|
|
2599
|
+
}
|
|
2600
|
+
},
|
|
2601
|
+
{ "@absent": { isExample: true } },
|
|
2602
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2603
|
+
],
|
|
2604
|
+
description: "Example marker / value on the match pair.",
|
|
2605
|
+
format: TagFormat.bitmarkText,
|
|
2606
|
+
nullable: true
|
|
2607
|
+
},
|
|
2340
2608
|
{
|
|
2341
2609
|
key: ConfigKey.tag_title,
|
|
2342
2610
|
description: "Title of the match pair.",
|
|
2343
2611
|
format: TagFormat.plainText,
|
|
2344
|
-
jsonKey: "^heading.forKeys"
|
|
2612
|
+
jsonKey: "^heading.forKeys",
|
|
2613
|
+
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2345
2614
|
},
|
|
2346
2615
|
{
|
|
2616
|
+
// PLAN-084: gate the key-side `@absent → $ancestor` cascade
|
|
2617
|
+
// synth with `@variantLacksTag=isCaseSensitive` so the rule
|
|
2618
|
+
// only fires when NO variant in the active card explicitly
|
|
2619
|
+
// carries `[@isCaseSensitive]`. When a value-side variant
|
|
2620
|
+
// carries the tag (e.g. `[@isCaseSensitive:false]`), the
|
|
2621
|
+
// synth is skipped here; the value-side explicit fire owns
|
|
2622
|
+
// the pair-level emission.
|
|
2347
2623
|
key: ConfigKey.property_isCaseSensitive,
|
|
2624
|
+
exportJsonKey: [
|
|
2625
|
+
{
|
|
2626
|
+
predicates: ["@absent", { "@variantLacksTag": "@isCaseSensitive" }],
|
|
2627
|
+
rule: { isCaseSensitive: "$ancestor" }
|
|
2628
|
+
},
|
|
2629
|
+
{ isCaseSensitive: "$" }
|
|
2630
|
+
],
|
|
2348
2631
|
description: "Property to indicate if the match is case sensitive.",
|
|
2349
2632
|
format: TagFormat.boolean
|
|
2350
2633
|
},
|
|
2351
2634
|
{
|
|
2352
2635
|
key: ConfigKey.resource_audio,
|
|
2353
2636
|
description: "Audio resource for the match pair.",
|
|
2354
|
-
jsonKey: "keyAudio"
|
|
2637
|
+
jsonKey: "keyAudio",
|
|
2638
|
+
exportJsonKey: { keyAudio: "$" }
|
|
2355
2639
|
},
|
|
2356
2640
|
{
|
|
2357
2641
|
key: ConfigKey.resource_image,
|
|
2358
2642
|
description: "Image resource for the match pair.",
|
|
2359
|
-
jsonKey: "keyImage"
|
|
2643
|
+
jsonKey: "keyImage",
|
|
2644
|
+
exportJsonKey: { keyImage: "$" }
|
|
2360
2645
|
}
|
|
2361
2646
|
]
|
|
2362
2647
|
}
|
|
@@ -2368,19 +2653,104 @@ var CARDSETS = {
|
|
|
2368
2653
|
variants: [
|
|
2369
2654
|
{
|
|
2370
2655
|
jsonKey: "values[]",
|
|
2656
|
+
exportJsonKey: { values: ["$"] },
|
|
2657
|
+
format: TextFormat2.plainText,
|
|
2371
2658
|
tags: [
|
|
2372
2659
|
{
|
|
2373
|
-
|
|
2374
|
-
|
|
2660
|
+
// PLAN-084: value-side excludes item/lead/pageNumber/marginNumber.
|
|
2661
|
+
// BPG `parseMatchPairs` does `delete tags.item; delete tags.lead;`
|
|
2662
|
+
// for sideIdx > 0; the schema-side equivalent is to use a
|
|
2663
|
+
// group_standardTags variant that omits group_standardItemLead.
|
|
2664
|
+
key: ConfigKey.group_standardTagsNoItemLead,
|
|
2665
|
+
description: "Standard tags for the match pair (values side, no item/lead)."
|
|
2666
|
+
},
|
|
2667
|
+
{
|
|
2668
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.6: cascade-fired
|
|
2669
|
+
// `@example` from the bit header fills each pair's
|
|
2670
|
+
// `example` with the pair's first value (mirrors BPG's
|
|
2671
|
+
// `fillStringExample(pairs, __defaultExample=values[0])`).
|
|
2672
|
+
//
|
|
2673
|
+
// PLAN-074: the cascade-source-VALUE branch is handled by
|
|
2674
|
+
// TAG 415 (keys side) which fires once per pair — keeping
|
|
2675
|
+
// it here would emit `example` twice per pair (one per
|
|
2676
|
+
// values-side parsed_variant) and merge them into a
|
|
2677
|
+
// multi-paragraph array.
|
|
2678
|
+
//
|
|
2679
|
+
// PLAN-075: bare `$parent` reads the parent variant fire's
|
|
2680
|
+
// source `$` value (the current `++`-iteration's value
|
|
2681
|
+
// text). For single-value pairs this matches the old
|
|
2682
|
+
// `$parent.values[0]`; for multi-value pairs with
|
|
2683
|
+
// `[@example]` attached to a non-first value, it correctly
|
|
2684
|
+
// resolves to that value.
|
|
2685
|
+
//
|
|
2686
|
+
// PLAN-077: dual `[@absent, { '$cascade': '*' }]` rule
|
|
2687
|
+
// routes pair-key `[@example:V]` (a per-pair cascade
|
|
2688
|
+
// source, bound via per-card CascadeCounters scope) and
|
|
2689
|
+
// bit-header `[@example:V]` (cardset cascade) into the
|
|
2690
|
+
// pair-level `example` via `$cascade`. The aggregator in
|
|
2691
|
+
// `populate_variants` fires this rule ONCE per pair (BPG
|
|
2692
|
+
// `parseMatchPairs` `exampleCard` precedence), avoiding
|
|
2693
|
+
// per-iter pollution.
|
|
2694
|
+
key: ConfigKey.property_example,
|
|
2695
|
+
exportJsonKey: [
|
|
2696
|
+
// PLAN-084: bare `[@example]` on a values-side variant fires
|
|
2697
|
+
// once per pair (first-wins, mirrors BPG `parseMatchPairs`
|
|
2698
|
+
// `exampleCard` + `pushDownTree` set-if-null semantic).
|
|
2699
|
+
// `maxEmits: 1` enforced inside the per-pair cascade-counter
|
|
2700
|
+
// scope opened by `build_card_item`.
|
|
2701
|
+
{
|
|
2702
|
+
predicates: ["@keyonly"],
|
|
2703
|
+
maxEmits: 1,
|
|
2704
|
+
rule: {
|
|
2705
|
+
isExample: true,
|
|
2706
|
+
example: "$parent",
|
|
2707
|
+
"@bit": { isExample: true }
|
|
2708
|
+
}
|
|
2709
|
+
},
|
|
2710
|
+
{
|
|
2711
|
+
predicates: ["@absent", { $cascade: "*" }],
|
|
2712
|
+
rule: {
|
|
2713
|
+
isExample: true,
|
|
2714
|
+
example: "$cascade",
|
|
2715
|
+
"@bit": { isExample: true }
|
|
2716
|
+
}
|
|
2717
|
+
},
|
|
2718
|
+
{
|
|
2719
|
+
"@absent": {
|
|
2720
|
+
isExample: true,
|
|
2721
|
+
example: "$parent",
|
|
2722
|
+
"@bit": { isExample: true }
|
|
2723
|
+
}
|
|
2724
|
+
},
|
|
2725
|
+
// PLAN-084: same cap applies to the explicit-value `[@example:V]`
|
|
2726
|
+
// form so per-`++`-iter values-side fires also first-win.
|
|
2727
|
+
{
|
|
2728
|
+
predicates: [],
|
|
2729
|
+
maxEmits: 1,
|
|
2730
|
+
rule: { isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2731
|
+
}
|
|
2732
|
+
],
|
|
2733
|
+
description: "Example marker / value on the match pair (values side).",
|
|
2734
|
+
format: TagFormat.bitmarkText,
|
|
2735
|
+
nullable: true
|
|
2375
2736
|
},
|
|
2376
2737
|
{
|
|
2377
2738
|
key: ConfigKey.tag_title,
|
|
2378
2739
|
description: "Title of the match pair.",
|
|
2379
2740
|
format: TagFormat.plainText,
|
|
2380
|
-
jsonKey: "^heading.forValues"
|
|
2741
|
+
jsonKey: "^heading.forValues",
|
|
2742
|
+
exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
|
|
2381
2743
|
},
|
|
2382
2744
|
{
|
|
2745
|
+
// PLAN-084: symmetric @variantLacksTag gating with the key-side.
|
|
2383
2746
|
key: ConfigKey.property_isCaseSensitive,
|
|
2747
|
+
exportJsonKey: [
|
|
2748
|
+
{
|
|
2749
|
+
predicates: ["@absent", { "@variantLacksTag": "@isCaseSensitive" }],
|
|
2750
|
+
rule: { isCaseSensitive: "$ancestor" }
|
|
2751
|
+
},
|
|
2752
|
+
{ isCaseSensitive: "$" }
|
|
2753
|
+
],
|
|
2384
2754
|
description: "Property to indicate if the match is case sensitive.",
|
|
2385
2755
|
format: TagFormat.boolean
|
|
2386
2756
|
}
|
|
@@ -2396,12 +2766,15 @@ var CARDSETS = {
|
|
|
2396
2766
|
//
|
|
2397
2767
|
[CardSetConfigKey.matchAudioPairs]: {
|
|
2398
2768
|
jsonKey: "pairs",
|
|
2769
|
+
exportJsonKey: { pairs: "$" },
|
|
2399
2770
|
sides: [
|
|
2400
2771
|
{
|
|
2401
2772
|
name: "key",
|
|
2402
2773
|
variants: [
|
|
2403
2774
|
{
|
|
2404
2775
|
jsonKey: "key",
|
|
2776
|
+
exportJsonKey: { key: "$" },
|
|
2777
|
+
format: TextFormat2.plainText,
|
|
2405
2778
|
tags: [
|
|
2406
2779
|
{
|
|
2407
2780
|
key: ConfigKey.group_standardTags,
|
|
@@ -2411,12 +2784,14 @@ var CARDSETS = {
|
|
|
2411
2784
|
key: ConfigKey.tag_title,
|
|
2412
2785
|
description: "Title of the audio match pair.",
|
|
2413
2786
|
format: TagFormat.plainText,
|
|
2414
|
-
jsonKey: "^heading.forKeys"
|
|
2787
|
+
jsonKey: "^heading.forKeys",
|
|
2788
|
+
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2415
2789
|
},
|
|
2416
2790
|
{
|
|
2417
2791
|
key: ConfigKey.resource_audio,
|
|
2418
2792
|
description: "Audio resource for the match pair.",
|
|
2419
|
-
jsonKey: "keyAudio"
|
|
2793
|
+
jsonKey: "keyAudio",
|
|
2794
|
+
exportJsonKey: { keyAudio: "$" }
|
|
2420
2795
|
}
|
|
2421
2796
|
]
|
|
2422
2797
|
}
|
|
@@ -2428,16 +2803,20 @@ var CARDSETS = {
|
|
|
2428
2803
|
variants: [
|
|
2429
2804
|
{
|
|
2430
2805
|
jsonKey: "values[]",
|
|
2806
|
+
exportJsonKey: { values: ["$"] },
|
|
2807
|
+
format: TextFormat2.plainText,
|
|
2431
2808
|
tags: [
|
|
2432
2809
|
{
|
|
2433
|
-
|
|
2434
|
-
|
|
2810
|
+
// PLAN-084: value-side excludes item/lead/pageNumber/marginNumber.
|
|
2811
|
+
key: ConfigKey.group_standardTagsNoItemLead,
|
|
2812
|
+
description: "Standard tags for the audio match pair (values side, no item/lead)."
|
|
2435
2813
|
},
|
|
2436
2814
|
{
|
|
2437
2815
|
key: ConfigKey.tag_title,
|
|
2438
2816
|
description: "Title of the audio match pair.",
|
|
2439
2817
|
format: TagFormat.plainText,
|
|
2440
|
-
jsonKey: "^heading.forValues"
|
|
2818
|
+
jsonKey: "^heading.forValues",
|
|
2819
|
+
exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
|
|
2441
2820
|
},
|
|
2442
2821
|
{
|
|
2443
2822
|
key: ConfigKey.resource_audio,
|
|
@@ -2455,12 +2834,15 @@ var CARDSETS = {
|
|
|
2455
2834
|
//
|
|
2456
2835
|
[CardSetConfigKey.matchImagePairs]: {
|
|
2457
2836
|
jsonKey: "pairs",
|
|
2837
|
+
exportJsonKey: { pairs: "$" },
|
|
2458
2838
|
sides: [
|
|
2459
2839
|
{
|
|
2460
2840
|
name: "key",
|
|
2461
2841
|
variants: [
|
|
2462
2842
|
{
|
|
2463
2843
|
jsonKey: "key",
|
|
2844
|
+
exportJsonKey: { key: "$" },
|
|
2845
|
+
format: TextFormat2.plainText,
|
|
2464
2846
|
tags: [
|
|
2465
2847
|
{
|
|
2466
2848
|
key: ConfigKey.group_standardTags,
|
|
@@ -2470,12 +2852,14 @@ var CARDSETS = {
|
|
|
2470
2852
|
key: ConfigKey.tag_title,
|
|
2471
2853
|
description: "Title of the image match pair.",
|
|
2472
2854
|
format: TagFormat.plainText,
|
|
2473
|
-
jsonKey: "^heading.forKeys"
|
|
2855
|
+
jsonKey: "^heading.forKeys",
|
|
2856
|
+
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2474
2857
|
},
|
|
2475
2858
|
{
|
|
2476
2859
|
key: ConfigKey.resource_image,
|
|
2477
2860
|
description: "Image resource for the match pair.",
|
|
2478
|
-
jsonKey: "keyImage"
|
|
2861
|
+
jsonKey: "keyImage",
|
|
2862
|
+
exportJsonKey: { keyImage: "$" }
|
|
2479
2863
|
}
|
|
2480
2864
|
]
|
|
2481
2865
|
}
|
|
@@ -2487,16 +2871,20 @@ var CARDSETS = {
|
|
|
2487
2871
|
variants: [
|
|
2488
2872
|
{
|
|
2489
2873
|
jsonKey: "values[]",
|
|
2874
|
+
exportJsonKey: { values: ["$"] },
|
|
2875
|
+
format: TextFormat2.plainText,
|
|
2490
2876
|
tags: [
|
|
2491
2877
|
{
|
|
2492
|
-
|
|
2493
|
-
|
|
2878
|
+
// PLAN-084: value-side excludes item/lead/pageNumber/marginNumber.
|
|
2879
|
+
key: ConfigKey.group_standardTagsNoItemLead,
|
|
2880
|
+
description: "Standard tags for the image match pair (values side, no item/lead)."
|
|
2494
2881
|
},
|
|
2495
2882
|
{
|
|
2496
2883
|
key: ConfigKey.tag_title,
|
|
2497
2884
|
description: "Title of the image match pair.",
|
|
2498
2885
|
format: TagFormat.plainText,
|
|
2499
|
-
jsonKey: "^heading.forValues"
|
|
2886
|
+
jsonKey: "^heading.forValues",
|
|
2887
|
+
exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
|
|
2500
2888
|
},
|
|
2501
2889
|
{
|
|
2502
2890
|
key: ConfigKey.resource_image,
|
|
@@ -2514,30 +2902,71 @@ var CARDSETS = {
|
|
|
2514
2902
|
//
|
|
2515
2903
|
[CardSetConfigKey.matchMatrix]: {
|
|
2516
2904
|
jsonKey: "matrix",
|
|
2905
|
+
exportJsonKey: { matrix: "$" },
|
|
2517
2906
|
sides: [
|
|
2518
2907
|
{
|
|
2519
2908
|
name: "key",
|
|
2520
2909
|
variants: [
|
|
2521
2910
|
{
|
|
2522
2911
|
jsonKey: "key",
|
|
2912
|
+
exportJsonKey: { key: "$" },
|
|
2913
|
+
format: TextFormat2.plainText,
|
|
2523
2914
|
tags: [
|
|
2524
2915
|
{
|
|
2525
2916
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2526
2917
|
description: "Standard tags for lead, instruction, and hint."
|
|
2527
2918
|
},
|
|
2528
2919
|
{
|
|
2920
|
+
// PLAN-076: drop `example: '$'` from valued rule — pair-key
|
|
2921
|
+
// `[@example:V]` is consumed as the per-pair cascade source.
|
|
2922
|
+
// PLAN-077 R14 follow-up: investigation showed the fixture
|
|
2923
|
+
// reference is INCONSISTENT — bits without a cardset-level
|
|
2924
|
+
// cascade (e.g. bit 3 `[@example:Y]should be...`) expect
|
|
2925
|
+
// pair-level `example: V` at pair scope, but bits WITH a
|
|
2926
|
+
// cardset cascade (e.g. bit 8 `[@example:99]` in title-row
|
|
2927
|
+
// PLUS pair-key `[@example:Y]`) expect NO pair-level
|
|
2928
|
+
// example. Emitting `example: $` here satisfies bit 3 but
|
|
2929
|
+
// breaks bit 8; dropping it satisfies bit 8 but breaks bit
|
|
2930
|
+
// 3. Conditional emission would require runtime gating on
|
|
2931
|
+
// the cardset cascade scope state. Left dropped pending a
|
|
2932
|
+
// dedicated plan — accepted divergence on bit 3's pair-
|
|
2933
|
+
// level emission (cells still get the per-cell `example`
|
|
2934
|
+
// correctly via PLAN-077 §4.2 + §4.3).
|
|
2529
2935
|
key: ConfigKey.property_example,
|
|
2936
|
+
exportJsonKey: [
|
|
2937
|
+
{
|
|
2938
|
+
"@keyonly": {
|
|
2939
|
+
isExample: true,
|
|
2940
|
+
"@bit": { isExample: true },
|
|
2941
|
+
"@card": { isExample: true }
|
|
2942
|
+
}
|
|
2943
|
+
},
|
|
2944
|
+
{
|
|
2945
|
+
"@absent": {
|
|
2946
|
+
isExample: true,
|
|
2947
|
+
"@bit": { isExample: true },
|
|
2948
|
+
"@card": { isExample: true }
|
|
2949
|
+
}
|
|
2950
|
+
},
|
|
2951
|
+
{ isExample: true, "@bit": { isExample: true }, "@card": { isExample: true } }
|
|
2952
|
+
],
|
|
2530
2953
|
description: "Example text for the match matrix.",
|
|
2531
|
-
format: TagFormat.plainText
|
|
2954
|
+
format: TagFormat.plainText,
|
|
2955
|
+
nullable: true
|
|
2532
2956
|
},
|
|
2533
2957
|
{
|
|
2534
2958
|
key: ConfigKey.tag_title,
|
|
2535
2959
|
description: "Title of the match matrix.",
|
|
2536
2960
|
format: TagFormat.plainText,
|
|
2537
|
-
jsonKey: "^heading.forKeys"
|
|
2961
|
+
jsonKey: "^heading.forKeys",
|
|
2962
|
+
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2538
2963
|
},
|
|
2539
2964
|
{
|
|
2540
2965
|
key: ConfigKey.property_isCaseSensitive,
|
|
2966
|
+
exportJsonKey: [
|
|
2967
|
+
{ "@absent": { isCaseSensitive: "$ancestor" } },
|
|
2968
|
+
{ isCaseSensitive: "$" }
|
|
2969
|
+
],
|
|
2541
2970
|
description: "Property to indicate if the match is case sensitive.",
|
|
2542
2971
|
format: TagFormat.boolean
|
|
2543
2972
|
}
|
|
@@ -2551,24 +2980,103 @@ var CARDSETS = {
|
|
|
2551
2980
|
variants: [
|
|
2552
2981
|
{
|
|
2553
2982
|
jsonKey: "cells[{s}].values[]",
|
|
2983
|
+
exportJsonKey: [
|
|
2984
|
+
// PLAN-085 / R14: the positional-blank emission for an
|
|
2985
|
+
// effectively-absent cell side fires ONLY when the active
|
|
2986
|
+
// card has at least one `[#]` variant fire. This matches
|
|
2987
|
+
// BPG `extractHeadingCard`'s `isHeading` gate: when no
|
|
2988
|
+
// `[#]` exists anywhere in the title card, BPG returns
|
|
2989
|
+
// undefined and no `heading` is emitted. The phantom
|
|
2990
|
+
// `forValues:['']` placeholder is appropriate only when
|
|
2991
|
+
// the card is being treated as a title-row.
|
|
2992
|
+
{
|
|
2993
|
+
predicates: ["@absent", { "@variantHasTag": "#" }],
|
|
2994
|
+
rule: { "@bit": { heading: { forValues: [""] } } }
|
|
2995
|
+
},
|
|
2996
|
+
{ cells: { $s: { values: ["$"] } } }
|
|
2997
|
+
],
|
|
2998
|
+
format: TextFormat2.plainText,
|
|
2554
2999
|
tags: [
|
|
2555
3000
|
{
|
|
2556
3001
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2557
3002
|
description: "Standard tags for lead, instruction, and hint."
|
|
2558
3003
|
},
|
|
2559
3004
|
{
|
|
3005
|
+
// PLAN-075: bare `$parent` reads the parent variant fire's
|
|
3006
|
+
// source `$` value (the current `++`-iteration's cell text).
|
|
3007
|
+
// Replaces `$parent.values[0]` which pinned to position 0
|
|
3008
|
+
// regardless of which `++`-value `[@example]` was on.
|
|
3009
|
+
//
|
|
3010
|
+
// PLAN-077: dual `[@absent, { '$cascade': '*' }]` rule
|
|
3011
|
+
// routes pair-key `[@example:V]` (a per-pair cascade
|
|
3012
|
+
// source, bound via per-card CascadeCounters scope) and
|
|
3013
|
+
// bit-header `[@example:V]` (cardset cascade) into the
|
|
3014
|
+
// per-cell `example` via `$cascade`. The aggregator in
|
|
3015
|
+
// `populate_variants` fires this rule ONCE per cell (BPG
|
|
3016
|
+
// `parseMatchMatrix` `exampleSide` precedence), avoiding
|
|
3017
|
+
// per-iter pollution.
|
|
3018
|
+
// @card scope-shift writes matrix-row container isExample.
|
|
2560
3019
|
key: ConfigKey.property_example,
|
|
3020
|
+
exportJsonKey: [
|
|
3021
|
+
{
|
|
3022
|
+
"@keyonly": {
|
|
3023
|
+
cells: { $s: { isExample: true, example: "$parent" } },
|
|
3024
|
+
"@bit": { isExample: true },
|
|
3025
|
+
"@card": { isExample: true }
|
|
3026
|
+
}
|
|
3027
|
+
},
|
|
3028
|
+
{
|
|
3029
|
+
predicates: ["@absent", { $cascade: "*" }],
|
|
3030
|
+
rule: {
|
|
3031
|
+
cells: { $s: { isExample: true, example: "$cascade" } },
|
|
3032
|
+
"@bit": { isExample: true },
|
|
3033
|
+
"@card": { isExample: true }
|
|
3034
|
+
}
|
|
3035
|
+
},
|
|
3036
|
+
{
|
|
3037
|
+
"@absent": {
|
|
3038
|
+
cells: { $s: { isExample: true, example: "$parent" } },
|
|
3039
|
+
"@bit": { isExample: true },
|
|
3040
|
+
"@card": { isExample: true }
|
|
3041
|
+
}
|
|
3042
|
+
},
|
|
3043
|
+
{
|
|
3044
|
+
cells: { $s: { isExample: true, example: "$" } },
|
|
3045
|
+
"@bit": { isExample: true },
|
|
3046
|
+
"@card": { isExample: true }
|
|
3047
|
+
}
|
|
3048
|
+
],
|
|
2561
3049
|
description: "Example text for the match matrix.",
|
|
2562
|
-
format: TagFormat.
|
|
3050
|
+
format: TagFormat.bitmarkText,
|
|
3051
|
+
nullable: true
|
|
2563
3052
|
},
|
|
2564
3053
|
{
|
|
3054
|
+
// PLAN-085 / R14: bare `[#]` on a value-side emits the
|
|
3055
|
+
// empty-string positional blank into `forValues` so the
|
|
3056
|
+
// array stays aligned with the cell positions (matches BPG
|
|
3057
|
+
// `extractHeadingCard`'s "all value-side headings present"
|
|
3058
|
+
// shape). The `@keyonly` rule is required for two reasons:
|
|
3059
|
+
// 1) it provides an emission for bare `[#]` (the `$` sigil
|
|
3060
|
+
// in the unconditional rule has no source for bare); and
|
|
3061
|
+
// 2) the presence of any `@keyonly` rule disables the
|
|
3062
|
+
// optimised-mode `should_suppress_outcome` strip (see
|
|
3063
|
+
// `forward_emit.rs`) so the resulting `forValues: [""]`
|
|
3064
|
+
// survives the all-natural-defaults check.
|
|
2565
3065
|
key: ConfigKey.tag_title,
|
|
2566
3066
|
description: "Title of the match matrix.",
|
|
2567
3067
|
format: TagFormat.plainText,
|
|
2568
|
-
jsonKey: "^heading.forValues"
|
|
3068
|
+
jsonKey: "^heading.forValues",
|
|
3069
|
+
exportJsonKey: [
|
|
3070
|
+
{ "@keyonly": { "@bit": { heading: { forValues: [""] } } } },
|
|
3071
|
+
{ "@bit": { heading: { forValues: ["$"] } } }
|
|
3072
|
+
]
|
|
2569
3073
|
},
|
|
2570
3074
|
{
|
|
2571
3075
|
key: ConfigKey.property_isCaseSensitive,
|
|
3076
|
+
exportJsonKey: [
|
|
3077
|
+
{ "@absent": { isCaseSensitive: "$ancestor" } },
|
|
3078
|
+
{ isCaseSensitive: "$" }
|
|
3079
|
+
],
|
|
2572
3080
|
description: "Property to indicate if the match is case sensitive.",
|
|
2573
3081
|
format: TagFormat.boolean
|
|
2574
3082
|
}
|
|
@@ -2584,28 +3092,61 @@ var CARDSETS = {
|
|
|
2584
3092
|
//
|
|
2585
3093
|
[CardSetConfigKey.statements]: {
|
|
2586
3094
|
jsonKey: "statements",
|
|
3095
|
+
exportJsonKey: { statements: "$" },
|
|
2587
3096
|
sides: [
|
|
2588
3097
|
{
|
|
2589
3098
|
name: "statement",
|
|
2590
3099
|
variants: [
|
|
2591
3100
|
{
|
|
2592
3101
|
jsonKey: "statement",
|
|
3102
|
+
exportJsonKey: { statement: "$" },
|
|
2593
3103
|
tags: [
|
|
2594
3104
|
{
|
|
2595
3105
|
key: ConfigKey.tag_true,
|
|
2596
3106
|
description: "Tag for true statements.",
|
|
2597
3107
|
jsonKey: "statement|set(isCorrect=true)",
|
|
3108
|
+
exportJsonKey: { statement: "$", isCorrect: true },
|
|
2598
3109
|
maxCount: 1
|
|
2599
3110
|
},
|
|
2600
3111
|
{
|
|
2601
3112
|
key: ConfigKey.tag_false,
|
|
2602
3113
|
description: "Tag for false statements.",
|
|
2603
3114
|
jsonKey: "statement|set(isCorrect=false)",
|
|
3115
|
+
exportJsonKey: { statement: "$", isCorrect: false },
|
|
2604
3116
|
maxCount: 1
|
|
2605
3117
|
},
|
|
2606
3118
|
{
|
|
2607
3119
|
key: ConfigKey.group_standardTags,
|
|
2608
3120
|
description: "Standard tags for the statement."
|
|
3121
|
+
},
|
|
3122
|
+
{
|
|
3123
|
+
// PLAN-072: cascade-fired `@example` from the bit header
|
|
3124
|
+
// fills each statement entry's `example` with the entry's
|
|
3125
|
+
// own `isCorrect`, mirroring BPG's `pushExampleDownTree`
|
|
3126
|
+
// for the statements cardset. Per-array-item strip removes
|
|
3127
|
+
// `example: false` from incorrect entries so only correct
|
|
3128
|
+
// entries retain `example: true`.
|
|
3129
|
+
key: ConfigKey.property_example,
|
|
3130
|
+
exportJsonKey: [
|
|
3131
|
+
{
|
|
3132
|
+
"@keyonly": {
|
|
3133
|
+
isExample: true,
|
|
3134
|
+
example: true,
|
|
3135
|
+
"@bit": { isExample: true }
|
|
3136
|
+
}
|
|
3137
|
+
},
|
|
3138
|
+
{
|
|
3139
|
+
"@absent": {
|
|
3140
|
+
isExample: true,
|
|
3141
|
+
example: "$parent.isCorrect",
|
|
3142
|
+
"@bit": { isExample: true }
|
|
3143
|
+
}
|
|
3144
|
+
},
|
|
3145
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3146
|
+
],
|
|
3147
|
+
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`.",
|
|
3148
|
+
format: TagFormat.boolean,
|
|
3149
|
+
nullable: true
|
|
2609
3150
|
}
|
|
2610
3151
|
],
|
|
2611
3152
|
bodyAllowed: false
|
|
@@ -2619,6 +3160,7 @@ var CARDSETS = {
|
|
|
2619
3160
|
//
|
|
2620
3161
|
[CardSetConfigKey.quiz]: {
|
|
2621
3162
|
jsonKey: "quizzes",
|
|
3163
|
+
exportJsonKey: { quizzes: "$" },
|
|
2622
3164
|
sides: [
|
|
2623
3165
|
{
|
|
2624
3166
|
name: "choices",
|
|
@@ -2633,6 +3175,71 @@ var CARDSETS = {
|
|
|
2633
3175
|
{
|
|
2634
3176
|
key: ConfigKey.group_standardTags,
|
|
2635
3177
|
description: "Standard tags for the quiz."
|
|
3178
|
+
},
|
|
3179
|
+
{
|
|
3180
|
+
// ALIGN-EXAMPLE-CASCADE §3.2: variant-level cascade for
|
|
3181
|
+
// quiz choices is delegated to group_trueFalse's
|
|
3182
|
+
// chain-child `@example` (`+` chain with maxEmits:1 +
|
|
3183
|
+
// `@parent.isCorrect=true`). Variant-level `@absent`
|
|
3184
|
+
// would over-fire on subsequent correct choices and on
|
|
3185
|
+
// incorrect ones — drop it.
|
|
3186
|
+
key: ConfigKey.property_example,
|
|
3187
|
+
exportJsonKey: [
|
|
3188
|
+
{ "@keyonly": { isExample: true, "@bit": { isExample: true } } },
|
|
3189
|
+
{ isExample: true, "@bit": { isExample: true } }
|
|
3190
|
+
],
|
|
3191
|
+
description: "Example marker on the quiz choice (entry-local only; cascade handled by group_trueFalse chain-children).",
|
|
3192
|
+
format: TagFormat.boolean,
|
|
3193
|
+
nullable: true
|
|
3194
|
+
}
|
|
3195
|
+
],
|
|
3196
|
+
bodyAllowed: false
|
|
3197
|
+
}
|
|
3198
|
+
]
|
|
3199
|
+
}
|
|
3200
|
+
]
|
|
3201
|
+
},
|
|
3202
|
+
//
|
|
3203
|
+
// quiz (responses)
|
|
3204
|
+
//
|
|
3205
|
+
[CardSetConfigKey.quizResponses]: {
|
|
3206
|
+
jsonKey: "quizzes",
|
|
3207
|
+
exportJsonKey: { quizzes: "$" },
|
|
3208
|
+
sides: [
|
|
3209
|
+
{
|
|
3210
|
+
name: "responses",
|
|
3211
|
+
variants: [
|
|
3212
|
+
{
|
|
3213
|
+
jsonKey: null,
|
|
3214
|
+
tags: [
|
|
3215
|
+
{
|
|
3216
|
+
key: ConfigKey.group_trueFalseResponses,
|
|
3217
|
+
description: "Group for true/false questions."
|
|
3218
|
+
},
|
|
3219
|
+
{
|
|
3220
|
+
key: ConfigKey.group_standardTags,
|
|
3221
|
+
description: "Standard tags for the quiz."
|
|
3222
|
+
},
|
|
3223
|
+
{
|
|
3224
|
+
// PLAN-072: cascade-fired `@example` from the bit header
|
|
3225
|
+
// fills each response entry's `example` with the entry's
|
|
3226
|
+
// own `isCorrect`, mirroring BPG's `pushExampleDownTree`
|
|
3227
|
+
// for the quiz-responses cardset (statements-style).
|
|
3228
|
+
key: ConfigKey.property_example,
|
|
3229
|
+
exportJsonKey: [
|
|
3230
|
+
{ "@keyonly": { isExample: true, "@bit": { isExample: true } } },
|
|
3231
|
+
{
|
|
3232
|
+
"@absent": {
|
|
3233
|
+
isExample: true,
|
|
3234
|
+
example: "$parent.isCorrect",
|
|
3235
|
+
"@bit": { isExample: true }
|
|
3236
|
+
}
|
|
3237
|
+
},
|
|
3238
|
+
{ isExample: true, "@bit": { isExample: true } }
|
|
3239
|
+
],
|
|
3240
|
+
description: "Example marker on the quiz response; cascade from bit-header fills `example` with the entry\u2019s own `isCorrect`.",
|
|
3241
|
+
format: TagFormat.boolean,
|
|
3242
|
+
nullable: true
|
|
2636
3243
|
}
|
|
2637
3244
|
],
|
|
2638
3245
|
bodyAllowed: false
|
|
@@ -2646,6 +3253,7 @@ var CARDSETS = {
|
|
|
2646
3253
|
//
|
|
2647
3254
|
[CardSetConfigKey.feedback]: {
|
|
2648
3255
|
jsonKey: "feedbacks",
|
|
3256
|
+
exportJsonKey: { feedbacks: "$" },
|
|
2649
3257
|
sides: [
|
|
2650
3258
|
{
|
|
2651
3259
|
name: "choices",
|
|
@@ -2657,6 +3265,73 @@ var CARDSETS = {
|
|
|
2657
3265
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2658
3266
|
description: "Standard tags for lead, instruction, and hint."
|
|
2659
3267
|
},
|
|
3268
|
+
{
|
|
3269
|
+
// Feedback choices: `[+]` / `[-]` map to choice + `requireReason`
|
|
3270
|
+
// (NOT `isCorrect` like trueFalse). Shadow the inherited
|
|
3271
|
+
// `tag_true` / `tag_false` from `group_trueFalse` to emit the
|
|
3272
|
+
// feedback-specific shape.
|
|
3273
|
+
//
|
|
3274
|
+
// Chain @example: `[+ X][@example]` writes
|
|
3275
|
+
// `isExample/example` onto the X choice only. BPG's
|
|
3276
|
+
// `setIsExampleFlags` (Builder.ts:4041-4172) does NOT
|
|
3277
|
+
// iterate `cardNode.feedbacks` — so unlike multipleChoice,
|
|
3278
|
+
// there is no bubble to bit-level or feedbacks-level
|
|
3279
|
+
// isExample. Pattern omits `@bit` scope-shift accordingly.
|
|
3280
|
+
// No `@absent`/`@parent.isCorrect` cascade rules either:
|
|
3281
|
+
// BPG's `pushExampleDownTree` (Builder.ts:3777-3849) has
|
|
3282
|
+
// no feedback dispatch, so bit-header `[@example]` does
|
|
3283
|
+
// not flow into feedback choices.
|
|
3284
|
+
key: ConfigKey.tag_true,
|
|
3285
|
+
exportJsonKey: { choices: [{ choice: "$", requireReason: true }] },
|
|
3286
|
+
description: "Reason-required choice for feedback (`[+]`).",
|
|
3287
|
+
maxCount: Count.infinity,
|
|
3288
|
+
format: TagFormat.plainText,
|
|
3289
|
+
chain: [
|
|
3290
|
+
{
|
|
3291
|
+
key: ConfigKey.property_example,
|
|
3292
|
+
exportJsonKey: [
|
|
3293
|
+
{ "@keyonly": { isExample: true, example: true } },
|
|
3294
|
+
{ isExample: true, example: "$" }
|
|
3295
|
+
],
|
|
3296
|
+
description: "Per-choice example marker for feedback `[+]`.",
|
|
3297
|
+
format: TagFormat.boolean,
|
|
3298
|
+
maxCount: 1,
|
|
3299
|
+
nullable: true
|
|
3300
|
+
},
|
|
3301
|
+
{
|
|
3302
|
+
// `[+ X][! foo]` chains `!` (instruction) onto the
|
|
3303
|
+
// choice; same for `[?]` (hint), `[%]` (item),
|
|
3304
|
+
// `[%2]`/`[%3]`/`[%4]` (lead/pageNumber/marginNumber).
|
|
3305
|
+
// Mirrors group_trueFalse's `+` chain shape.
|
|
3306
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3307
|
+
description: "Item, lead, page number, margin number, instruction and hint chained onto the feedback choice."
|
|
3308
|
+
}
|
|
3309
|
+
]
|
|
3310
|
+
},
|
|
3311
|
+
{
|
|
3312
|
+
key: ConfigKey.tag_false,
|
|
3313
|
+
exportJsonKey: { choices: [{ choice: "$", requireReason: false }] },
|
|
3314
|
+
description: "Reason-not-required choice for feedback (`[-]`).",
|
|
3315
|
+
maxCount: Count.infinity,
|
|
3316
|
+
format: TagFormat.plainText,
|
|
3317
|
+
chain: [
|
|
3318
|
+
{
|
|
3319
|
+
key: ConfigKey.property_example,
|
|
3320
|
+
exportJsonKey: [
|
|
3321
|
+
{ "@keyonly": { isExample: true, example: true } },
|
|
3322
|
+
{ isExample: true, example: "$" }
|
|
3323
|
+
],
|
|
3324
|
+
description: "Per-choice example marker for feedback `[-]`.",
|
|
3325
|
+
format: TagFormat.boolean,
|
|
3326
|
+
maxCount: 1,
|
|
3327
|
+
nullable: true
|
|
3328
|
+
},
|
|
3329
|
+
{
|
|
3330
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3331
|
+
description: "Item, lead, page number, margin number, instruction and hint chained onto the feedback choice."
|
|
3332
|
+
}
|
|
3333
|
+
]
|
|
3334
|
+
},
|
|
2660
3335
|
{
|
|
2661
3336
|
key: ConfigKey.group_trueFalse,
|
|
2662
3337
|
description: "Group for true/false feedback."
|
|
@@ -2665,7 +3340,8 @@ var CARDSETS = {
|
|
|
2665
3340
|
key: ConfigKey.tag_title,
|
|
2666
3341
|
description: "Title of the feedback.",
|
|
2667
3342
|
format: TagFormat.plainText,
|
|
2668
|
-
jsonKey: "^heading.forKeys"
|
|
3343
|
+
jsonKey: "^heading.forKeys",
|
|
3344
|
+
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2669
3345
|
}
|
|
2670
3346
|
],
|
|
2671
3347
|
bodyAllowed: false
|
|
@@ -2676,27 +3352,78 @@ var CARDSETS = {
|
|
|
2676
3352
|
name: "reason",
|
|
2677
3353
|
variants: [
|
|
2678
3354
|
{
|
|
3355
|
+
// PLAN: feedback.reason — Object-only variant pattern. Per
|
|
3356
|
+
// SYNTAX.md §8.1, sibling tag emissions do NOT auto-wrap
|
|
3357
|
+
// under `reason.*`; each tag here spells out the full path.
|
|
3358
|
+
// Body is a plain string (BPG `parseFeedback` uses
|
|
3359
|
+
// `cardBodyStr ?? ''` for `reason.text`).
|
|
2679
3360
|
jsonKey: "reason.text",
|
|
3361
|
+
exportJsonKey: { reason: { text: "$" } },
|
|
3362
|
+
format: TextFormat2.plainText,
|
|
2680
3363
|
tags: [
|
|
2681
3364
|
{
|
|
2682
|
-
|
|
2683
|
-
|
|
3365
|
+
// Instruction lands under reason. Hint/item/lead/etc.
|
|
3366
|
+
// omitted: not exercised by any fixture and BPG's
|
|
3367
|
+
// `parseFeedback` spreads only the tags actually present
|
|
3368
|
+
// — adding the rest can be done lazily as fixtures
|
|
3369
|
+
// require them, with the same `{reason: {…}}` wrapper.
|
|
3370
|
+
key: ConfigKey.tag_instruction,
|
|
3371
|
+
exportJsonKey: { reason: { instruction: "$" } },
|
|
3372
|
+
description: "Instruction for the feedback reason.",
|
|
3373
|
+
format: TagFormat.bitmarkText
|
|
2684
3374
|
},
|
|
2685
3375
|
{
|
|
2686
3376
|
key: ConfigKey.property_reasonableNumOfChars,
|
|
3377
|
+
exportJsonKey: [
|
|
3378
|
+
{ "@absent": { reason: { reasonableNumOfChars: "$ancestor" } } },
|
|
3379
|
+
{ reason: { reasonableNumOfChars: "$" } }
|
|
3380
|
+
],
|
|
2687
3381
|
description: "Property for reasonable number of characters.",
|
|
2688
3382
|
format: TagFormat.number
|
|
2689
3383
|
},
|
|
2690
3384
|
{
|
|
3385
|
+
// ALIGN-EXAMPLE-CASCADE §3.9: `feedback.reason` is NOT in
|
|
3386
|
+
// BPG's `pushExampleDownTree` dispatch — no bit-header
|
|
3387
|
+
// cascade. Local emission only.
|
|
3388
|
+
//
|
|
3389
|
+
// Both `reason.example` and `feedbacks[].example` are
|
|
3390
|
+
// `TextAst` per BPG's schema — paragraph arrays. Format
|
|
3391
|
+
// here is `bitmarkText` so `$` coerces to a paragraph
|
|
3392
|
+
// array at both write sites.
|
|
2691
3393
|
key: ConfigKey.property_example,
|
|
2692
|
-
|
|
2693
|
-
|
|
3394
|
+
exportJsonKey: [
|
|
3395
|
+
{
|
|
3396
|
+
// Bare `[@example]`: reason.example is TextAst — BPG
|
|
3397
|
+
// coerces the boolean default to a paragraph
|
|
3398
|
+
// containing the string "true". feedbacks[].example
|
|
3399
|
+
// is not TextAst, stays a boolean. Two literal writes.
|
|
3400
|
+
"@keyonly": {
|
|
3401
|
+
reason: {
|
|
3402
|
+
isExample: true,
|
|
3403
|
+
example: [{ type: "paragraph", content: [{ text: "true", type: "text" }] }]
|
|
3404
|
+
},
|
|
3405
|
+
isExample: true,
|
|
3406
|
+
example: true,
|
|
3407
|
+
"@bit": { isExample: true }
|
|
3408
|
+
}
|
|
3409
|
+
},
|
|
3410
|
+
{
|
|
3411
|
+
reason: { isExample: true, example: "$" },
|
|
3412
|
+
isExample: true,
|
|
3413
|
+
example: "$",
|
|
3414
|
+
"@bit": { isExample: true }
|
|
3415
|
+
}
|
|
3416
|
+
],
|
|
3417
|
+
description: "Example text for the feedback reason (entry-local only; no bit-header cascade).",
|
|
3418
|
+
format: TagFormat.bitmarkText,
|
|
3419
|
+
nullable: true
|
|
2694
3420
|
},
|
|
2695
3421
|
{
|
|
2696
3422
|
key: ConfigKey.tag_title,
|
|
2697
3423
|
description: "Title of the feedback.",
|
|
2698
3424
|
format: TagFormat.plainText,
|
|
2699
|
-
jsonKey: "^heading.forValues"
|
|
3425
|
+
jsonKey: "^heading.forValues",
|
|
3426
|
+
exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
|
|
2700
3427
|
}
|
|
2701
3428
|
],
|
|
2702
3429
|
bodyAllowed: true
|
|
@@ -2710,21 +3437,29 @@ var CARDSETS = {
|
|
|
2710
3437
|
//
|
|
2711
3438
|
[CardSetConfigKey.questions]: {
|
|
2712
3439
|
jsonKey: "questions",
|
|
3440
|
+
exportJsonKey: { questions: "$" },
|
|
2713
3441
|
sides: [
|
|
2714
3442
|
{
|
|
2715
3443
|
name: "question",
|
|
2716
3444
|
variants: [
|
|
2717
3445
|
{
|
|
2718
3446
|
jsonKey: "question",
|
|
3447
|
+
exportJsonKey: { question: "$" },
|
|
2719
3448
|
tags: [
|
|
2720
3449
|
{
|
|
2721
3450
|
key: ConfigKey.property_reasonableNumOfChars,
|
|
3451
|
+
exportJsonKey: [
|
|
3452
|
+
{ "@absent": { reasonableNumOfChars: "$ancestor" } },
|
|
3453
|
+
{ reasonableNumOfChars: "$" }
|
|
3454
|
+
],
|
|
2722
3455
|
description: "Property for reasonable number of characters.",
|
|
2723
3456
|
format: TagFormat.number
|
|
2724
3457
|
},
|
|
2725
3458
|
{
|
|
3459
|
+
exportJsonKey: { sampleSolution: "$" },
|
|
2726
3460
|
key: ConfigKey.tag_sampleSolution,
|
|
2727
|
-
description: "Sample solution for the question."
|
|
3461
|
+
description: "Sample solution for the question.",
|
|
3462
|
+
format: TagFormat.plainText
|
|
2728
3463
|
},
|
|
2729
3464
|
{
|
|
2730
3465
|
key: ConfigKey.property_sampleSolution,
|
|
@@ -2745,6 +3480,22 @@ var CARDSETS = {
|
|
|
2745
3480
|
{
|
|
2746
3481
|
key: ConfigKey.group_standardTags,
|
|
2747
3482
|
description: "Standard tags for the question."
|
|
3483
|
+
},
|
|
3484
|
+
{
|
|
3485
|
+
// ALIGN-EXAMPLE-CASCADE §3.10: `questions` is NOT in BPG's
|
|
3486
|
+
// `pushExampleDownTree` dispatch — bit-header `[@example]`
|
|
3487
|
+
// does not propagate `example`/`isExample` onto question
|
|
3488
|
+
// entries. Only entry-local `[@example]` fires (handled by
|
|
3489
|
+
// `@keyonly` and the unconditional fallback). No `@absent`
|
|
3490
|
+
// rule.
|
|
3491
|
+
key: ConfigKey.property_example,
|
|
3492
|
+
exportJsonKey: [
|
|
3493
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
3494
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3495
|
+
],
|
|
3496
|
+
description: "Example marker for the question (entry-local only; no bit-header cascade).",
|
|
3497
|
+
format: TagFormat.bitmarkText,
|
|
3498
|
+
nullable: true
|
|
2748
3499
|
}
|
|
2749
3500
|
]
|
|
2750
3501
|
}
|
|
@@ -2764,15 +3515,23 @@ var CARDSETS = {
|
|
|
2764
3515
|
variants: [
|
|
2765
3516
|
{
|
|
2766
3517
|
jsonKey: "elements[]",
|
|
3518
|
+
exportJsonKey: { elements: ["$"] },
|
|
2767
3519
|
tags: [
|
|
2768
3520
|
{
|
|
2769
3521
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2770
3522
|
description: "Standard tags for lead, instruction, and hint."
|
|
2771
3523
|
},
|
|
2772
3524
|
{
|
|
3525
|
+
// ALIGN-EXAMPLE-CASCADE §3.11: `elements` is NOT in BPG's
|
|
3526
|
+
// `pushExampleDownTree` dispatch — no bit-header cascade.
|
|
2773
3527
|
key: ConfigKey.property_example,
|
|
2774
|
-
|
|
2775
|
-
|
|
3528
|
+
exportJsonKey: [
|
|
3529
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
3530
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3531
|
+
],
|
|
3532
|
+
description: "Example text for the element (entry-local only; no bit-header cascade).",
|
|
3533
|
+
format: TagFormat.plainText,
|
|
3534
|
+
nullable: true
|
|
2776
3535
|
}
|
|
2777
3536
|
],
|
|
2778
3537
|
repeatCount: Count.infinity
|
|
@@ -2784,8 +3543,57 @@ var CARDSETS = {
|
|
|
2784
3543
|
//
|
|
2785
3544
|
// table
|
|
2786
3545
|
//
|
|
3546
|
+
// PLAN-079: supports BOTH source formats and collapses to the same basic
|
|
3547
|
+
// output (`{ columns?, data, columnWidths? }`):
|
|
3548
|
+
//
|
|
3549
|
+
// 1. Basic format — first card carries `[#X]` markers (fire `tag_title`
|
|
3550
|
+
// → `^table.columns[]`); subsequent cards are body rows. Cards have
|
|
3551
|
+
// no qualifier, so they route to the `table-body` (default) section.
|
|
3552
|
+
//
|
|
3553
|
+
// 2. Extended format — `==== table-header ====` / `==== table-footer ====`
|
|
3554
|
+
// qualifiers. The `table-header` section uses `@cardIndex=0` to route
|
|
3555
|
+
// the first header card's cells to `columns` and demote remaining
|
|
3556
|
+
// header cards (rows) into `data`. Per-cell `[@tableRowSpan]` /
|
|
3557
|
+
// `[@tableScope]` / `[@tableCellType]` tags are valid-but-unmapped
|
|
3558
|
+
// here (no per-cell metadata in basic shape) — declared on the cell
|
|
3559
|
+
// variant below.
|
|
3560
|
+
//
|
|
2787
3561
|
[CardSetConfigKey.table]: {
|
|
2788
|
-
jsonKey:
|
|
3562
|
+
jsonKey: null,
|
|
3563
|
+
exportJsonKey: null,
|
|
3564
|
+
sections: {
|
|
3565
|
+
"table-header": {
|
|
3566
|
+
// First header card's row of cells → `columns`. Subsequent header
|
|
3567
|
+
// cards' rows → `data` (per-card append; `[$]` shape because
|
|
3568
|
+
// per-card emission fires once per card, multiple fires deep_merge-
|
|
3569
|
+
// append). PLAN-079 + PLAN-080: predicates inside exportJsonKey
|
|
3570
|
+
// both ROUTE cards to this section (when no explicit `==== table-
|
|
3571
|
+
// header ====` qualifier) and SELECT the rule body once routed.
|
|
3572
|
+
// First rule = first card with any `[#]` → `columns`; second rule
|
|
3573
|
+
// = subsequent cards in this section → `data` (per-row append).
|
|
3574
|
+
jsonKey: "table.columns",
|
|
3575
|
+
exportJsonKey: [
|
|
3576
|
+
{
|
|
3577
|
+
predicates: [{ "@cardIndex": 0 }, { "@variantHasTag": "#" }],
|
|
3578
|
+
rule: { "@bit": { table: { columns: "$" } } }
|
|
3579
|
+
},
|
|
3580
|
+
{ "@cardIndex=0": { "@bit": { table: { columns: "$" } } } },
|
|
3581
|
+
{ "@bit": { table: { data: ["$"] } } }
|
|
3582
|
+
]
|
|
3583
|
+
},
|
|
3584
|
+
"table-body": {
|
|
3585
|
+
// Batched emission: `$` is the entire 2D array of body card rows.
|
|
3586
|
+
// This is the default section (no qualifier → cards land here).
|
|
3587
|
+
jsonKey: "table.data",
|
|
3588
|
+
exportJsonKey: { "@bit": { table: { data: "$" } } },
|
|
3589
|
+
isDefault: true
|
|
3590
|
+
},
|
|
3591
|
+
"table-footer": {
|
|
3592
|
+
// Batched emission: `$` is the entire 2D array of footer rows.
|
|
3593
|
+
jsonKey: "table.data",
|
|
3594
|
+
exportJsonKey: { "@bit": { table: { data: "$" } } }
|
|
3595
|
+
}
|
|
3596
|
+
},
|
|
2789
3597
|
sides: [
|
|
2790
3598
|
{
|
|
2791
3599
|
name: "cell",
|
|
@@ -2801,6 +3609,7 @@ var CARDSETS = {
|
|
|
2801
3609
|
{
|
|
2802
3610
|
key: ConfigKey.tag_title,
|
|
2803
3611
|
jsonKey: "^table.columns[]",
|
|
3612
|
+
exportJsonKey: { "@bit": { table: { columns: ["$"] } } },
|
|
2804
3613
|
description: "Title of the table."
|
|
2805
3614
|
},
|
|
2806
3615
|
{
|
|
@@ -2825,6 +3634,8 @@ var CARDSETS = {
|
|
|
2825
3634
|
},
|
|
2826
3635
|
{
|
|
2827
3636
|
key: ConfigKey.property_tableColWidth,
|
|
3637
|
+
jsonKey: "^table.columnWidths[{s}]",
|
|
3638
|
+
exportJsonKey: { "@bit": { table: { columnWidths: { $s: "$" } } } },
|
|
2828
3639
|
description: "Width for the column.",
|
|
2829
3640
|
format: TagFormat.number
|
|
2830
3641
|
}
|
|
@@ -2841,18 +3652,49 @@ var CARDSETS = {
|
|
|
2841
3652
|
[CardSetConfigKey.tableExtended]: {
|
|
2842
3653
|
jsonKey: null,
|
|
2843
3654
|
sections: {
|
|
2844
|
-
"table-header": {
|
|
2845
|
-
|
|
2846
|
-
|
|
3655
|
+
"table-header": {
|
|
3656
|
+
jsonKey: "table.header.rows",
|
|
3657
|
+
// PLAN-080: section dispatch via predicates inside exportJsonKey.
|
|
3658
|
+
// Cards with no explicit `==== table-header ====` qualifier
|
|
3659
|
+
// route here if FIRST CARD contains any `[#]` tag in any
|
|
3660
|
+
// variant. Explicit-qualifier cards fall through to the
|
|
3661
|
+
// unconditional fallback rule. Both rules use the per-card
|
|
3662
|
+
// append shape `rows: ['$']` — the runtime triggers per-card
|
|
3663
|
+
// emission whenever the pattern carries predicates, and each
|
|
3664
|
+
// fire appends a single-element array (multi-fire deep-merge
|
|
3665
|
+
// concatenates).
|
|
3666
|
+
exportJsonKey: [
|
|
3667
|
+
{
|
|
3668
|
+
predicates: [{ "@cardIndex": 0 }, { "@variantHasTag": "#" }],
|
|
3669
|
+
rule: { table: { header: { rows: ["$"] } } }
|
|
3670
|
+
},
|
|
3671
|
+
{ table: { header: { rows: ["$"] } } }
|
|
3672
|
+
],
|
|
3673
|
+
sideJsonKey: "cells[{s}]|set(title=true)",
|
|
3674
|
+
sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } }
|
|
3675
|
+
},
|
|
3676
|
+
"table-body": {
|
|
3677
|
+
jsonKey: "table.body.rows",
|
|
3678
|
+
exportJsonKey: { table: { body: { rows: "$" } } },
|
|
3679
|
+
isDefault: true
|
|
3680
|
+
},
|
|
3681
|
+
"table-footer": {
|
|
3682
|
+
jsonKey: "table.footer.rows",
|
|
3683
|
+
exportJsonKey: { table: { footer: { rows: "$" } } },
|
|
3684
|
+
sideJsonKey: "cells[{s}]|set(title=true)",
|
|
3685
|
+
sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } }
|
|
3686
|
+
}
|
|
2847
3687
|
},
|
|
2848
3688
|
sides: [
|
|
2849
3689
|
{
|
|
2850
3690
|
name: "cell",
|
|
2851
3691
|
repeat: true,
|
|
2852
3692
|
jsonKey: "cells[{s}]",
|
|
3693
|
+
exportJsonKey: { cells: { $s: "$" } },
|
|
2853
3694
|
variants: [
|
|
2854
3695
|
{
|
|
2855
3696
|
jsonKey: "content",
|
|
3697
|
+
exportJsonKey: { content: "$" },
|
|
2856
3698
|
tags: [
|
|
2857
3699
|
{
|
|
2858
3700
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
@@ -2860,35 +3702,47 @@ var CARDSETS = {
|
|
|
2860
3702
|
},
|
|
2861
3703
|
{
|
|
2862
3704
|
key: ConfigKey.tag_title,
|
|
2863
|
-
|
|
2864
|
-
|
|
3705
|
+
// PLAN-080: the `[#]` tag writes its text to the cell's
|
|
3706
|
+
// `content` field. When the card is in the `table-header`
|
|
3707
|
+
// section, the section's sideExportJsonKey wraps each
|
|
3708
|
+
// cell with `title: true` automatically.
|
|
3709
|
+
jsonKey: "content",
|
|
3710
|
+
exportJsonKey: { content: "$" },
|
|
3711
|
+
description: "Title text of the table cell (header rows)."
|
|
2865
3712
|
},
|
|
2866
3713
|
{
|
|
2867
3714
|
key: ConfigKey.property_tableCellType,
|
|
2868
3715
|
jsonKey: "title|bool(th)",
|
|
3716
|
+
exportJsonKey: [{ "@value=th": { title: true } }],
|
|
2869
3717
|
description: "Table cell type (th/td).",
|
|
2870
3718
|
format: TagFormat.plainText
|
|
2871
3719
|
},
|
|
2872
3720
|
{
|
|
2873
3721
|
key: ConfigKey.property_tableRowSpan,
|
|
2874
3722
|
jsonKey: "rowspan",
|
|
3723
|
+
exportJsonKey: { rowspan: "$" },
|
|
2875
3724
|
description: "Number of rows the cell spans.",
|
|
2876
3725
|
format: TagFormat.number
|
|
2877
3726
|
},
|
|
2878
3727
|
{
|
|
2879
3728
|
key: ConfigKey.property_tableColSpan,
|
|
2880
3729
|
jsonKey: "colspan",
|
|
3730
|
+
exportJsonKey: { colspan: "$" },
|
|
2881
3731
|
description: "Number of columns the cell spans.",
|
|
2882
3732
|
format: TagFormat.number
|
|
2883
3733
|
},
|
|
2884
3734
|
{
|
|
2885
3735
|
key: ConfigKey.property_tableScope,
|
|
2886
3736
|
jsonKey: "scope",
|
|
3737
|
+
exportJsonKey: { scope: "$" },
|
|
2887
3738
|
description: "Scope attribute for header cells.",
|
|
2888
3739
|
format: TagFormat.plainText
|
|
2889
3740
|
},
|
|
2890
3741
|
{
|
|
2891
3742
|
key: ConfigKey.property_tableColWidth,
|
|
3743
|
+
// PLAN-080: write to the cell's `colwidth` field.
|
|
3744
|
+
jsonKey: "colwidth",
|
|
3745
|
+
exportJsonKey: { colwidth: "$" },
|
|
2892
3746
|
description: "Width for the column.",
|
|
2893
3747
|
format: TagFormat.number
|
|
2894
3748
|
}
|
|
@@ -2904,6 +3758,7 @@ var CARDSETS = {
|
|
|
2904
3758
|
//
|
|
2905
3759
|
[CardSetConfigKey.pronunciationTable]: {
|
|
2906
3760
|
jsonKey: "pronunciationTable.data",
|
|
3761
|
+
exportJsonKey: { pronunciationTable: { data: "$" } },
|
|
2907
3762
|
sides: [
|
|
2908
3763
|
{
|
|
2909
3764
|
name: "cell",
|
|
@@ -2911,19 +3766,22 @@ var CARDSETS = {
|
|
|
2911
3766
|
variants: [
|
|
2912
3767
|
{
|
|
2913
3768
|
jsonKey: "body",
|
|
3769
|
+
exportJsonKey: { body: "$" },
|
|
2914
3770
|
tags: [
|
|
2915
3771
|
{
|
|
2916
3772
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2917
3773
|
description: "Standard tags for lead, instruction, and hint."
|
|
2918
3774
|
},
|
|
2919
3775
|
{
|
|
3776
|
+
exportJsonKey: { title: "$" },
|
|
2920
3777
|
key: ConfigKey.tag_title,
|
|
2921
3778
|
description: "Title of the pronunciation table."
|
|
2922
3779
|
},
|
|
2923
3780
|
{
|
|
2924
3781
|
key: ConfigKey.resource_audio,
|
|
2925
3782
|
description: "Audio resource for the pronunciation table.",
|
|
2926
|
-
jsonKey: "audio"
|
|
3783
|
+
jsonKey: "audio",
|
|
3784
|
+
exportJsonKey: { audio: { type: "audio", audio: { src: "$" } } }
|
|
2927
3785
|
}
|
|
2928
3786
|
],
|
|
2929
3787
|
repeatCount: Count.infinity
|
|
@@ -2937,12 +3795,15 @@ var CARDSETS = {
|
|
|
2937
3795
|
//
|
|
2938
3796
|
[CardSetConfigKey.botActionResponses]: {
|
|
2939
3797
|
jsonKey: "responses",
|
|
3798
|
+
exportJsonKey: { responses: "$" },
|
|
2940
3799
|
sides: [
|
|
2941
3800
|
{
|
|
2942
3801
|
name: "response",
|
|
2943
3802
|
variants: [
|
|
2944
3803
|
{
|
|
2945
3804
|
jsonKey: "feedback",
|
|
3805
|
+
exportJsonKey: { feedback: "$" },
|
|
3806
|
+
format: TextFormat2.plainText,
|
|
2946
3807
|
tags: [
|
|
2947
3808
|
{
|
|
2948
3809
|
key: ConfigKey.property_reaction,
|
|
@@ -2950,18 +3811,58 @@ var CARDSETS = {
|
|
|
2950
3811
|
format: TagFormat.plainText
|
|
2951
3812
|
},
|
|
2952
3813
|
{
|
|
2953
|
-
key: ConfigKey.
|
|
2954
|
-
|
|
3814
|
+
key: ConfigKey.tag_item,
|
|
3815
|
+
jsonKey: "item",
|
|
3816
|
+
exportJsonKey: { item: "$" },
|
|
3817
|
+
format: TagFormat.plainText,
|
|
3818
|
+
description: "The item for the bit",
|
|
3819
|
+
chain: [
|
|
3820
|
+
{
|
|
3821
|
+
key: ConfigKey.tag_item,
|
|
3822
|
+
jsonKey: "lead",
|
|
3823
|
+
exportJsonKey: { lead: "$" },
|
|
3824
|
+
description: "The lead for the bit",
|
|
3825
|
+
maxCount: 1,
|
|
3826
|
+
chain: [
|
|
3827
|
+
{
|
|
3828
|
+
key: ConfigKey.tag_item,
|
|
3829
|
+
jsonKey: "pageNumber",
|
|
3830
|
+
exportJsonKey: { pageNumber: "$" },
|
|
3831
|
+
description: "The page number for the bit",
|
|
3832
|
+
maxCount: 1,
|
|
3833
|
+
chain: [
|
|
3834
|
+
{
|
|
3835
|
+
key: ConfigKey.tag_item,
|
|
3836
|
+
jsonKey: "marginNumber",
|
|
3837
|
+
exportJsonKey: { marginNumber: "$" },
|
|
3838
|
+
description: "The margin number for the bit",
|
|
3839
|
+
maxCount: 1
|
|
3840
|
+
}
|
|
3841
|
+
]
|
|
3842
|
+
}
|
|
3843
|
+
]
|
|
3844
|
+
}
|
|
3845
|
+
]
|
|
2955
3846
|
},
|
|
2956
3847
|
{
|
|
2957
3848
|
key: ConfigKey.tag_instruction,
|
|
2958
3849
|
description: "The response label for the bot action.",
|
|
2959
|
-
jsonKey: "response"
|
|
3850
|
+
jsonKey: "response",
|
|
3851
|
+
exportJsonKey: { response: "$" },
|
|
3852
|
+
format: TagFormat.plainText
|
|
2960
3853
|
},
|
|
2961
3854
|
{
|
|
3855
|
+
// ALIGN-EXAMPLE-CASCADE §3.12: `bot-action-responses` is
|
|
3856
|
+
// NOT in BPG's `pushExampleDownTree` dispatch — no bit-
|
|
3857
|
+
// header cascade.
|
|
2962
3858
|
key: ConfigKey.property_example,
|
|
2963
|
-
|
|
2964
|
-
|
|
3859
|
+
exportJsonKey: [
|
|
3860
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
3861
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3862
|
+
],
|
|
3863
|
+
description: "Example text for the bot action response (entry-local only; no bit-header cascade).",
|
|
3864
|
+
format: TagFormat.plainText,
|
|
3865
|
+
nullable: true
|
|
2965
3866
|
}
|
|
2966
3867
|
]
|
|
2967
3868
|
}
|
|
@@ -2974,12 +3875,14 @@ var CARDSETS = {
|
|
|
2974
3875
|
//
|
|
2975
3876
|
[CardSetConfigKey.clozeList]: {
|
|
2976
3877
|
jsonKey: "listItems",
|
|
3878
|
+
exportJsonKey: { listItems: "$" },
|
|
2977
3879
|
sides: [
|
|
2978
3880
|
{
|
|
2979
3881
|
name: "content",
|
|
2980
3882
|
variants: [
|
|
2981
3883
|
{
|
|
2982
3884
|
jsonKey: "body",
|
|
3885
|
+
exportJsonKey: { body: "$" },
|
|
2983
3886
|
tags: [
|
|
2984
3887
|
{
|
|
2985
3888
|
key: ConfigKey.group_standardTags,
|
|
@@ -3000,18 +3903,21 @@ var CARDSETS = {
|
|
|
3000
3903
|
//
|
|
3001
3904
|
[CardSetConfigKey.exampleBitList]: {
|
|
3002
3905
|
jsonKey: "listItems",
|
|
3906
|
+
exportJsonKey: { listItems: "$" },
|
|
3003
3907
|
sides: [
|
|
3004
3908
|
{
|
|
3005
3909
|
name: "item",
|
|
3006
3910
|
variants: [
|
|
3007
3911
|
{
|
|
3008
3912
|
jsonKey: "body",
|
|
3913
|
+
exportJsonKey: { body: "$" },
|
|
3009
3914
|
tags: [
|
|
3010
3915
|
{
|
|
3011
3916
|
key: ConfigKey.group_standardTags,
|
|
3012
3917
|
description: "Standard tags for example bits."
|
|
3013
3918
|
},
|
|
3014
3919
|
{
|
|
3920
|
+
exportJsonKey: { title: "$" },
|
|
3015
3921
|
key: ConfigKey.tag_title,
|
|
3016
3922
|
description: "Title of the example bit."
|
|
3017
3923
|
}
|
|
@@ -3022,18 +3928,53 @@ var CARDSETS = {
|
|
|
3022
3928
|
]
|
|
3023
3929
|
},
|
|
3024
3930
|
//
|
|
3931
|
+
// page-footer-sections — mirrors example-bit-list but emits cards under
|
|
3932
|
+
// `sections` instead of `listItems`. BPG's JsonGenerator special-cases
|
|
3933
|
+
// BitType.pageFooter in code; this dedicated cardSet expresses the same
|
|
3934
|
+
// routing as pure config so the Rust serializer can pick it up.
|
|
3935
|
+
//
|
|
3936
|
+
[CardSetConfigKey.pageFooterSections]: {
|
|
3937
|
+
jsonKey: "sections",
|
|
3938
|
+
exportJsonKey: { sections: "$" },
|
|
3939
|
+
sides: [
|
|
3940
|
+
{
|
|
3941
|
+
name: "item",
|
|
3942
|
+
variants: [
|
|
3943
|
+
{
|
|
3944
|
+
jsonKey: "body",
|
|
3945
|
+
exportJsonKey: { body: "$" },
|
|
3946
|
+
tags: [
|
|
3947
|
+
{
|
|
3948
|
+
key: ConfigKey.group_standardTags,
|
|
3949
|
+
description: "Standard tags for page-footer section bits."
|
|
3950
|
+
},
|
|
3951
|
+
{
|
|
3952
|
+
exportJsonKey: { title: "$" },
|
|
3953
|
+
key: ConfigKey.tag_title,
|
|
3954
|
+
description: "Title of the page-footer section."
|
|
3955
|
+
}
|
|
3956
|
+
]
|
|
3957
|
+
}
|
|
3958
|
+
]
|
|
3959
|
+
}
|
|
3960
|
+
]
|
|
3961
|
+
},
|
|
3962
|
+
//
|
|
3025
3963
|
// ingredients
|
|
3026
3964
|
//
|
|
3027
3965
|
[CardSetConfigKey.ingredients]: {
|
|
3028
3966
|
jsonKey: "ingredients",
|
|
3967
|
+
exportJsonKey: { ingredients: "$" },
|
|
3029
3968
|
sides: [
|
|
3030
3969
|
{
|
|
3031
3970
|
name: "ingredient",
|
|
3032
3971
|
variants: [
|
|
3033
3972
|
{
|
|
3034
3973
|
jsonKey: "ingredient",
|
|
3974
|
+
exportJsonKey: { ingredient: "$" },
|
|
3035
3975
|
tags: [
|
|
3036
3976
|
{
|
|
3977
|
+
exportJsonKey: { title: "$" },
|
|
3037
3978
|
key: ConfigKey.tag_title,
|
|
3038
3979
|
description: "Title of the ingredient."
|
|
3039
3980
|
},
|
|
@@ -3041,6 +3982,7 @@ var CARDSETS = {
|
|
|
3041
3982
|
key: ConfigKey.tag_true,
|
|
3042
3983
|
description: "Checked state for the ingredient.",
|
|
3043
3984
|
jsonKey: "|set(checked=true)",
|
|
3985
|
+
exportJsonKey: { checked: true, $: "$" },
|
|
3044
3986
|
maxCount: 1
|
|
3045
3987
|
// nullable: true,
|
|
3046
3988
|
},
|
|
@@ -3048,6 +3990,7 @@ var CARDSETS = {
|
|
|
3048
3990
|
key: ConfigKey.tag_false,
|
|
3049
3991
|
description: "Unchecked state for the ingredient.",
|
|
3050
3992
|
jsonKey: "|set(checked=false)",
|
|
3993
|
+
exportJsonKey: { checked: false, $: "$" },
|
|
3051
3994
|
maxCount: 1
|
|
3052
3995
|
// nullable: true,
|
|
3053
3996
|
},
|
|
@@ -3059,9 +4002,11 @@ var CARDSETS = {
|
|
|
3059
4002
|
key: ConfigKey.tag_instruction,
|
|
3060
4003
|
description: "The quantity of the ingredient.",
|
|
3061
4004
|
jsonKey: "quantity",
|
|
4005
|
+
exportJsonKey: { quantity: "$" },
|
|
3062
4006
|
format: TagFormat.number
|
|
3063
4007
|
},
|
|
3064
4008
|
{
|
|
4009
|
+
exportJsonKey: { hint: "$" },
|
|
3065
4010
|
key: ConfigKey.tag_hint,
|
|
3066
4011
|
description: "The hint for the ingredient."
|
|
3067
4012
|
},
|
|
@@ -3097,6 +4042,7 @@ var CARDSETS = {
|
|
|
3097
4042
|
//
|
|
3098
4043
|
[CardSetConfigKey.bookReferenceList]: {
|
|
3099
4044
|
jsonKey: "bookReferences",
|
|
4045
|
+
exportJsonKey: { bookReferences: "$" },
|
|
3100
4046
|
sides: [
|
|
3101
4047
|
{
|
|
3102
4048
|
name: "reference",
|
|
@@ -3156,6 +4102,11 @@ var GROUPS = {
|
|
|
3156
4102
|
format: TagFormat.plainText,
|
|
3157
4103
|
maxCount: Count.infinity
|
|
3158
4104
|
},
|
|
4105
|
+
{
|
|
4106
|
+
key: ConfigKey.property_gUri,
|
|
4107
|
+
description: "Global URI for the bit",
|
|
4108
|
+
format: TagFormat.plainText
|
|
4109
|
+
},
|
|
3159
4110
|
{
|
|
3160
4111
|
key: ConfigKey.property_customerId,
|
|
3161
4112
|
description: "The customer-specific identifier for the bit",
|
|
@@ -3339,12 +4290,18 @@ var GROUPS = {
|
|
|
3339
4290
|
{
|
|
3340
4291
|
key: ConfigKey.property_groupTag,
|
|
3341
4292
|
jsonKey: "groupTag.name",
|
|
4293
|
+
// PLAN-063: starter-array shape with `@id` declares entity-merge
|
|
4294
|
+
// semantics — repeated `[@groupTag: name]` occurrences with the
|
|
4295
|
+
// same value fold into one entry; chained `@tag` children's
|
|
4296
|
+
// arrays merge as sets.
|
|
4297
|
+
exportJsonKey: { groupTag: [{ "@id": "name", name: "$" }] },
|
|
3342
4298
|
description: "The group tag(s) for the bit",
|
|
3343
4299
|
format: TagFormat.plainText,
|
|
3344
4300
|
maxCount: Count.infinity,
|
|
3345
4301
|
chain: [
|
|
3346
4302
|
{
|
|
3347
4303
|
key: ConfigKey.property_tag,
|
|
4304
|
+
exportJsonKey: { tags: ["$"] },
|
|
3348
4305
|
description: "The tag(s) for the group",
|
|
3349
4306
|
format: TagFormat.plainText,
|
|
3350
4307
|
maxCount: Count.infinity
|
|
@@ -3375,6 +4332,12 @@ var GROUPS = {
|
|
|
3375
4332
|
format: TagFormat.plainText,
|
|
3376
4333
|
maxCount: Count.infinity
|
|
3377
4334
|
},
|
|
4335
|
+
{
|
|
4336
|
+
key: ConfigKey.property_sourceBB,
|
|
4337
|
+
description: "The source bounding box(es) for the bit (x, y, x1, y1)",
|
|
4338
|
+
format: TagFormat.coordinates,
|
|
4339
|
+
maxCount: Count.infinity
|
|
4340
|
+
},
|
|
3378
4341
|
{
|
|
3379
4342
|
key: ConfigKey.property_levelCEFRp,
|
|
3380
4343
|
description: "The CEFRp level for the bit",
|
|
@@ -3412,6 +4375,7 @@ var GROUPS = {
|
|
|
3412
4375
|
maxCount: Count.infinity
|
|
3413
4376
|
},
|
|
3414
4377
|
{
|
|
4378
|
+
exportJsonKey: { anchor: "$" },
|
|
3415
4379
|
key: ConfigKey.tag_anchor,
|
|
3416
4380
|
name: "Anchor",
|
|
3417
4381
|
format: TagFormat.plainText,
|
|
@@ -3449,23 +4413,27 @@ var GROUPS = {
|
|
|
3449
4413
|
{
|
|
3450
4414
|
key: ConfigKey.tag_item,
|
|
3451
4415
|
jsonKey: "item",
|
|
4416
|
+
exportJsonKey: { item: "$" },
|
|
3452
4417
|
description: "The item for the bit",
|
|
3453
4418
|
chain: [
|
|
3454
4419
|
{
|
|
3455
4420
|
key: ConfigKey.tag_item,
|
|
3456
4421
|
jsonKey: "lead",
|
|
4422
|
+
exportJsonKey: { lead: "$" },
|
|
3457
4423
|
description: "The lead for the bit",
|
|
3458
4424
|
maxCount: 1,
|
|
3459
4425
|
chain: [
|
|
3460
4426
|
{
|
|
3461
4427
|
key: ConfigKey.tag_item,
|
|
3462
4428
|
jsonKey: "pageNumber",
|
|
4429
|
+
exportJsonKey: { pageNumber: "$" },
|
|
3463
4430
|
description: "The page number for the bit",
|
|
3464
4431
|
maxCount: 1,
|
|
3465
4432
|
chain: [
|
|
3466
4433
|
{
|
|
3467
4434
|
key: ConfigKey.tag_item,
|
|
3468
4435
|
jsonKey: "marginNumber",
|
|
4436
|
+
exportJsonKey: { marginNumber: "$" },
|
|
3469
4437
|
description: "The margin number for the bit",
|
|
3470
4438
|
maxCount: 1
|
|
3471
4439
|
}
|
|
@@ -3486,11 +4454,31 @@ var GROUPS = {
|
|
|
3486
4454
|
description: "Item, lead, page number, and margin number tags"
|
|
3487
4455
|
},
|
|
3488
4456
|
{
|
|
4457
|
+
exportJsonKey: { instruction: "$" },
|
|
4458
|
+
key: ConfigKey.tag_instruction,
|
|
4459
|
+
name: "Instruction",
|
|
4460
|
+
description: "The instruction for the bit"
|
|
4461
|
+
},
|
|
4462
|
+
{
|
|
4463
|
+
exportJsonKey: { hint: "$" },
|
|
4464
|
+
key: ConfigKey.tag_hint,
|
|
4465
|
+
name: "Hint",
|
|
4466
|
+
description: "The hint for the bit"
|
|
4467
|
+
}
|
|
4468
|
+
]
|
|
4469
|
+
},
|
|
4470
|
+
[ConfigKey.group_standardInstructionHint]: {
|
|
4471
|
+
type: GroupConfigType.standard,
|
|
4472
|
+
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).",
|
|
4473
|
+
tags: [
|
|
4474
|
+
{
|
|
4475
|
+
exportJsonKey: { instruction: "$" },
|
|
3489
4476
|
key: ConfigKey.tag_instruction,
|
|
3490
4477
|
name: "Instruction",
|
|
3491
4478
|
description: "The instruction for the bit"
|
|
3492
4479
|
},
|
|
3493
4480
|
{
|
|
4481
|
+
exportJsonKey: { hint: "$" },
|
|
3494
4482
|
key: ConfigKey.tag_hint,
|
|
3495
4483
|
name: "Hint",
|
|
3496
4484
|
description: "The hint for the bit"
|
|
@@ -3510,9 +4498,45 @@ var GROUPS = {
|
|
|
3510
4498
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3511
4499
|
},
|
|
3512
4500
|
{
|
|
4501
|
+
// Bit-level example tag (default — non-`isTopLevelExample` bits):
|
|
4502
|
+
// - bare `[@example]`: consume only (records cascade marker, emits
|
|
4503
|
+
// nothing at bit-level — OLD parser scrubs bit-level isExample
|
|
4504
|
+
// for bits NOT in its `isTopLevelExample` allow-list).
|
|
4505
|
+
// - synthesized (descendant cascade): still emits `isExample: true`
|
|
4506
|
+
// at the descendant scope.
|
|
4507
|
+
// - valued `[@example:text]`: emit the example value only; bit-level
|
|
4508
|
+
// `isExample` is left to bubble from descendants.
|
|
4509
|
+
// Bits in the OLD parser's allow-list (flashcard, definitionList,
|
|
4510
|
+
// sequence, multipleChoice, trueFalse, cloze*, mark, interview,
|
|
4511
|
+
// matchMatrix, match, essay, etc.) override this entry with the
|
|
4512
|
+
// legacy emit-isExample shape.
|
|
3513
4513
|
key: ConfigKey.property_example,
|
|
4514
|
+
exportJsonKey: [{ "@keyonly": {} }, { "@absent": { isExample: true } }, { example: "$" }],
|
|
3514
4515
|
description: "The example(s) for the bit",
|
|
3515
|
-
format: TagFormat.
|
|
4516
|
+
format: TagFormat.bitmarkText,
|
|
4517
|
+
nullable: true
|
|
4518
|
+
}
|
|
4519
|
+
]
|
|
4520
|
+
},
|
|
4521
|
+
[ConfigKey.group_standardTagsNoItemLead]: {
|
|
4522
|
+
type: GroupConfigType.standard,
|
|
4523
|
+
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).",
|
|
4524
|
+
tags: [
|
|
4525
|
+
{
|
|
4526
|
+
key: ConfigKey.group_standardAllBits,
|
|
4527
|
+
description: "All standard tags which apply to all bits"
|
|
4528
|
+
},
|
|
4529
|
+
{
|
|
4530
|
+
key: ConfigKey.group_standardInstructionHint,
|
|
4531
|
+
description: "Instruction and hint tags only (no item/lead chain)."
|
|
4532
|
+
},
|
|
4533
|
+
{
|
|
4534
|
+
// Mirror of group_standardTags property_example entry.
|
|
4535
|
+
key: ConfigKey.property_example,
|
|
4536
|
+
exportJsonKey: [{ "@keyonly": {} }, { "@absent": { isExample: true } }, { example: "$" }],
|
|
4537
|
+
description: "The example(s) for the bit",
|
|
4538
|
+
format: TagFormat.bitmarkText,
|
|
4539
|
+
nullable: true
|
|
3516
4540
|
}
|
|
3517
4541
|
]
|
|
3518
4542
|
},
|
|
@@ -3523,6 +4547,7 @@ var GROUPS = {
|
|
|
3523
4547
|
{
|
|
3524
4548
|
key: ConfigKey.property_imageSource,
|
|
3525
4549
|
jsonKey: "imageSource.url",
|
|
4550
|
+
exportJsonKey: { imageSource: { url: "$" } },
|
|
3526
4551
|
description: "The source of an image",
|
|
3527
4552
|
format: TagFormat.plainText,
|
|
3528
4553
|
chain: [
|
|
@@ -3557,6 +4582,7 @@ var GROUPS = {
|
|
|
3557
4582
|
{
|
|
3558
4583
|
key: ConfigKey.property_technicalTerm,
|
|
3559
4584
|
jsonKey: "technicalTerm.technicalTerm",
|
|
4585
|
+
exportJsonKey: { technicalTerm: { technicalTerm: "$" } },
|
|
3560
4586
|
description: "The technical term",
|
|
3561
4587
|
format: TagFormat.plainText,
|
|
3562
4588
|
chain: [
|
|
@@ -3575,7 +4601,8 @@ var GROUPS = {
|
|
|
3575
4601
|
tags: [
|
|
3576
4602
|
{
|
|
3577
4603
|
key: ConfigKey.property_person,
|
|
3578
|
-
jsonKey: "
|
|
4604
|
+
jsonKey: "person.name",
|
|
4605
|
+
exportJsonKey: { person: { name: "$" } },
|
|
3579
4606
|
description: "A person",
|
|
3580
4607
|
format: TagFormat.plainText,
|
|
3581
4608
|
chain: [
|
|
@@ -3587,6 +4614,7 @@ var GROUPS = {
|
|
|
3587
4614
|
{
|
|
3588
4615
|
key: ConfigKey.group_resourceImage,
|
|
3589
4616
|
jsonKey: "avatarImage|resource(type=image, key=image)",
|
|
4617
|
+
exportJsonKey: { avatarImage: { type: "image", image: { src: "$" } } },
|
|
3590
4618
|
description: "The image of the person"
|
|
3591
4619
|
}
|
|
3592
4620
|
]
|
|
@@ -3594,7 +4622,8 @@ var GROUPS = {
|
|
|
3594
4622
|
{
|
|
3595
4623
|
// Deprecated (parter renamed to person)
|
|
3596
4624
|
key: ConfigKey.property_partner,
|
|
3597
|
-
jsonKey: "
|
|
4625
|
+
jsonKey: "person.name",
|
|
4626
|
+
exportJsonKey: { person: { name: "$" } },
|
|
3598
4627
|
description: "A partner",
|
|
3599
4628
|
format: TagFormat.plainText,
|
|
3600
4629
|
chain: [
|
|
@@ -3606,6 +4635,7 @@ var GROUPS = {
|
|
|
3606
4635
|
{
|
|
3607
4636
|
key: ConfigKey.group_resourceImage,
|
|
3608
4637
|
jsonKey: "avatarImage|resource(type=image, key=image)",
|
|
4638
|
+
exportJsonKey: { avatarImage: { type: "image", image: { src: "$" } } },
|
|
3609
4639
|
description: "The image of the partner"
|
|
3610
4640
|
}
|
|
3611
4641
|
]
|
|
@@ -3617,29 +4647,66 @@ var GROUPS = {
|
|
|
3617
4647
|
description: "Gap chain",
|
|
3618
4648
|
tags: [
|
|
3619
4649
|
{
|
|
4650
|
+
exportJsonKey: {
|
|
4651
|
+
"@body-inline": { type: "gap", attrs: { solutions: ["$"] } }
|
|
4652
|
+
},
|
|
3620
4653
|
key: ConfigKey.tag_gap,
|
|
3621
4654
|
description: "The value of a gap in the content",
|
|
3622
4655
|
maxCount: Count.infinity,
|
|
4656
|
+
format: TagFormat.plainText,
|
|
3623
4657
|
chain: [
|
|
3624
4658
|
{
|
|
3625
4659
|
key: ConfigKey.tag_gap,
|
|
3626
4660
|
jsonKey: "solutions[]",
|
|
4661
|
+
exportJsonKey: { solutions: ["$"] },
|
|
3627
4662
|
description: "Alternative values for the gaps in the content",
|
|
3628
|
-
maxCount: Count.infinity
|
|
4663
|
+
maxCount: Count.infinity,
|
|
4664
|
+
format: TagFormat.plainText
|
|
3629
4665
|
},
|
|
3630
4666
|
{
|
|
3631
4667
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3632
4668
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3633
4669
|
},
|
|
3634
4670
|
{
|
|
4671
|
+
// BPG ExampleTagContentProcessor.ts:91-95 reads
|
|
4672
|
+
// `__solutionsAst[length - 1]` — the solution closest to the
|
|
4673
|
+
// `[@example]` tag at parse time. Our chain accumulator is built
|
|
4674
|
+
// incrementally (scope.rs `parent.merge` after each tag), so at
|
|
4675
|
+
// the moment `[@example]` fires, `solutions` only contains the
|
|
4676
|
+
// preceding `[_x]` entries — `[-1]` resolves to the closest one.
|
|
4677
|
+
// E.g. `[_cloze][_gap][@example]` → solutions=["cloze","gap"],
|
|
4678
|
+
// `[-1]`="gap"; `[_solution][@example][_problem]` →
|
|
4679
|
+
// solutions=["solution"], `[-1]`="solution".
|
|
3635
4680
|
key: ConfigKey.property_example,
|
|
3636
4681
|
jsonKey: "example",
|
|
4682
|
+
exportJsonKey: [
|
|
4683
|
+
{
|
|
4684
|
+
"@keyonly": {
|
|
4685
|
+
isExample: true,
|
|
4686
|
+
example: "$parent.solutions[-1]",
|
|
4687
|
+
"@bit": { isExample: true }
|
|
4688
|
+
}
|
|
4689
|
+
},
|
|
4690
|
+
{
|
|
4691
|
+
"@absent": {
|
|
4692
|
+
isExample: true,
|
|
4693
|
+
example: "$parent.solutions[-1]",
|
|
4694
|
+
"@bit": { isExample: true }
|
|
4695
|
+
}
|
|
4696
|
+
},
|
|
4697
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
4698
|
+
],
|
|
3637
4699
|
description: "An example for the gap",
|
|
3638
|
-
format: TagFormat.
|
|
4700
|
+
format: TagFormat.bitmarkText,
|
|
4701
|
+
nullable: true
|
|
3639
4702
|
},
|
|
3640
4703
|
{
|
|
3641
4704
|
key: ConfigKey.property_isCaseSensitive,
|
|
3642
4705
|
jsonKey: "isCaseSensitive",
|
|
4706
|
+
exportJsonKey: [
|
|
4707
|
+
{ "@absent": { isCaseSensitive: "$ancestor" } },
|
|
4708
|
+
{ isCaseSensitive: "$" }
|
|
4709
|
+
],
|
|
3643
4710
|
description: "If true, the gap text is case sensitive",
|
|
3644
4711
|
format: TagFormat.boolean,
|
|
3645
4712
|
defaultValue: "true"
|
|
@@ -3653,60 +4720,587 @@ var GROUPS = {
|
|
|
3653
4720
|
description: "True/False chain",
|
|
3654
4721
|
tags: [
|
|
3655
4722
|
{
|
|
4723
|
+
exportJsonKey: { choices: [{ choice: "$", isCorrect: true }] },
|
|
3656
4724
|
key: ConfigKey.tag_true,
|
|
3657
4725
|
description: "True value for a true/false statement/question",
|
|
3658
4726
|
maxCount: Count.infinity,
|
|
4727
|
+
format: TagFormat.plainText,
|
|
3659
4728
|
chain: [
|
|
3660
4729
|
{
|
|
3661
4730
|
key: ConfigKey.tag_true,
|
|
3662
4731
|
jsonKey: "choices[]|set(isCorrect=true)",
|
|
4732
|
+
exportJsonKey: { choices: [{ choice: "$", isCorrect: true }] },
|
|
3663
4733
|
description: "True values for a true/false statement/question",
|
|
3664
|
-
maxCount: Count.infinity
|
|
4734
|
+
maxCount: Count.infinity,
|
|
4735
|
+
format: TagFormat.plainText
|
|
3665
4736
|
},
|
|
3666
4737
|
{
|
|
3667
4738
|
key: ConfigKey.tag_false,
|
|
3668
4739
|
jsonKey: "choices[]|set(isCorrect=false)",
|
|
4740
|
+
exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
|
|
3669
4741
|
description: "False values for a true/false statement/question",
|
|
3670
|
-
maxCount: Count.infinity
|
|
4742
|
+
maxCount: Count.infinity,
|
|
4743
|
+
format: TagFormat.plainText
|
|
3671
4744
|
},
|
|
3672
4745
|
{
|
|
3673
4746
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3674
4747
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3675
4748
|
},
|
|
3676
4749
|
{
|
|
4750
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.2: cascade-fired
|
|
4751
|
+
// `@example` from the bit header marks EVERY choice with
|
|
4752
|
+
// `isExample: true` (matches BPG output), but only the
|
|
4753
|
+
// FIRST correct choice gets `example: true` (BPG
|
|
4754
|
+
// `fillBooleanExample(..., firstCorrectOnly=true)`).
|
|
4755
|
+
//
|
|
4756
|
+
// Two `@absent` rules, picked first-match-wins:
|
|
4757
|
+
// 1. Verbose form gated on `@parent.isCorrect=true` with
|
|
4758
|
+
// `maxEmits:1` — fires once for the first correct.
|
|
4759
|
+
// 2. Plain `@absent` — fires on every remaining entry
|
|
4760
|
+
// (subsequent corrects and all incorrects), emitting
|
|
4761
|
+
// `isExample` only.
|
|
4762
|
+
// The `serialize_cards` cascade-counter scope holds the cap
|
|
4763
|
+
// across the whole cardset.
|
|
4764
|
+
// @card scope-shift writes choice-container isExample (e.g.
|
|
4765
|
+
// `quizzes[i].isExample`) — was previously provided by the
|
|
4766
|
+
// universal `bubble_is_example` post-walk, which was removed
|
|
4767
|
+
// in favour of explicit per-tag config. SYNTAX.md §8.
|
|
3677
4768
|
key: ConfigKey.property_example,
|
|
3678
4769
|
jsonKey: "example",
|
|
4770
|
+
exportJsonKey: [
|
|
4771
|
+
{
|
|
4772
|
+
"@keyonly": {
|
|
4773
|
+
isExample: true,
|
|
4774
|
+
example: "$parent.isCorrect",
|
|
4775
|
+
"@bit": { isExample: true },
|
|
4776
|
+
"@card": { isExample: true }
|
|
4777
|
+
}
|
|
4778
|
+
},
|
|
4779
|
+
{
|
|
4780
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
4781
|
+
maxEmits: 1,
|
|
4782
|
+
rule: {
|
|
4783
|
+
isExample: true,
|
|
4784
|
+
example: true,
|
|
4785
|
+
"@bit": { isExample: true },
|
|
4786
|
+
"@card": { isExample: true }
|
|
4787
|
+
}
|
|
4788
|
+
},
|
|
4789
|
+
{
|
|
4790
|
+
"@absent": {
|
|
4791
|
+
isExample: true,
|
|
4792
|
+
"@bit": { isExample: true },
|
|
4793
|
+
"@card": { isExample: true }
|
|
4794
|
+
}
|
|
4795
|
+
},
|
|
4796
|
+
{
|
|
4797
|
+
isExample: true,
|
|
4798
|
+
example: "$",
|
|
4799
|
+
"@bit": { isExample: true },
|
|
4800
|
+
"@card": { isExample: true }
|
|
4801
|
+
}
|
|
4802
|
+
],
|
|
3679
4803
|
description: "An example for the true/false statement/question",
|
|
3680
|
-
format: TagFormat.
|
|
4804
|
+
format: TagFormat.boolean,
|
|
4805
|
+
nullable: true
|
|
3681
4806
|
}
|
|
3682
4807
|
]
|
|
3683
4808
|
},
|
|
3684
4809
|
{
|
|
4810
|
+
exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
|
|
3685
4811
|
key: ConfigKey.tag_false,
|
|
3686
4812
|
description: "False value for a true/false statement/question",
|
|
3687
4813
|
maxCount: Count.infinity,
|
|
4814
|
+
format: TagFormat.plainText,
|
|
3688
4815
|
chain: [
|
|
3689
4816
|
{
|
|
3690
4817
|
key: ConfigKey.tag_true,
|
|
3691
4818
|
jsonKey: "choices[]|set(isCorrect=true)",
|
|
4819
|
+
exportJsonKey: { choices: [{ choice: "$", isCorrect: true }] },
|
|
3692
4820
|
description: "True values for a true/false statement/question",
|
|
3693
|
-
maxCount: Count.infinity
|
|
4821
|
+
maxCount: Count.infinity,
|
|
4822
|
+
format: TagFormat.plainText
|
|
3694
4823
|
},
|
|
3695
4824
|
{
|
|
3696
4825
|
key: ConfigKey.tag_false,
|
|
3697
4826
|
jsonKey: "choices[]|set(isCorrect=false)",
|
|
4827
|
+
exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
|
|
3698
4828
|
description: "False values for a true/false statement/question",
|
|
3699
|
-
maxCount: Count.infinity
|
|
4829
|
+
maxCount: Count.infinity,
|
|
4830
|
+
format: TagFormat.plainText
|
|
4831
|
+
},
|
|
4832
|
+
{
|
|
4833
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
4834
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
4835
|
+
},
|
|
4836
|
+
{
|
|
4837
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.2: cascade-fired
|
|
4838
|
+
// `@example` on a `-` (incorrect choice) emits
|
|
4839
|
+
// `isExample: true` only — no `example` (BPG fixtures show
|
|
4840
|
+
// `isExample` on every choice, but `example` only on the
|
|
4841
|
+
// first correct via firstCorrectOnly cascade).
|
|
4842
|
+
// @card scope-shift writes choice-container isExample.
|
|
4843
|
+
key: ConfigKey.property_example,
|
|
4844
|
+
jsonKey: "example",
|
|
4845
|
+
exportJsonKey: [
|
|
4846
|
+
{
|
|
4847
|
+
"@keyonly": {
|
|
4848
|
+
isExample: true,
|
|
4849
|
+
example: "$parent.isCorrect",
|
|
4850
|
+
"@bit": { isExample: true },
|
|
4851
|
+
"@card": { isExample: true }
|
|
4852
|
+
}
|
|
4853
|
+
},
|
|
4854
|
+
{
|
|
4855
|
+
"@absent": {
|
|
4856
|
+
isExample: true,
|
|
4857
|
+
"@bit": { isExample: true },
|
|
4858
|
+
"@card": { isExample: true }
|
|
4859
|
+
}
|
|
4860
|
+
},
|
|
4861
|
+
{
|
|
4862
|
+
isExample: true,
|
|
4863
|
+
example: "$",
|
|
4864
|
+
"@bit": { isExample: true },
|
|
4865
|
+
"@card": { isExample: true }
|
|
4866
|
+
}
|
|
4867
|
+
],
|
|
4868
|
+
description: "An example for the true/false statement/question (incorrect entry \u2014 isExample only on cascade)",
|
|
4869
|
+
format: TagFormat.boolean,
|
|
4870
|
+
nullable: true
|
|
4871
|
+
}
|
|
4872
|
+
]
|
|
4873
|
+
}
|
|
4874
|
+
]
|
|
4875
|
+
},
|
|
4876
|
+
[ConfigKey.group_trueFalseResponses]: {
|
|
4877
|
+
type: GroupConfigType.standard,
|
|
4878
|
+
description: "True/False Responses chain",
|
|
4879
|
+
tags: [
|
|
4880
|
+
{
|
|
4881
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: true }] },
|
|
4882
|
+
key: ConfigKey.tag_true,
|
|
4883
|
+
description: "True value for a true/false statement/question",
|
|
4884
|
+
maxCount: Count.infinity,
|
|
4885
|
+
format: TagFormat.plainText,
|
|
4886
|
+
chain: [
|
|
4887
|
+
{
|
|
4888
|
+
key: ConfigKey.tag_true,
|
|
4889
|
+
jsonKey: "responses[]|set(isCorrect=true)",
|
|
4890
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: true }] },
|
|
4891
|
+
description: "True values for a true/false statement/question",
|
|
4892
|
+
maxCount: Count.infinity,
|
|
4893
|
+
format: TagFormat.plainText
|
|
4894
|
+
},
|
|
4895
|
+
{
|
|
4896
|
+
key: ConfigKey.tag_false,
|
|
4897
|
+
jsonKey: "responses[]|set(isCorrect=false)",
|
|
4898
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: false }] },
|
|
4899
|
+
description: "False values for a true/false statement/question",
|
|
4900
|
+
maxCount: Count.infinity,
|
|
4901
|
+
format: TagFormat.plainText
|
|
4902
|
+
},
|
|
4903
|
+
{
|
|
4904
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
4905
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
4906
|
+
},
|
|
4907
|
+
{
|
|
4908
|
+
// @card scope-shift writes response-container isExample.
|
|
4909
|
+
key: ConfigKey.property_example,
|
|
4910
|
+
jsonKey: "example",
|
|
4911
|
+
exportJsonKey: [
|
|
4912
|
+
{
|
|
4913
|
+
"@keyonly": {
|
|
4914
|
+
isExample: true,
|
|
4915
|
+
example: "$parent.isCorrect",
|
|
4916
|
+
"@bit": { isExample: true },
|
|
4917
|
+
"@card": { isExample: true }
|
|
4918
|
+
}
|
|
4919
|
+
},
|
|
4920
|
+
{
|
|
4921
|
+
"@absent": {
|
|
4922
|
+
isExample: "$parent.isCorrect",
|
|
4923
|
+
example: "$parent.isCorrect",
|
|
4924
|
+
"@bit": { isExample: "$parent.isCorrect" },
|
|
4925
|
+
"@card": { isExample: "$parent.isCorrect" }
|
|
4926
|
+
}
|
|
4927
|
+
},
|
|
4928
|
+
{
|
|
4929
|
+
isExample: true,
|
|
4930
|
+
example: "$",
|
|
4931
|
+
"@bit": { isExample: true },
|
|
4932
|
+
"@card": { isExample: true }
|
|
4933
|
+
}
|
|
4934
|
+
],
|
|
4935
|
+
description: "An example for the true/false statement/question",
|
|
4936
|
+
format: TagFormat.boolean,
|
|
4937
|
+
nullable: true
|
|
4938
|
+
}
|
|
4939
|
+
]
|
|
4940
|
+
},
|
|
4941
|
+
{
|
|
4942
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: false }] },
|
|
4943
|
+
key: ConfigKey.tag_false,
|
|
4944
|
+
description: "False value for a true/false statement/question",
|
|
4945
|
+
maxCount: Count.infinity,
|
|
4946
|
+
format: TagFormat.plainText,
|
|
4947
|
+
chain: [
|
|
4948
|
+
{
|
|
4949
|
+
key: ConfigKey.tag_true,
|
|
4950
|
+
jsonKey: "responses[]|set(isCorrect=true)",
|
|
4951
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: true }] },
|
|
4952
|
+
description: "True values for a true/false statement/question",
|
|
4953
|
+
maxCount: Count.infinity,
|
|
4954
|
+
format: TagFormat.plainText
|
|
4955
|
+
},
|
|
4956
|
+
{
|
|
4957
|
+
key: ConfigKey.tag_false,
|
|
4958
|
+
jsonKey: "responses[]|set(isCorrect=false)",
|
|
4959
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: false }] },
|
|
4960
|
+
description: "False values for a true/false statement/question",
|
|
4961
|
+
maxCount: Count.infinity,
|
|
4962
|
+
format: TagFormat.plainText
|
|
3700
4963
|
},
|
|
3701
4964
|
{
|
|
3702
4965
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3703
4966
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3704
4967
|
},
|
|
3705
4968
|
{
|
|
4969
|
+
// @card scope-shift writes response-container isExample.
|
|
3706
4970
|
key: ConfigKey.property_example,
|
|
3707
4971
|
jsonKey: "example",
|
|
4972
|
+
exportJsonKey: [
|
|
4973
|
+
{
|
|
4974
|
+
"@keyonly": {
|
|
4975
|
+
isExample: true,
|
|
4976
|
+
example: "$parent.isCorrect",
|
|
4977
|
+
"@bit": { isExample: true },
|
|
4978
|
+
"@card": { isExample: true }
|
|
4979
|
+
}
|
|
4980
|
+
},
|
|
4981
|
+
{
|
|
4982
|
+
"@absent": {
|
|
4983
|
+
isExample: true,
|
|
4984
|
+
example: "$parent.isCorrect",
|
|
4985
|
+
"@bit": { isExample: true },
|
|
4986
|
+
"@card": { isExample: true }
|
|
4987
|
+
}
|
|
4988
|
+
},
|
|
4989
|
+
{
|
|
4990
|
+
isExample: true,
|
|
4991
|
+
example: "$",
|
|
4992
|
+
"@bit": { isExample: true },
|
|
4993
|
+
"@card": { isExample: true }
|
|
4994
|
+
}
|
|
4995
|
+
],
|
|
3708
4996
|
description: "An example for the true/false statement/question",
|
|
4997
|
+
format: TagFormat.boolean,
|
|
4998
|
+
nullable: true
|
|
4999
|
+
}
|
|
5000
|
+
]
|
|
5001
|
+
}
|
|
5002
|
+
]
|
|
5003
|
+
},
|
|
5004
|
+
[ConfigKey.group_trueFalseInlineSelect]: {
|
|
5005
|
+
type: GroupConfigType.standard,
|
|
5006
|
+
description: "True/False chain composed inline (select body-bit). +/- tags are consume-only at bit level.",
|
|
5007
|
+
tags: [
|
|
5008
|
+
{
|
|
5009
|
+
exportJsonKey: {
|
|
5010
|
+
"@body-inline": {
|
|
5011
|
+
type: "select",
|
|
5012
|
+
attrs: { options: [{ text: "$", isCorrect: true }] }
|
|
5013
|
+
}
|
|
5014
|
+
},
|
|
5015
|
+
key: ConfigKey.tag_true,
|
|
5016
|
+
description: "True value for an inline select body bit",
|
|
5017
|
+
maxCount: Count.infinity,
|
|
5018
|
+
format: TagFormat.plainText,
|
|
5019
|
+
chain: [
|
|
5020
|
+
{
|
|
5021
|
+
key: ConfigKey.tag_true,
|
|
5022
|
+
exportJsonKey: {},
|
|
5023
|
+
description: "True values for an inline select body bit",
|
|
5024
|
+
maxCount: Count.infinity,
|
|
5025
|
+
format: TagFormat.plainText
|
|
5026
|
+
},
|
|
5027
|
+
{
|
|
5028
|
+
key: ConfigKey.tag_false,
|
|
5029
|
+
exportJsonKey: {},
|
|
5030
|
+
description: "False values for an inline select body bit",
|
|
5031
|
+
maxCount: Count.infinity,
|
|
5032
|
+
format: TagFormat.plainText
|
|
5033
|
+
},
|
|
5034
|
+
{
|
|
5035
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5036
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5037
|
+
},
|
|
5038
|
+
{
|
|
5039
|
+
// PLAN-083: cascade-fired `@example` from bit header fires
|
|
5040
|
+
// `isExample:true, example:true` on the FIRST CORRECT option
|
|
5041
|
+
// only (BPG `fillBooleanExample(select.options,
|
|
5042
|
+
// firstCorrectOnly=true)`). Mirrors group_trueFalseInlineHighlight.
|
|
5043
|
+
// Every rule also bubbles `@bit:{isExample:true}` (idempotent
|
|
5044
|
+
// OR — any cascade ⇒ bit marked) and
|
|
5045
|
+
// `@body-inline:{attrs:{isExample:true}}` (node-level marker
|
|
5046
|
+
// on the select node).
|
|
5047
|
+
key: ConfigKey.property_example,
|
|
5048
|
+
jsonKey: "example",
|
|
5049
|
+
exportJsonKey: [
|
|
5050
|
+
{
|
|
5051
|
+
"@keyonly": {
|
|
5052
|
+
isExample: true,
|
|
5053
|
+
example: "$parent.isCorrect",
|
|
5054
|
+
"@bit": { isExample: true },
|
|
5055
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5056
|
+
}
|
|
5057
|
+
},
|
|
5058
|
+
{
|
|
5059
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5060
|
+
maxEmits: 1,
|
|
5061
|
+
rule: {
|
|
5062
|
+
isExample: true,
|
|
5063
|
+
example: true,
|
|
5064
|
+
"@bit": { isExample: true },
|
|
5065
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5066
|
+
}
|
|
5067
|
+
},
|
|
5068
|
+
{
|
|
5069
|
+
isExample: true,
|
|
5070
|
+
example: "$",
|
|
5071
|
+
"@bit": { isExample: true },
|
|
5072
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5073
|
+
}
|
|
5074
|
+
],
|
|
5075
|
+
description: "An example for the inline select option (first correct only)",
|
|
5076
|
+
format: TagFormat.boolean,
|
|
5077
|
+
nullable: true
|
|
5078
|
+
}
|
|
5079
|
+
]
|
|
5080
|
+
},
|
|
5081
|
+
{
|
|
5082
|
+
exportJsonKey: {
|
|
5083
|
+
"@body-inline": {
|
|
5084
|
+
type: "select",
|
|
5085
|
+
attrs: { options: [{ text: "$", isCorrect: false }] }
|
|
5086
|
+
}
|
|
5087
|
+
},
|
|
5088
|
+
key: ConfigKey.tag_false,
|
|
5089
|
+
description: "False value for an inline select body bit",
|
|
5090
|
+
maxCount: Count.infinity,
|
|
5091
|
+
format: TagFormat.plainText,
|
|
5092
|
+
chain: [
|
|
5093
|
+
{
|
|
5094
|
+
key: ConfigKey.tag_true,
|
|
5095
|
+
exportJsonKey: {},
|
|
5096
|
+
description: "True values for an inline select body bit",
|
|
5097
|
+
maxCount: Count.infinity,
|
|
5098
|
+
format: TagFormat.plainText
|
|
5099
|
+
},
|
|
5100
|
+
{
|
|
5101
|
+
key: ConfigKey.tag_false,
|
|
5102
|
+
exportJsonKey: {},
|
|
5103
|
+
description: "False values for an inline select body bit",
|
|
5104
|
+
maxCount: Count.infinity,
|
|
5105
|
+
format: TagFormat.plainText
|
|
5106
|
+
},
|
|
5107
|
+
{
|
|
5108
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5109
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5110
|
+
},
|
|
5111
|
+
{
|
|
5112
|
+
// PLAN-083: identical to the `+` lead's chain @example —
|
|
5113
|
+
// cascade reaches the first correct option regardless of
|
|
5114
|
+
// which lead (+/-) opens the chain. Every firing rule bubbles
|
|
5115
|
+
// `@bit:{isExample:true}` and `@body-inline:{attrs:{isExample:true}}`.
|
|
5116
|
+
key: ConfigKey.property_example,
|
|
5117
|
+
jsonKey: "example",
|
|
5118
|
+
exportJsonKey: [
|
|
5119
|
+
{
|
|
5120
|
+
"@keyonly": {
|
|
5121
|
+
isExample: true,
|
|
5122
|
+
example: "$parent.isCorrect",
|
|
5123
|
+
"@bit": { isExample: true },
|
|
5124
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5125
|
+
}
|
|
5126
|
+
},
|
|
5127
|
+
{
|
|
5128
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5129
|
+
maxEmits: 1,
|
|
5130
|
+
rule: {
|
|
5131
|
+
isExample: true,
|
|
5132
|
+
example: true,
|
|
5133
|
+
"@bit": { isExample: true },
|
|
5134
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5135
|
+
}
|
|
5136
|
+
},
|
|
5137
|
+
{
|
|
5138
|
+
isExample: true,
|
|
5139
|
+
example: "$",
|
|
5140
|
+
"@bit": { isExample: true },
|
|
5141
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5142
|
+
}
|
|
5143
|
+
],
|
|
5144
|
+
description: "An example for the inline select option (first correct only)",
|
|
5145
|
+
format: TagFormat.boolean,
|
|
5146
|
+
nullable: true
|
|
5147
|
+
}
|
|
5148
|
+
]
|
|
5149
|
+
}
|
|
5150
|
+
]
|
|
5151
|
+
},
|
|
5152
|
+
[ConfigKey.group_trueFalseInlineHighlight]: {
|
|
5153
|
+
type: GroupConfigType.standard,
|
|
5154
|
+
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.',
|
|
5155
|
+
tags: [
|
|
5156
|
+
{
|
|
5157
|
+
exportJsonKey: {
|
|
5158
|
+
"@body-inline": {
|
|
5159
|
+
type: "highlight",
|
|
5160
|
+
attrs: { texts: [{ text: "$", isCorrect: true }] }
|
|
5161
|
+
}
|
|
5162
|
+
},
|
|
5163
|
+
key: ConfigKey.tag_true,
|
|
5164
|
+
description: "Highlighted span in the body (correct)",
|
|
5165
|
+
maxCount: Count.infinity,
|
|
5166
|
+
format: TagFormat.plainText,
|
|
5167
|
+
chain: [
|
|
5168
|
+
{
|
|
5169
|
+
key: ConfigKey.tag_true,
|
|
5170
|
+
exportJsonKey: {},
|
|
5171
|
+
description: "Highlighted span values (correct)",
|
|
5172
|
+
maxCount: Count.infinity,
|
|
5173
|
+
format: TagFormat.plainText
|
|
5174
|
+
},
|
|
5175
|
+
{
|
|
5176
|
+
key: ConfigKey.tag_false,
|
|
5177
|
+
exportJsonKey: {},
|
|
5178
|
+
description: "Highlighted span values (incorrect)",
|
|
5179
|
+
maxCount: Count.infinity,
|
|
5180
|
+
format: TagFormat.plainText
|
|
5181
|
+
},
|
|
5182
|
+
{
|
|
5183
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5184
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5185
|
+
},
|
|
5186
|
+
{
|
|
5187
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.13: cascade-fired
|
|
5188
|
+
// `@example` from the bit header fires `example: true` +
|
|
5189
|
+
// `isExample: true` on the FIRST correct highlight only
|
|
5190
|
+
// (BPG `fillBooleanExample(highlight.texts,
|
|
5191
|
+
// firstCorrectOnly=true)`). Incorrect highlights get
|
|
5192
|
+
// nothing (unlike choices, the highlight-text fixture
|
|
5193
|
+
// shows no `isExample` on incorrect entries).
|
|
5194
|
+
key: ConfigKey.property_example,
|
|
5195
|
+
jsonKey: "example",
|
|
5196
|
+
exportJsonKey: [
|
|
5197
|
+
{
|
|
5198
|
+
"@keyonly": {
|
|
5199
|
+
isExample: true,
|
|
5200
|
+
example: "$parent.isCorrect",
|
|
5201
|
+
"@bit": { isExample: true },
|
|
5202
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5203
|
+
}
|
|
5204
|
+
},
|
|
5205
|
+
{
|
|
5206
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5207
|
+
maxEmits: 1,
|
|
5208
|
+
rule: {
|
|
5209
|
+
isExample: true,
|
|
5210
|
+
example: true,
|
|
5211
|
+
"@bit": { isExample: true },
|
|
5212
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5213
|
+
}
|
|
5214
|
+
},
|
|
5215
|
+
{
|
|
5216
|
+
isExample: true,
|
|
5217
|
+
example: "$",
|
|
5218
|
+
"@bit": { isExample: true },
|
|
5219
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5220
|
+
}
|
|
5221
|
+
],
|
|
5222
|
+
description: "An example for the highlighted span (first correct only)",
|
|
5223
|
+
format: TagFormat.boolean,
|
|
5224
|
+
nullable: true
|
|
5225
|
+
}
|
|
5226
|
+
]
|
|
5227
|
+
},
|
|
5228
|
+
{
|
|
5229
|
+
// PLAN-083 follow-up (2026-05-22): mirror the select `-` lead shape
|
|
5230
|
+
// by writing `isCorrect: false`. Without it, `$parent.isCorrect` in
|
|
5231
|
+
// chain-child @example rules resolves to ParentPathMissing for `-`
|
|
5232
|
+
// entries (e.g. `[-fish][@example]`), so the @keyonly rule falls
|
|
5233
|
+
// through and nothing fires. The natural-default strip removes
|
|
5234
|
+
// `isCorrect: false` from the final texts entries (matches fixture).
|
|
5235
|
+
exportJsonKey: {
|
|
5236
|
+
"@body-inline": {
|
|
5237
|
+
type: "highlight",
|
|
5238
|
+
attrs: { texts: [{ text: "$", isCorrect: false }] }
|
|
5239
|
+
}
|
|
5240
|
+
},
|
|
5241
|
+
key: ConfigKey.tag_false,
|
|
5242
|
+
description: "Highlighted span in the body (incorrect)",
|
|
5243
|
+
maxCount: Count.infinity,
|
|
5244
|
+
format: TagFormat.plainText,
|
|
5245
|
+
chain: [
|
|
5246
|
+
{
|
|
5247
|
+
key: ConfigKey.tag_true,
|
|
5248
|
+
exportJsonKey: {},
|
|
5249
|
+
description: "Highlighted span values (correct)",
|
|
5250
|
+
maxCount: Count.infinity,
|
|
3709
5251
|
format: TagFormat.plainText
|
|
5252
|
+
},
|
|
5253
|
+
{
|
|
5254
|
+
key: ConfigKey.tag_false,
|
|
5255
|
+
exportJsonKey: {},
|
|
5256
|
+
description: "Highlighted span values (incorrect)",
|
|
5257
|
+
maxCount: Count.infinity,
|
|
5258
|
+
format: TagFormat.plainText
|
|
5259
|
+
},
|
|
5260
|
+
{
|
|
5261
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5262
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5263
|
+
},
|
|
5264
|
+
{
|
|
5265
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.13: cascade-fired
|
|
5266
|
+
// `@example` on a `-` (incorrect highlight) emits nothing
|
|
5267
|
+
// (highlight-text fixture has no `isExample` on incorrect
|
|
5268
|
+
// entries; firstCorrectOnly cascade skips them entirely).
|
|
5269
|
+
// No `@absent` rule.
|
|
5270
|
+
// PLAN-083: identical to the `+` lead's chain @example —
|
|
5271
|
+
// cascade reaches the first correct option regardless of
|
|
5272
|
+
// which lead (+/-) opens the chain.
|
|
5273
|
+
key: ConfigKey.property_example,
|
|
5274
|
+
jsonKey: "example",
|
|
5275
|
+
exportJsonKey: [
|
|
5276
|
+
{
|
|
5277
|
+
"@keyonly": {
|
|
5278
|
+
isExample: true,
|
|
5279
|
+
example: "$parent.isCorrect",
|
|
5280
|
+
"@bit": { isExample: true },
|
|
5281
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5282
|
+
}
|
|
5283
|
+
},
|
|
5284
|
+
{
|
|
5285
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5286
|
+
maxEmits: 1,
|
|
5287
|
+
rule: {
|
|
5288
|
+
isExample: true,
|
|
5289
|
+
example: true,
|
|
5290
|
+
"@bit": { isExample: true },
|
|
5291
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5292
|
+
}
|
|
5293
|
+
},
|
|
5294
|
+
{
|
|
5295
|
+
isExample: true,
|
|
5296
|
+
example: "$",
|
|
5297
|
+
"@bit": { isExample: true },
|
|
5298
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5299
|
+
}
|
|
5300
|
+
],
|
|
5301
|
+
description: "An example for the highlighted span (first correct only)",
|
|
5302
|
+
format: TagFormat.boolean,
|
|
5303
|
+
nullable: true
|
|
3710
5304
|
}
|
|
3711
5305
|
]
|
|
3712
5306
|
}
|
|
@@ -3719,6 +5313,7 @@ var GROUPS = {
|
|
|
3719
5313
|
{
|
|
3720
5314
|
key: ConfigKey.property_mark,
|
|
3721
5315
|
jsonKey: "marks.mark",
|
|
5316
|
+
exportJsonKey: { marks: [{ mark: "$" }] },
|
|
3722
5317
|
description: "The mark configuration",
|
|
3723
5318
|
format: TagFormat.plainText,
|
|
3724
5319
|
maxCount: Count.infinity,
|
|
@@ -3742,21 +5337,32 @@ var GROUPS = {
|
|
|
3742
5337
|
description: "Mark chain",
|
|
3743
5338
|
tags: [
|
|
3744
5339
|
{
|
|
5340
|
+
exportJsonKey: {
|
|
5341
|
+
"@body-inline": { type: "mark", attrs: { solution: "$" } }
|
|
5342
|
+
},
|
|
3745
5343
|
key: ConfigKey.tag_mark,
|
|
3746
5344
|
description: "The marked content",
|
|
3747
5345
|
maxCount: Count.infinity,
|
|
5346
|
+
format: TagFormat.plainText,
|
|
3748
5347
|
chain: [
|
|
3749
5348
|
{
|
|
3750
5349
|
key: ConfigKey.property_mark,
|
|
3751
5350
|
jsonKey: "mark",
|
|
5351
|
+
exportJsonKey: { mark: "$" },
|
|
3752
5352
|
description: "The mark configuration",
|
|
3753
5353
|
format: TagFormat.plainText
|
|
3754
5354
|
},
|
|
3755
5355
|
{
|
|
3756
5356
|
key: ConfigKey.property_example,
|
|
3757
5357
|
jsonKey: "example",
|
|
5358
|
+
exportJsonKey: [
|
|
5359
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
5360
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
5361
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
5362
|
+
],
|
|
3758
5363
|
description: "An example for the marked content",
|
|
3759
|
-
format: TagFormat.
|
|
5364
|
+
format: TagFormat.bitmarkText,
|
|
5365
|
+
nullable: true
|
|
3760
5366
|
}
|
|
3761
5367
|
]
|
|
3762
5368
|
}
|
|
@@ -3845,7 +5451,8 @@ var GROUPS = {
|
|
|
3845
5451
|
name: "Title",
|
|
3846
5452
|
description: "The title of the book",
|
|
3847
5453
|
maxCount: 2,
|
|
3848
|
-
jsonKey: "title|multi(count=2, key=subtitle)"
|
|
5454
|
+
jsonKey: "title|multi(count=2, key=subtitle)",
|
|
5455
|
+
exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
|
|
3849
5456
|
},
|
|
3850
5457
|
{
|
|
3851
5458
|
key: ConfigKey.property_subtype,
|
|
@@ -3861,6 +5468,7 @@ var GROUPS = {
|
|
|
3861
5468
|
{
|
|
3862
5469
|
key: ConfigKey.resource_coverImage,
|
|
3863
5470
|
jsonKey: "coverImage|resource(type=image, key=image)",
|
|
5471
|
+
exportJsonKey: { coverImage: { type: "image", image: { src: "$" } } },
|
|
3864
5472
|
description: "The cover image of the book",
|
|
3865
5473
|
chain: [
|
|
3866
5474
|
{
|
|
@@ -3878,6 +5486,7 @@ var GROUPS = {
|
|
|
3878
5486
|
{
|
|
3879
5487
|
key: ConfigKey.resource_backgroundImage,
|
|
3880
5488
|
jsonKey: "backgroundImage|resource(type=image, key=image)",
|
|
5489
|
+
exportJsonKey: { backgroundImage: { type: "image", image: { src: "$" } } },
|
|
3881
5490
|
description: "The background image of the book",
|
|
3882
5491
|
chain: [
|
|
3883
5492
|
{
|
|
@@ -4037,10 +5646,21 @@ var GROUPS = {
|
|
|
4037
5646
|
format: TagFormat.plainText,
|
|
4038
5647
|
chain: [
|
|
4039
5648
|
{
|
|
5649
|
+
exportJsonKey: { reference: "$" },
|
|
4040
5650
|
key: ConfigKey.tag_reference,
|
|
4041
5651
|
format: TagFormat.plainText,
|
|
4042
|
-
description: "The reference
|
|
4043
|
-
maxCount:
|
|
5652
|
+
description: "The reference for the book(s) in the learning path",
|
|
5653
|
+
maxCount: 1,
|
|
5654
|
+
chain: [
|
|
5655
|
+
{
|
|
5656
|
+
key: ConfigKey.tag_reference,
|
|
5657
|
+
jsonKey: "referenceEnd",
|
|
5658
|
+
exportJsonKey: { referenceEnd: "$" },
|
|
5659
|
+
format: TagFormat.plainText,
|
|
5660
|
+
description: "The referenceEnd for the book(s) in the learning path",
|
|
5661
|
+
maxCount: 1
|
|
5662
|
+
}
|
|
5663
|
+
]
|
|
4044
5664
|
}
|
|
4045
5665
|
]
|
|
4046
5666
|
}
|
|
@@ -4171,6 +5791,42 @@ var GROUPS = {
|
|
|
4171
5791
|
}
|
|
4172
5792
|
]
|
|
4173
5793
|
},
|
|
5794
|
+
[ConfigKey.group_backgroundWallpaper]: {
|
|
5795
|
+
type: GroupConfigType.standard,
|
|
5796
|
+
description: "Background wallpaper tags",
|
|
5797
|
+
tags: [
|
|
5798
|
+
{
|
|
5799
|
+
key: ConfigKey.resource_backgroundWallpaper,
|
|
5800
|
+
exportJsonKey: { backgroundWallpaper: { type: "image", image: { src: "$" } } },
|
|
5801
|
+
description: "Background wallpaper for the image, used to set a background for the image",
|
|
5802
|
+
chain: [
|
|
5803
|
+
{
|
|
5804
|
+
key: ConfigKey.group_resourceImageCommon,
|
|
5805
|
+
description: "Common resource image tags for images"
|
|
5806
|
+
}
|
|
5807
|
+
]
|
|
5808
|
+
}
|
|
5809
|
+
]
|
|
5810
|
+
},
|
|
5811
|
+
[ConfigKey.group_imageNoZoom]: {
|
|
5812
|
+
type: GroupConfigType.standard,
|
|
5813
|
+
description: "Image bit tags",
|
|
5814
|
+
tags: [
|
|
5815
|
+
{
|
|
5816
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
5817
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
5818
|
+
},
|
|
5819
|
+
{
|
|
5820
|
+
key: ConfigKey.group_resourceBitTags,
|
|
5821
|
+
description: "Resource bit tags for images, used to define additional properties for images"
|
|
5822
|
+
},
|
|
5823
|
+
{
|
|
5824
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
5825
|
+
description: "Resource image tags for images, used to attach images to the bit",
|
|
5826
|
+
minCount: 1
|
|
5827
|
+
}
|
|
5828
|
+
]
|
|
5829
|
+
},
|
|
4174
5830
|
//
|
|
4175
5831
|
// Resource groups
|
|
4176
5832
|
//
|
|
@@ -4180,6 +5836,8 @@ var GROUPS = {
|
|
|
4180
5836
|
tags: [
|
|
4181
5837
|
{
|
|
4182
5838
|
key: ConfigKey.resource_imagePlaceholder,
|
|
5839
|
+
jsonKey: "imagePlaceholder|resource(type=image, key=image)",
|
|
5840
|
+
exportJsonKey: { imagePlaceholder: { type: "image", image: { src: "$" } } },
|
|
4183
5841
|
description: "Placeholder image for the resource",
|
|
4184
5842
|
chain: [
|
|
4185
5843
|
{
|
|
@@ -4288,6 +5946,58 @@ var GROUPS = {
|
|
|
4288
5946
|
}
|
|
4289
5947
|
]
|
|
4290
5948
|
},
|
|
5949
|
+
[ConfigKey.group_resourceImageCommonNoZoom]: {
|
|
5950
|
+
type: GroupConfigType.standard,
|
|
5951
|
+
description: "Common properties for image resources where @zoomDisabled defaults to true",
|
|
5952
|
+
tags: [
|
|
5953
|
+
{
|
|
5954
|
+
key: ConfigKey.group_resourceCommon,
|
|
5955
|
+
description: "Common resource properties"
|
|
5956
|
+
},
|
|
5957
|
+
{
|
|
5958
|
+
key: ConfigKey.property_src1x,
|
|
5959
|
+
description: "The source URL for the image at 1x resolution",
|
|
5960
|
+
format: TagFormat.plainText
|
|
5961
|
+
},
|
|
5962
|
+
{
|
|
5963
|
+
key: ConfigKey.property_src2x,
|
|
5964
|
+
description: "The source URL for the image at 2x resolution",
|
|
5965
|
+
format: TagFormat.plainText
|
|
5966
|
+
},
|
|
5967
|
+
{
|
|
5968
|
+
key: ConfigKey.property_src3x,
|
|
5969
|
+
description: "The source URL for the image at 3x resolution",
|
|
5970
|
+
format: TagFormat.plainText
|
|
5971
|
+
},
|
|
5972
|
+
{
|
|
5973
|
+
key: ConfigKey.property_src4x,
|
|
5974
|
+
description: "The source URL for the image at 4x resolution",
|
|
5975
|
+
format: TagFormat.plainText
|
|
5976
|
+
},
|
|
5977
|
+
{
|
|
5978
|
+
key: ConfigKey.property_width,
|
|
5979
|
+
description: "The width of the image",
|
|
5980
|
+
format: TagFormat.number
|
|
5981
|
+
},
|
|
5982
|
+
{
|
|
5983
|
+
key: ConfigKey.property_height,
|
|
5984
|
+
description: "The height of the image",
|
|
5985
|
+
format: TagFormat.number
|
|
5986
|
+
},
|
|
5987
|
+
{
|
|
5988
|
+
key: ConfigKey.property_alt,
|
|
5989
|
+
description: "The alternative text for the image",
|
|
5990
|
+
format: TagFormat.plainText
|
|
5991
|
+
},
|
|
5992
|
+
// @zoomDisabled with a true default
|
|
5993
|
+
{
|
|
5994
|
+
key: ConfigKey.property_zoomDisabled,
|
|
5995
|
+
description: "If true, zooming is disabled for the image (defaults to true)",
|
|
5996
|
+
format: TagFormat.boolean,
|
|
5997
|
+
defaultValue: "true"
|
|
5998
|
+
}
|
|
5999
|
+
]
|
|
6000
|
+
},
|
|
4291
6001
|
[ConfigKey.group_resourceAudioCommon]: {
|
|
4292
6002
|
type: GroupConfigType.standard,
|
|
4293
6003
|
description: "Common properties for audio resources",
|
|
@@ -4364,6 +6074,7 @@ var GROUPS = {
|
|
|
4364
6074
|
{
|
|
4365
6075
|
key: ConfigKey.property_posterImage,
|
|
4366
6076
|
jsonKey: "posterImage.src",
|
|
6077
|
+
exportJsonKey: { posterImage: { src: "$" } },
|
|
4367
6078
|
description: "The poster image for the video",
|
|
4368
6079
|
format: TagFormat.plainText,
|
|
4369
6080
|
chain: [
|
|
@@ -4376,22 +6087,26 @@ var GROUPS = {
|
|
|
4376
6087
|
{
|
|
4377
6088
|
key: ConfigKey.property_src1x,
|
|
4378
6089
|
description: "The source URL for the video at 1x resolution",
|
|
4379
|
-
format: TagFormat.plainText
|
|
6090
|
+
format: TagFormat.plainText,
|
|
6091
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4380
6092
|
},
|
|
4381
6093
|
{
|
|
4382
6094
|
key: ConfigKey.property_src2x,
|
|
4383
6095
|
description: "The source URL for the video at 2x resolution",
|
|
4384
|
-
format: TagFormat.plainText
|
|
6096
|
+
format: TagFormat.plainText,
|
|
6097
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4385
6098
|
},
|
|
4386
6099
|
{
|
|
4387
6100
|
key: ConfigKey.property_src3x,
|
|
4388
6101
|
description: "The source URL for the video at 3x resolution",
|
|
4389
|
-
format: TagFormat.plainText
|
|
6102
|
+
format: TagFormat.plainText,
|
|
6103
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4390
6104
|
},
|
|
4391
6105
|
{
|
|
4392
6106
|
key: ConfigKey.property_src4x,
|
|
4393
6107
|
description: "The source URL for the video at 4x resolution",
|
|
4394
|
-
format: TagFormat.plainText
|
|
6108
|
+
format: TagFormat.plainText,
|
|
6109
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4395
6110
|
}
|
|
4396
6111
|
]
|
|
4397
6112
|
},
|
|
@@ -4404,6 +6119,7 @@ var GROUPS = {
|
|
|
4404
6119
|
tags: [
|
|
4405
6120
|
{
|
|
4406
6121
|
key: ConfigKey.resource_icon,
|
|
6122
|
+
exportJsonKey: { resource: { type: "icon", icon: { src: "$" } } },
|
|
4407
6123
|
description: "The icon resource",
|
|
4408
6124
|
chain: [
|
|
4409
6125
|
{
|
|
@@ -4420,6 +6136,7 @@ var GROUPS = {
|
|
|
4420
6136
|
tags: [
|
|
4421
6137
|
{
|
|
4422
6138
|
key: ConfigKey.resource_image,
|
|
6139
|
+
exportJsonKey: { resource: { type: "image", image: { src: "$" } } },
|
|
4423
6140
|
description: "The image resource",
|
|
4424
6141
|
chain: [
|
|
4425
6142
|
{
|
|
@@ -4430,12 +6147,30 @@ var GROUPS = {
|
|
|
4430
6147
|
}
|
|
4431
6148
|
]
|
|
4432
6149
|
},
|
|
6150
|
+
[ConfigKey.group_resourceImageNoZoom]: {
|
|
6151
|
+
type: GroupConfigType.resource,
|
|
6152
|
+
description: "Image resource where @zoomDisabled defaults to true",
|
|
6153
|
+
tags: [
|
|
6154
|
+
{
|
|
6155
|
+
key: ConfigKey.resource_image,
|
|
6156
|
+
exportJsonKey: { resource: { type: "image", image: { src: "$" } } },
|
|
6157
|
+
description: "The image resource (no-zoom default)",
|
|
6158
|
+
chain: [
|
|
6159
|
+
{
|
|
6160
|
+
key: ConfigKey.group_resourceImageCommonNoZoom,
|
|
6161
|
+
description: "Common image properties with @zoomDisabled defaulting to true"
|
|
6162
|
+
}
|
|
6163
|
+
]
|
|
6164
|
+
}
|
|
6165
|
+
]
|
|
6166
|
+
},
|
|
4433
6167
|
[ConfigKey.group_resourceImagePortrait]: {
|
|
4434
6168
|
type: GroupConfigType.resource,
|
|
4435
6169
|
description: "Portrait image resource",
|
|
4436
6170
|
tags: [
|
|
4437
6171
|
{
|
|
4438
6172
|
key: ConfigKey.resource_imagePortrait,
|
|
6173
|
+
exportJsonKey: { resource: { type: "image-portrait", imagePortrait: { src: "$" } } },
|
|
4439
6174
|
description: "The portrait image resource",
|
|
4440
6175
|
chain: [
|
|
4441
6176
|
{
|
|
@@ -4452,6 +6187,7 @@ var GROUPS = {
|
|
|
4452
6187
|
tags: [
|
|
4453
6188
|
{
|
|
4454
6189
|
key: ConfigKey.resource_imageLandscape,
|
|
6190
|
+
exportJsonKey: { resource: { type: "image-landscape", imageLandscape: { src: "$" } } },
|
|
4455
6191
|
description: "The landscape image resource",
|
|
4456
6192
|
chain: [
|
|
4457
6193
|
{
|
|
@@ -4468,6 +6204,7 @@ var GROUPS = {
|
|
|
4468
6204
|
tags: [
|
|
4469
6205
|
{
|
|
4470
6206
|
key: ConfigKey.resource_imageEmbed,
|
|
6207
|
+
exportJsonKey: { resource: { type: "image-embed", imageEmbed: { src: "$" } } },
|
|
4471
6208
|
description: "The embedded image resource",
|
|
4472
6209
|
chain: [
|
|
4473
6210
|
{
|
|
@@ -4484,6 +6221,7 @@ var GROUPS = {
|
|
|
4484
6221
|
tags: [
|
|
4485
6222
|
{
|
|
4486
6223
|
key: ConfigKey.resource_imageLink,
|
|
6224
|
+
exportJsonKey: { resource: { type: "image-link", imageLink: { url: "$" } } },
|
|
4487
6225
|
description: "The link to the image resource",
|
|
4488
6226
|
chain: [
|
|
4489
6227
|
{
|
|
@@ -4500,6 +6238,7 @@ var GROUPS = {
|
|
|
4500
6238
|
tags: [
|
|
4501
6239
|
{
|
|
4502
6240
|
key: ConfigKey.resource_audio,
|
|
6241
|
+
exportJsonKey: { resource: { type: "audio", audio: { src: "$" } } },
|
|
4503
6242
|
description: "The audio resource",
|
|
4504
6243
|
chain: [
|
|
4505
6244
|
{
|
|
@@ -4516,6 +6255,7 @@ var GROUPS = {
|
|
|
4516
6255
|
tags: [
|
|
4517
6256
|
{
|
|
4518
6257
|
key: ConfigKey.resource_audioEmbed,
|
|
6258
|
+
exportJsonKey: { resource: { type: "audio-embed", audioEmbed: { src: "$" } } },
|
|
4519
6259
|
description: "The embedded audio resource",
|
|
4520
6260
|
chain: [
|
|
4521
6261
|
{
|
|
@@ -4532,6 +6272,7 @@ var GROUPS = {
|
|
|
4532
6272
|
tags: [
|
|
4533
6273
|
{
|
|
4534
6274
|
key: ConfigKey.resource_audioLink,
|
|
6275
|
+
exportJsonKey: { resource: { type: "audio-link", audioLink: { url: "$" } } },
|
|
4535
6276
|
description: "The link to the audio resource",
|
|
4536
6277
|
chain: [
|
|
4537
6278
|
{
|
|
@@ -4548,6 +6289,7 @@ var GROUPS = {
|
|
|
4548
6289
|
tags: [
|
|
4549
6290
|
{
|
|
4550
6291
|
key: ConfigKey.resource_video,
|
|
6292
|
+
exportJsonKey: { resource: { type: "video", video: { src: "$" } } },
|
|
4551
6293
|
description: "The video resource",
|
|
4552
6294
|
chain: [
|
|
4553
6295
|
{
|
|
@@ -4564,6 +6306,7 @@ var GROUPS = {
|
|
|
4564
6306
|
tags: [
|
|
4565
6307
|
{
|
|
4566
6308
|
key: ConfigKey.resource_videoEmbed,
|
|
6309
|
+
exportJsonKey: { resource: { type: "video-embed", videoEmbed: { url: "$" } } },
|
|
4567
6310
|
description: "The embedded video resource",
|
|
4568
6311
|
chain: [
|
|
4569
6312
|
{
|
|
@@ -4580,6 +6323,7 @@ var GROUPS = {
|
|
|
4580
6323
|
tags: [
|
|
4581
6324
|
{
|
|
4582
6325
|
key: ConfigKey.resource_videoLink,
|
|
6326
|
+
exportJsonKey: { resource: { type: "video-link", videoLink: { url: "$" } } },
|
|
4583
6327
|
description: "The link to the video resource",
|
|
4584
6328
|
chain: [
|
|
4585
6329
|
{
|
|
@@ -4596,6 +6340,9 @@ var GROUPS = {
|
|
|
4596
6340
|
tags: [
|
|
4597
6341
|
{
|
|
4598
6342
|
key: ConfigKey.resource_stillImageFilmEmbed,
|
|
6343
|
+
exportJsonKey: {
|
|
6344
|
+
resource: { type: "still-image-film-embed", stillImageFilmEmbed: { url: "$" } }
|
|
6345
|
+
},
|
|
4599
6346
|
description: "The embedded still image film resource",
|
|
4600
6347
|
chain: [
|
|
4601
6348
|
{
|
|
@@ -4612,6 +6359,9 @@ var GROUPS = {
|
|
|
4612
6359
|
tags: [
|
|
4613
6360
|
{
|
|
4614
6361
|
key: ConfigKey.resource_stillImageFilmLink,
|
|
6362
|
+
exportJsonKey: {
|
|
6363
|
+
resource: { type: "still-image-film-link", stillImageFilmLink: { url: "$" } }
|
|
6364
|
+
},
|
|
4615
6365
|
description: "The link to the still image film resource",
|
|
4616
6366
|
chain: [
|
|
4617
6367
|
{
|
|
@@ -4628,6 +6378,7 @@ var GROUPS = {
|
|
|
4628
6378
|
tags: [
|
|
4629
6379
|
{
|
|
4630
6380
|
key: ConfigKey.resource_article,
|
|
6381
|
+
exportJsonKey: { resource: { type: "article", article: { body: "$" } } },
|
|
4631
6382
|
description: "The article resource",
|
|
4632
6383
|
chain: [
|
|
4633
6384
|
{
|
|
@@ -4644,6 +6395,7 @@ var GROUPS = {
|
|
|
4644
6395
|
tags: [
|
|
4645
6396
|
{
|
|
4646
6397
|
key: ConfigKey.resource_articleEmbed,
|
|
6398
|
+
exportJsonKey: { resource: { type: "article-embed", articleEmbed: { url: "$" } } },
|
|
4647
6399
|
description: "The embedded article resource",
|
|
4648
6400
|
chain: [
|
|
4649
6401
|
{
|
|
@@ -4660,6 +6412,7 @@ var GROUPS = {
|
|
|
4660
6412
|
tags: [
|
|
4661
6413
|
{
|
|
4662
6414
|
key: ConfigKey.resource_articleLink,
|
|
6415
|
+
exportJsonKey: { resource: { type: "article-link", articleLink: { url: "$" } } },
|
|
4663
6416
|
description: "The link to the article resource",
|
|
4664
6417
|
chain: [
|
|
4665
6418
|
{
|
|
@@ -4676,6 +6429,7 @@ var GROUPS = {
|
|
|
4676
6429
|
tags: [
|
|
4677
6430
|
{
|
|
4678
6431
|
key: ConfigKey.resource_document,
|
|
6432
|
+
exportJsonKey: { resource: { type: "document", document: { url: "$" } } },
|
|
4679
6433
|
description: "The document resource",
|
|
4680
6434
|
chain: [
|
|
4681
6435
|
{
|
|
@@ -4692,6 +6446,7 @@ var GROUPS = {
|
|
|
4692
6446
|
tags: [
|
|
4693
6447
|
{
|
|
4694
6448
|
key: ConfigKey.resource_documentEmbed,
|
|
6449
|
+
exportJsonKey: { resource: { type: "document-embed", documentEmbed: { url: "$" } } },
|
|
4695
6450
|
description: "The embedded document resource",
|
|
4696
6451
|
chain: [
|
|
4697
6452
|
{
|
|
@@ -4708,6 +6463,7 @@ var GROUPS = {
|
|
|
4708
6463
|
tags: [
|
|
4709
6464
|
{
|
|
4710
6465
|
key: ConfigKey.resource_documentLink,
|
|
6466
|
+
exportJsonKey: { resource: { type: "document-link", documentLink: { url: "$" } } },
|
|
4711
6467
|
description: "The link to the document resource",
|
|
4712
6468
|
chain: [
|
|
4713
6469
|
{
|
|
@@ -4724,6 +6480,7 @@ var GROUPS = {
|
|
|
4724
6480
|
tags: [
|
|
4725
6481
|
{
|
|
4726
6482
|
key: ConfigKey.resource_documentDownload,
|
|
6483
|
+
exportJsonKey: { resource: { type: "document-download", documentDownload: { url: "$" } } },
|
|
4727
6484
|
description: "The downloadable document resource",
|
|
4728
6485
|
chain: [
|
|
4729
6486
|
{
|
|
@@ -4740,6 +6497,7 @@ var GROUPS = {
|
|
|
4740
6497
|
tags: [
|
|
4741
6498
|
{
|
|
4742
6499
|
key: ConfigKey.resource_appLink,
|
|
6500
|
+
exportJsonKey: { resource: { type: "app-link", appLink: { url: "$" } } },
|
|
4743
6501
|
description: "The link to the app resource",
|
|
4744
6502
|
chain: [
|
|
4745
6503
|
{
|
|
@@ -4756,6 +6514,7 @@ var GROUPS = {
|
|
|
4756
6514
|
tags: [
|
|
4757
6515
|
{
|
|
4758
6516
|
key: ConfigKey.resource_websiteLink,
|
|
6517
|
+
exportJsonKey: { resource: { type: "website-link", websiteLink: { url: "$" } } },
|
|
4759
6518
|
description: "The link to the website resource",
|
|
4760
6519
|
chain: [
|
|
4761
6520
|
{
|
|
@@ -4814,6 +6573,7 @@ var GROUPS = {
|
|
|
4814
6573
|
{
|
|
4815
6574
|
key: ConfigKey.resource_previewImage,
|
|
4816
6575
|
jsonKey: "previewImage|resource(type=image, key=image)",
|
|
6576
|
+
exportJsonKey: { previewImage: { type: "image", image: { src: "$" } } },
|
|
4817
6577
|
description: "The preview image resource",
|
|
4818
6578
|
chain: [
|
|
4819
6579
|
{
|
|
@@ -4831,6 +6591,7 @@ var GROUPS = {
|
|
|
4831
6591
|
{
|
|
4832
6592
|
key: ConfigKey.resource_previewVideo,
|
|
4833
6593
|
jsonKey: "previewVideo|resource(type=video, key=video)",
|
|
6594
|
+
exportJsonKey: { previewVideo: { type: "video", video: { src: "$" } } },
|
|
4834
6595
|
description: "The preview video resource",
|
|
4835
6596
|
chain: [
|
|
4836
6597
|
{
|
|
@@ -4895,20 +6656,53 @@ var ConfigHydrator = class {
|
|
|
4895
6656
|
_side.name,
|
|
4896
6657
|
_side.repeat ?? false,
|
|
4897
6658
|
variantsOfSide,
|
|
4898
|
-
_side.jsonKey
|
|
6659
|
+
_side.jsonKey,
|
|
6660
|
+
_side.exportJsonKey,
|
|
6661
|
+
Object.prototype.hasOwnProperty.call(_side, "exportJsonKey")
|
|
4899
6662
|
);
|
|
4900
6663
|
sides.push(sideConfig);
|
|
4901
6664
|
}
|
|
4902
6665
|
const cardSetConfig = new CardSetConfig(
|
|
4903
6666
|
_cardSet,
|
|
4904
6667
|
_cardSetConfig.jsonKey,
|
|
4905
|
-
_cardSetConfig.
|
|
6668
|
+
_cardSetConfig.exportJsonKey,
|
|
6669
|
+
Object.prototype.hasOwnProperty.call(_cardSetConfig, "exportJsonKey"),
|
|
6670
|
+
this.hydrateCardSections(_cardSetConfig.sections),
|
|
4906
6671
|
sides
|
|
4907
6672
|
);
|
|
4908
6673
|
return cardSetConfig;
|
|
4909
6674
|
}
|
|
6675
|
+
hydrateCardSections(sections) {
|
|
6676
|
+
if (!sections) return void 0;
|
|
6677
|
+
const out = {};
|
|
6678
|
+
for (const [k, v] of Object.entries(sections)) {
|
|
6679
|
+
out[k] = {
|
|
6680
|
+
jsonKey: v.jsonKey,
|
|
6681
|
+
exportJsonKey: v.exportJsonKey,
|
|
6682
|
+
hasExportJsonKey: Object.prototype.hasOwnProperty.call(v, "exportJsonKey"),
|
|
6683
|
+
isDefault: v.isDefault,
|
|
6684
|
+
sideJsonKey: v.sideJsonKey,
|
|
6685
|
+
sideExportJsonKey: v.sideExportJsonKey,
|
|
6686
|
+
hasSideExportJsonKey: Object.prototype.hasOwnProperty.call(v, "sideExportJsonKey"),
|
|
6687
|
+
// PLAN-085: cardinality fields pass through; defaults applied
|
|
6688
|
+
// downstream by the config consumer (Rust treats `0` / undefined
|
|
6689
|
+
// as unbounded).
|
|
6690
|
+
minCount: v.minCount,
|
|
6691
|
+
maxCount: v.maxCount
|
|
6692
|
+
};
|
|
6693
|
+
}
|
|
6694
|
+
return out;
|
|
6695
|
+
}
|
|
4910
6696
|
hydrateTagConfig(_tag) {
|
|
4911
|
-
const {
|
|
6697
|
+
const {
|
|
6698
|
+
key: _configKey,
|
|
6699
|
+
maxCount,
|
|
6700
|
+
minCount,
|
|
6701
|
+
chain: _chain,
|
|
6702
|
+
deprecated,
|
|
6703
|
+
jsonKey,
|
|
6704
|
+
exportJsonKey
|
|
6705
|
+
} = _tag;
|
|
4912
6706
|
const configKey = Enum2(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
|
|
4913
6707
|
if (!configKey) throw new Error(`No tag key found for config key '${configKey}'`);
|
|
4914
6708
|
const tag = Enum2(Tag).fromValue(configKey);
|
|
@@ -4923,6 +6717,9 @@ var ConfigHydrator = class {
|
|
|
4923
6717
|
maxCount: maxCount ?? MAX_COUNT_DEFAULT,
|
|
4924
6718
|
minCount: minCount ?? MIN_COUNT_DEFAULT,
|
|
4925
6719
|
chain,
|
|
6720
|
+
jsonKey,
|
|
6721
|
+
exportJsonKey,
|
|
6722
|
+
hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
|
|
4926
6723
|
deprecated
|
|
4927
6724
|
});
|
|
4928
6725
|
return {
|
|
@@ -4941,7 +6738,8 @@ var ConfigHydrator = class {
|
|
|
4941
6738
|
format,
|
|
4942
6739
|
values,
|
|
4943
6740
|
defaultValue,
|
|
4944
|
-
jsonKey
|
|
6741
|
+
jsonKey,
|
|
6742
|
+
exportJsonKey
|
|
4945
6743
|
} = _tag;
|
|
4946
6744
|
const configKey = Enum2(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
|
|
4947
6745
|
if (!configKey) throw new Error(`No property key found for config key '${configKey}'`);
|
|
@@ -4957,6 +6755,8 @@ var ConfigHydrator = class {
|
|
|
4957
6755
|
minCount: minCount ?? MIN_COUNT_DEFAULT,
|
|
4958
6756
|
chain,
|
|
4959
6757
|
jsonKey,
|
|
6758
|
+
exportJsonKey,
|
|
6759
|
+
hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
|
|
4960
6760
|
format,
|
|
4961
6761
|
values,
|
|
4962
6762
|
defaultValue,
|
|
@@ -4969,7 +6769,15 @@ var ConfigHydrator = class {
|
|
|
4969
6769
|
};
|
|
4970
6770
|
}
|
|
4971
6771
|
hydrateResourceTagConfig(_tag) {
|
|
4972
|
-
const {
|
|
6772
|
+
const {
|
|
6773
|
+
key: _configKey,
|
|
6774
|
+
maxCount,
|
|
6775
|
+
minCount,
|
|
6776
|
+
chain: _chain,
|
|
6777
|
+
deprecated,
|
|
6778
|
+
jsonKey,
|
|
6779
|
+
exportJsonKey
|
|
6780
|
+
} = _tag;
|
|
4973
6781
|
const configKey = Enum2(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
|
|
4974
6782
|
if (!configKey) throw new Error(`No resource key found for config key '${configKey}'`);
|
|
4975
6783
|
const tag = _configKey.substring(1);
|
|
@@ -4984,6 +6792,8 @@ var ConfigHydrator = class {
|
|
|
4984
6792
|
minCount: minCount ?? MIN_COUNT_DEFAULT,
|
|
4985
6793
|
chain,
|
|
4986
6794
|
jsonKey,
|
|
6795
|
+
exportJsonKey,
|
|
6796
|
+
hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
|
|
4987
6797
|
deprecated
|
|
4988
6798
|
});
|
|
4989
6799
|
return {
|
|
@@ -5015,14 +6825,25 @@ var ConfigHydrator = class {
|
|
|
5015
6825
|
};
|
|
5016
6826
|
}
|
|
5017
6827
|
hydrateCardVariantConfig(_variant) {
|
|
5018
|
-
const {
|
|
6828
|
+
const {
|
|
6829
|
+
tags: _tags,
|
|
6830
|
+
bodyAllowed,
|
|
6831
|
+
bodyRequired,
|
|
6832
|
+
repeatCount,
|
|
6833
|
+
jsonKey,
|
|
6834
|
+
exportJsonKey,
|
|
6835
|
+
format
|
|
6836
|
+
} = _variant;
|
|
5019
6837
|
const tags2 = this.hydrateTagsConfig(_tags);
|
|
5020
6838
|
const cardSetConfig = new CardVariantConfig(
|
|
5021
6839
|
tags2.tags,
|
|
5022
6840
|
bodyAllowed,
|
|
5023
6841
|
bodyRequired,
|
|
5024
6842
|
repeatCount,
|
|
5025
|
-
jsonKey
|
|
6843
|
+
jsonKey,
|
|
6844
|
+
exportJsonKey,
|
|
6845
|
+
Object.prototype.hasOwnProperty.call(_variant, "exportJsonKey"),
|
|
6846
|
+
format
|
|
5026
6847
|
);
|
|
5027
6848
|
return cardSetConfig;
|
|
5028
6849
|
}
|
|
@@ -5060,6 +6881,7 @@ var BITS = {
|
|
|
5060
6881
|
description: "Common tags for quiz bits"
|
|
5061
6882
|
},
|
|
5062
6883
|
{
|
|
6884
|
+
exportJsonKey: { title: "$" },
|
|
5063
6885
|
key: ConfigKey.tag_title,
|
|
5064
6886
|
description: "The title of the flashcard quiz"
|
|
5065
6887
|
},
|
|
@@ -5068,6 +6890,21 @@ var BITS = {
|
|
|
5068
6890
|
description: "The flashcard set to use for the app flashcards",
|
|
5069
6891
|
format: TagFormat.plainText,
|
|
5070
6892
|
maxCount: Count.infinity
|
|
6893
|
+
},
|
|
6894
|
+
{
|
|
6895
|
+
// Override inherited @example from group_standardTags: string root
|
|
6896
|
+
// example. Bare/synthesized emits `example: "true"` (a text literal
|
|
6897
|
+
// that field-coerces to a paragraph "true" in bitmark+ contexts);
|
|
6898
|
+
// valued [@example:text] emits the user's text via `$`.
|
|
6899
|
+
key: ConfigKey.property_example,
|
|
6900
|
+
exportJsonKey: [
|
|
6901
|
+
{ "@keyonly": { isExample: true, example: "true" } },
|
|
6902
|
+
{ "@absent": { isExample: true, example: "true" } },
|
|
6903
|
+
{ isExample: true, example: "$" }
|
|
6904
|
+
],
|
|
6905
|
+
description: "The example text for the bit",
|
|
6906
|
+
format: TagFormat.plainText,
|
|
6907
|
+
nullable: true
|
|
5071
6908
|
}
|
|
5072
6909
|
],
|
|
5073
6910
|
rootExampleType: ExampleType.string
|
|
@@ -5149,6 +6986,7 @@ var BITS = {
|
|
|
5149
6986
|
description: "Article bit, used for articles / paragraphs",
|
|
5150
6987
|
tags: [
|
|
5151
6988
|
{
|
|
6989
|
+
exportJsonKey: { title: "$" },
|
|
5152
6990
|
key: ConfigKey.tag_title,
|
|
5153
6991
|
description: "The title of the article"
|
|
5154
6992
|
}
|
|
@@ -5256,7 +7094,8 @@ var BITS = {
|
|
|
5256
7094
|
key: ConfigKey.tag_title,
|
|
5257
7095
|
description: "Title and subtitle of the catalog item",
|
|
5258
7096
|
maxCount: 2,
|
|
5259
|
-
jsonKey: "title|multi(count=2, key=subtitle)"
|
|
7097
|
+
jsonKey: "title|multi(count=2, key=subtitle)",
|
|
7098
|
+
exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
|
|
5260
7099
|
},
|
|
5261
7100
|
{
|
|
5262
7101
|
key: ConfigKey.property_coverImage,
|
|
@@ -5266,6 +7105,7 @@ var BITS = {
|
|
|
5266
7105
|
{
|
|
5267
7106
|
key: ConfigKey.resource_coverImage,
|
|
5268
7107
|
jsonKey: "coverImage|resource(type=image, key=image)",
|
|
7108
|
+
exportJsonKey: { coverImage: { type: "image", image: { src: "$" } } },
|
|
5269
7109
|
description: "Cover image of the catalog item",
|
|
5270
7110
|
chain: [
|
|
5271
7111
|
{
|
|
@@ -5393,6 +7233,18 @@ var BITS = {
|
|
|
5393
7233
|
key: ConfigKey.group_previewVideos,
|
|
5394
7234
|
description: "Array of preview videos for the catalog item",
|
|
5395
7235
|
maxCount: Count.infinity
|
|
7236
|
+
},
|
|
7237
|
+
{
|
|
7238
|
+
// Override inherited @example from group_standardTags: string root example.
|
|
7239
|
+
key: ConfigKey.property_example,
|
|
7240
|
+
exportJsonKey: [
|
|
7241
|
+
{ "@keyonly": { isExample: true, example: "true" } },
|
|
7242
|
+
{ "@absent": { isExample: true, example: "true" } },
|
|
7243
|
+
{ isExample: true, example: "$" }
|
|
7244
|
+
],
|
|
7245
|
+
description: "The example text for the bit",
|
|
7246
|
+
format: TagFormat.plainText,
|
|
7247
|
+
nullable: true
|
|
5396
7248
|
}
|
|
5397
7249
|
],
|
|
5398
7250
|
rootExampleType: ExampleType.string
|
|
@@ -5406,7 +7258,8 @@ var BITS = {
|
|
|
5406
7258
|
key: ConfigKey.tag_title,
|
|
5407
7259
|
description: "Title and subtitle of the catalog item",
|
|
5408
7260
|
maxCount: 2,
|
|
5409
|
-
jsonKey: "title|multi(count=2, key=subtitle)"
|
|
7261
|
+
jsonKey: "title|multi(count=2, key=subtitle)",
|
|
7262
|
+
exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
|
|
5410
7263
|
},
|
|
5411
7264
|
{
|
|
5412
7265
|
key: ConfigKey.property_coverImage,
|
|
@@ -5416,6 +7269,7 @@ var BITS = {
|
|
|
5416
7269
|
{
|
|
5417
7270
|
key: ConfigKey.resource_coverImage,
|
|
5418
7271
|
jsonKey: "coverImage|resource(type=image, key=image)",
|
|
7272
|
+
exportJsonKey: { coverImage: { type: "image", image: { src: "$" } } },
|
|
5419
7273
|
description: "Cover image of the catalog item",
|
|
5420
7274
|
chain: [
|
|
5421
7275
|
{
|
|
@@ -5543,6 +7397,18 @@ var BITS = {
|
|
|
5543
7397
|
key: ConfigKey.group_previewVideos,
|
|
5544
7398
|
description: "Array of preview videos for the catalog item",
|
|
5545
7399
|
maxCount: Count.infinity
|
|
7400
|
+
},
|
|
7401
|
+
{
|
|
7402
|
+
// Override inherited @example from group_standardTags: string root example.
|
|
7403
|
+
key: ConfigKey.property_example,
|
|
7404
|
+
exportJsonKey: [
|
|
7405
|
+
{ "@keyonly": { isExample: true, example: "true" } },
|
|
7406
|
+
{ "@absent": { isExample: true, example: "true" } },
|
|
7407
|
+
{ isExample: true, example: "$" }
|
|
7408
|
+
],
|
|
7409
|
+
description: "The example text for the bit",
|
|
7410
|
+
format: TagFormat.plainText,
|
|
7411
|
+
nullable: true
|
|
5546
7412
|
}
|
|
5547
7413
|
],
|
|
5548
7414
|
rootExampleType: ExampleType.string
|
|
@@ -5556,7 +7422,8 @@ var BITS = {
|
|
|
5556
7422
|
key: ConfigKey.tag_title,
|
|
5557
7423
|
description: "Title and subtitle of the catalog item",
|
|
5558
7424
|
maxCount: 2,
|
|
5559
|
-
jsonKey: "title|multi(count=2, key=subtitle)"
|
|
7425
|
+
jsonKey: "title|multi(count=2, key=subtitle)",
|
|
7426
|
+
exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
|
|
5560
7427
|
},
|
|
5561
7428
|
{
|
|
5562
7429
|
key: ConfigKey.property_coverImage,
|
|
@@ -5682,6 +7549,18 @@ var BITS = {
|
|
|
5682
7549
|
key: ConfigKey.group_previewVideos,
|
|
5683
7550
|
description: "Array of preview videos for the catalog item",
|
|
5684
7551
|
maxCount: Count.infinity
|
|
7552
|
+
},
|
|
7553
|
+
{
|
|
7554
|
+
// Override inherited @example from group_standardTags: string root example.
|
|
7555
|
+
key: ConfigKey.property_example,
|
|
7556
|
+
exportJsonKey: [
|
|
7557
|
+
{ "@keyonly": { isExample: true, example: "true" } },
|
|
7558
|
+
{ "@absent": { isExample: true, example: "true" } },
|
|
7559
|
+
{ isExample: true, example: "$" }
|
|
7560
|
+
],
|
|
7561
|
+
description: "The example text for the bit",
|
|
7562
|
+
format: TagFormat.plainText,
|
|
7563
|
+
nullable: true
|
|
5685
7564
|
}
|
|
5686
7565
|
],
|
|
5687
7566
|
rootExampleType: ExampleType.string
|
|
@@ -5883,11 +7762,13 @@ var BITS = {
|
|
|
5883
7762
|
description: "Bit alias, used to create an alias for a bit",
|
|
5884
7763
|
tags: [
|
|
5885
7764
|
{
|
|
7765
|
+
exportJsonKey: { reference: "$" },
|
|
5886
7766
|
key: ConfigKey.tag_reference,
|
|
5887
7767
|
format: TagFormat.plainText,
|
|
5888
7768
|
description: "The reference to the bit that this alias points to"
|
|
5889
7769
|
},
|
|
5890
7770
|
{
|
|
7771
|
+
exportJsonKey: { anchor: "$" },
|
|
5891
7772
|
key: ConfigKey.tag_anchor,
|
|
5892
7773
|
format: TagFormat.plainText,
|
|
5893
7774
|
description: "The anchor for the bit alias, used for linking"
|
|
@@ -6089,7 +7970,8 @@ var BITS = {
|
|
|
6089
7970
|
description: "The title of the book cover",
|
|
6090
7971
|
maxCount: 2,
|
|
6091
7972
|
// title & subtitle
|
|
6092
|
-
jsonKey: "title|multi(count=2, key=subtitle)"
|
|
7973
|
+
jsonKey: "title|multi(count=2, key=subtitle)",
|
|
7974
|
+
exportJsonKey: [{ "@level=1": { title: "$" } }, { "@level=2": { subtitle: "$" } }]
|
|
6093
7975
|
},
|
|
6094
7976
|
{
|
|
6095
7977
|
key: ConfigKey.property_coverColor,
|
|
@@ -6233,6 +8115,7 @@ var BITS = {
|
|
|
6233
8115
|
description: "Chapter bit, used to define chapters in books or articles",
|
|
6234
8116
|
tags: [
|
|
6235
8117
|
{
|
|
8118
|
+
exportJsonKey: { anchor: "$" },
|
|
6236
8119
|
key: ConfigKey.tag_anchor,
|
|
6237
8120
|
format: TagFormat.plainText,
|
|
6238
8121
|
description: "The anchor for the chapter, used for linking"
|
|
@@ -6240,7 +8123,8 @@ var BITS = {
|
|
|
6240
8123
|
{
|
|
6241
8124
|
key: ConfigKey.tag_title,
|
|
6242
8125
|
description: "The title of the chapter",
|
|
6243
|
-
jsonKey: "title|setMulti(level)"
|
|
8126
|
+
jsonKey: "title|setMulti(level)",
|
|
8127
|
+
exportJsonKey: { title: "$", level: "$level" }
|
|
6244
8128
|
},
|
|
6245
8129
|
{
|
|
6246
8130
|
key: ConfigKey.property_toc,
|
|
@@ -6271,8 +8155,31 @@ var BITS = {
|
|
|
6271
8155
|
description: "Tags for gaps in cloze and multiple choice text bits"
|
|
6272
8156
|
},
|
|
6273
8157
|
{
|
|
6274
|
-
key: ConfigKey.
|
|
8158
|
+
key: ConfigKey.group_trueFalseInlineSelect,
|
|
6275
8159
|
description: "Tags for true/false questions in cloze and multiple choice text bits"
|
|
8160
|
+
},
|
|
8161
|
+
{
|
|
8162
|
+
// Bit-level @isCaseSensitive — empty exportJsonKey (no bit-level emission);
|
|
8163
|
+
// defaultValue 'true' phantom-fires onto the ancestor stack so the gap chain's
|
|
8164
|
+
// `@absent: $ancestor` rule resolves to true. Mirrors BPG Builder.ts:1643-1652
|
|
8165
|
+
// `pushDownTree(... 'isCaseSensitive', data.isCaseSensitive ?? true)` for cloze bits.
|
|
8166
|
+
key: ConfigKey.property_isCaseSensitive,
|
|
8167
|
+
exportJsonKey: {},
|
|
8168
|
+
description: "If the cloze answers are case sensitive",
|
|
8169
|
+
format: TagFormat.boolean,
|
|
8170
|
+
defaultValue: "true"
|
|
8171
|
+
},
|
|
8172
|
+
{
|
|
8173
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
8174
|
+
key: ConfigKey.property_example,
|
|
8175
|
+
exportJsonKey: [
|
|
8176
|
+
{ "@keyonly": { isExample: true } },
|
|
8177
|
+
{ "@absent": { isExample: true } },
|
|
8178
|
+
{ isExample: true, example: "$" }
|
|
8179
|
+
],
|
|
8180
|
+
description: "The example(s) for the bit",
|
|
8181
|
+
format: TagFormat.bitmarkText,
|
|
8182
|
+
nullable: true
|
|
6276
8183
|
}
|
|
6277
8184
|
]
|
|
6278
8185
|
},
|
|
@@ -6293,6 +8200,7 @@ var BITS = {
|
|
|
6293
8200
|
},
|
|
6294
8201
|
{
|
|
6295
8202
|
key: ConfigKey.property_isCaseSensitive,
|
|
8203
|
+
exportJsonKey: {},
|
|
6296
8204
|
description: "If the cloze answers are case sensitive",
|
|
6297
8205
|
format: TagFormat.boolean,
|
|
6298
8206
|
defaultValue: "true"
|
|
@@ -6310,18 +8218,56 @@ var BITS = {
|
|
|
6310
8218
|
{
|
|
6311
8219
|
key: ConfigKey.group_gap,
|
|
6312
8220
|
description: "Tags for gaps in cloze bits"
|
|
8221
|
+
},
|
|
8222
|
+
{
|
|
8223
|
+
// Override inherited @example: cloze is in OLD parser's
|
|
8224
|
+
// `isTopLevelExample` allow-list, so [@example] at bit-header
|
|
8225
|
+
// emits `isExample: true`.
|
|
8226
|
+
key: ConfigKey.property_example,
|
|
8227
|
+
exportJsonKey: [
|
|
8228
|
+
{ "@keyonly": { isExample: true } },
|
|
8229
|
+
{ "@absent": { isExample: true } },
|
|
8230
|
+
{ isExample: true, example: "$" }
|
|
8231
|
+
],
|
|
8232
|
+
description: "The example(s) for the bit",
|
|
8233
|
+
format: TagFormat.bitmarkText,
|
|
8234
|
+
nullable: true
|
|
6313
8235
|
}
|
|
6314
8236
|
]
|
|
6315
8237
|
},
|
|
6316
8238
|
[BitType2.clozeInstructionGrouped]: {
|
|
6317
8239
|
since: "1.3.0",
|
|
6318
8240
|
baseBitType: BitType2.cloze,
|
|
6319
|
-
description: "Cloze instruction grouped bit, used for cloze questions with grouped instructions"
|
|
8241
|
+
description: "Cloze instruction grouped bit, used for cloze questions with grouped instructions",
|
|
8242
|
+
tags: [
|
|
8243
|
+
{
|
|
8244
|
+
key: ConfigKey.property_quizCountItems,
|
|
8245
|
+
description: "The number of items in the cloze quiz (instruction-grouped default: true)",
|
|
8246
|
+
format: TagFormat.boolean,
|
|
8247
|
+
defaultValue: "true"
|
|
8248
|
+
}
|
|
8249
|
+
// Note: quizStrikethroughSolutions defaults to false for instruction-grouped per OLD
|
|
8250
|
+
// JsonGenerator.ts:1689-1690, which equals the Boolean natural default → no override needed.
|
|
8251
|
+
]
|
|
6320
8252
|
},
|
|
6321
8253
|
[BitType2.clozeSolutionGrouped]: {
|
|
6322
8254
|
since: "1.3.0",
|
|
6323
8255
|
baseBitType: BitType2.cloze,
|
|
6324
|
-
description: "Cloze solution grouped bit, used for cloze questions with grouped solutions"
|
|
8256
|
+
description: "Cloze solution grouped bit, used for cloze questions with grouped solutions",
|
|
8257
|
+
tags: [
|
|
8258
|
+
{
|
|
8259
|
+
key: ConfigKey.property_quizCountItems,
|
|
8260
|
+
description: "The number of items in the cloze quiz (solution-grouped default: true)",
|
|
8261
|
+
format: TagFormat.boolean,
|
|
8262
|
+
defaultValue: "true"
|
|
8263
|
+
},
|
|
8264
|
+
{
|
|
8265
|
+
key: ConfigKey.property_quizStrikethroughSolutions,
|
|
8266
|
+
description: "If the cloze solutions should be strikethrough (solution-grouped default: true)",
|
|
8267
|
+
format: TagFormat.boolean,
|
|
8268
|
+
defaultValue: "true"
|
|
8269
|
+
}
|
|
8270
|
+
]
|
|
6325
8271
|
},
|
|
6326
8272
|
[BitType2.clozeSeveral]: {
|
|
6327
8273
|
since: "3.5.0",
|
|
@@ -6357,6 +8303,17 @@ var BITS = {
|
|
|
6357
8303
|
{
|
|
6358
8304
|
key: ConfigKey.group_quizCommon,
|
|
6359
8305
|
description: "Common tags for quiz bits"
|
|
8306
|
+
},
|
|
8307
|
+
{
|
|
8308
|
+
// PLAN-084 (R12): bit-level @isCaseSensitive — empty exportJsonKey
|
|
8309
|
+
// (no bit-level emission); defaultValue 'true' phantom-fires onto
|
|
8310
|
+
// the ancestor stack so each listItem's gap chain `@absent: $ancestor`
|
|
8311
|
+
// rule resolves to true. Mirrors the cloze bit (bits.ts:1326-1336).
|
|
8312
|
+
key: ConfigKey.property_isCaseSensitive,
|
|
8313
|
+
exportJsonKey: {},
|
|
8314
|
+
description: "If the cloze answers are case sensitive",
|
|
8315
|
+
format: TagFormat.boolean,
|
|
8316
|
+
defaultValue: "true"
|
|
6360
8317
|
}
|
|
6361
8318
|
],
|
|
6362
8319
|
cardSet: CardSetConfigKey.clozeList
|
|
@@ -6390,6 +8347,11 @@ var BITS = {
|
|
|
6390
8347
|
description: "Formula bit, used for mathematical formulas in articles or documents",
|
|
6391
8348
|
textFormatDefault: TextFormat2.latex
|
|
6392
8349
|
},
|
|
8350
|
+
[BitType2.formulaImage]: {
|
|
8351
|
+
since: "5.23.0",
|
|
8352
|
+
baseBitType: BitType2.formula,
|
|
8353
|
+
description: "Formula image bit, used for mathematical formulas rendered as images"
|
|
8354
|
+
},
|
|
6393
8355
|
[BitType2.smartStandardFormula]: {
|
|
6394
8356
|
since: "3.11.0",
|
|
6395
8357
|
baseBitType: BitType2.formula,
|
|
@@ -6518,6 +8480,7 @@ var BITS = {
|
|
|
6518
8480
|
tags: [
|
|
6519
8481
|
{
|
|
6520
8482
|
key: ConfigKey.group_person,
|
|
8483
|
+
exportJsonKey: { partner: { name: "$" } },
|
|
6521
8484
|
description: "Tags for the person in the conversation"
|
|
6522
8485
|
}
|
|
6523
8486
|
]
|
|
@@ -6742,6 +8705,7 @@ var BITS = {
|
|
|
6742
8705
|
{
|
|
6743
8706
|
key: ConfigKey.property_servings,
|
|
6744
8707
|
jsonKey: "servings.servings",
|
|
8708
|
+
exportJsonKey: { servings: { servings: "$" } },
|
|
6745
8709
|
description: "The number of servings for the ingredients",
|
|
6746
8710
|
format: TagFormat.number,
|
|
6747
8711
|
chain: [
|
|
@@ -6767,6 +8731,7 @@ var BITS = {
|
|
|
6767
8731
|
format: TagFormat.boolean
|
|
6768
8732
|
},
|
|
6769
8733
|
{
|
|
8734
|
+
exportJsonKey: { hint: "$" },
|
|
6770
8735
|
key: ConfigKey.tag_hint,
|
|
6771
8736
|
description: "Hint for the ingredient, used to provide additional information",
|
|
6772
8737
|
format: TagFormat.plainText
|
|
@@ -6944,6 +8909,18 @@ var BITS = {
|
|
|
6944
8909
|
description: "Reference for the essay, used to link to external resources",
|
|
6945
8910
|
format: TagFormat.plainText,
|
|
6946
8911
|
maxCount: Count.infinity
|
|
8912
|
+
},
|
|
8913
|
+
{
|
|
8914
|
+
// Override inherited @example from group_standardTags: string root example.
|
|
8915
|
+
key: ConfigKey.property_example,
|
|
8916
|
+
exportJsonKey: [
|
|
8917
|
+
{ "@keyonly": { isExample: true, example: "true" } },
|
|
8918
|
+
{ "@absent": { isExample: true, example: "true" } },
|
|
8919
|
+
{ isExample: true, example: "$" }
|
|
8920
|
+
],
|
|
8921
|
+
description: "The example text for the essay bit",
|
|
8922
|
+
format: TagFormat.plainText,
|
|
8923
|
+
nullable: true
|
|
6947
8924
|
}
|
|
6948
8925
|
],
|
|
6949
8926
|
rootExampleType: ExampleType.string
|
|
@@ -6964,8 +8941,21 @@ var BITS = {
|
|
|
6964
8941
|
description: "Example bit, used to provide examples in articles or books",
|
|
6965
8942
|
tags: [
|
|
6966
8943
|
{
|
|
8944
|
+
exportJsonKey: { title: "$" },
|
|
6967
8945
|
key: ConfigKey.tag_title,
|
|
6968
8946
|
description: "The title of the example"
|
|
8947
|
+
},
|
|
8948
|
+
{
|
|
8949
|
+
// Override inherited @example from group_standardTags: string root example.
|
|
8950
|
+
key: ConfigKey.property_example,
|
|
8951
|
+
exportJsonKey: [
|
|
8952
|
+
{ "@keyonly": { isExample: true, example: "true" } },
|
|
8953
|
+
{ "@absent": { isExample: true, example: "true" } },
|
|
8954
|
+
{ isExample: true, example: "$" }
|
|
8955
|
+
],
|
|
8956
|
+
description: "The example text for the example bit",
|
|
8957
|
+
format: TagFormat.plainText,
|
|
8958
|
+
nullable: true
|
|
6969
8959
|
}
|
|
6970
8960
|
],
|
|
6971
8961
|
rootExampleType: ExampleType.string
|
|
@@ -7051,7 +9041,19 @@ var BITS = {
|
|
|
7051
9041
|
[BitType2.articleAi]: {
|
|
7052
9042
|
since: "1.3.0",
|
|
7053
9043
|
baseBitType: BitType2.article,
|
|
7054
|
-
description: "Article AI bit, used to create AI-generated articles"
|
|
9044
|
+
description: "Article AI bit, used to create AI-generated articles",
|
|
9045
|
+
tags: [
|
|
9046
|
+
{
|
|
9047
|
+
// Shadows the inherited @aiGenerated from the standard group: this
|
|
9048
|
+
// bit type forces aiGenerated:true regardless of source value or
|
|
9049
|
+
// absence. Literal `true` in the export pattern ignores `$`.
|
|
9050
|
+
key: ConfigKey.property_aiGenerated,
|
|
9051
|
+
description: "AI-generated flag, forced true for article-ai bits",
|
|
9052
|
+
format: TagFormat.boolean,
|
|
9053
|
+
defaultValue: "true",
|
|
9054
|
+
exportJsonKey: { aiGenerated: true }
|
|
9055
|
+
}
|
|
9056
|
+
]
|
|
7055
9057
|
},
|
|
7056
9058
|
[BitType2.articleAttachment]: {
|
|
7057
9059
|
since: "1.3.0",
|
|
@@ -7376,7 +9378,19 @@ var BITS = {
|
|
|
7376
9378
|
[BitType2.noteAi]: {
|
|
7377
9379
|
since: "1.3.0",
|
|
7378
9380
|
baseBitType: BitType2.note,
|
|
7379
|
-
description: "Note AI bit, used to create AI-generated notes in articles or books"
|
|
9381
|
+
description: "Note AI bit, used to create AI-generated notes in articles or books",
|
|
9382
|
+
tags: [
|
|
9383
|
+
{
|
|
9384
|
+
// Shadows the inherited @aiGenerated from the standard group: this
|
|
9385
|
+
// bit type forces aiGenerated:true regardless of source value or
|
|
9386
|
+
// absence. Literal `true` in the export pattern ignores `$`.
|
|
9387
|
+
key: ConfigKey.property_aiGenerated,
|
|
9388
|
+
description: "AI-generated flag, forced true for article-ai bits",
|
|
9389
|
+
format: TagFormat.boolean,
|
|
9390
|
+
defaultValue: "true",
|
|
9391
|
+
exportJsonKey: { aiGenerated: true }
|
|
9392
|
+
}
|
|
9393
|
+
]
|
|
7380
9394
|
},
|
|
7381
9395
|
[BitType2.notebookArticle]: {
|
|
7382
9396
|
since: "1.3.0",
|
|
@@ -7501,7 +9515,19 @@ var BITS = {
|
|
|
7501
9515
|
[BitType2.summaryAi]: {
|
|
7502
9516
|
since: "1.3.0",
|
|
7503
9517
|
baseBitType: BitType2.summary,
|
|
7504
|
-
description: "AI-generated summary bit"
|
|
9518
|
+
description: "AI-generated summary bit",
|
|
9519
|
+
tags: [
|
|
9520
|
+
{
|
|
9521
|
+
// Shadows the inherited @aiGenerated from the standard group: this
|
|
9522
|
+
// bit type forces aiGenerated:true regardless of source value or
|
|
9523
|
+
// absence. Literal `true` in the export pattern ignores `$`.
|
|
9524
|
+
key: ConfigKey.property_aiGenerated,
|
|
9525
|
+
description: "AI-generated flag, forced true for article-ai bits",
|
|
9526
|
+
format: TagFormat.boolean,
|
|
9527
|
+
defaultValue: "true",
|
|
9528
|
+
exportJsonKey: { aiGenerated: true }
|
|
9529
|
+
}
|
|
9530
|
+
]
|
|
7505
9531
|
},
|
|
7506
9532
|
[BitType2.videoTranscript]: {
|
|
7507
9533
|
since: "1.3.0",
|
|
@@ -7775,7 +9801,7 @@ var BITS = {
|
|
|
7775
9801
|
description: "Product ID for the module product, used to link to a specific product",
|
|
7776
9802
|
format: TagFormat.plainText,
|
|
7777
9803
|
minCount: 1,
|
|
7778
|
-
maxCount:
|
|
9804
|
+
maxCount: 1
|
|
7779
9805
|
}
|
|
7780
9806
|
]
|
|
7781
9807
|
},
|
|
@@ -7828,9 +9854,13 @@ var BITS = {
|
|
|
7828
9854
|
description: "Resource bit tags for logo grave images, used to define additional properties"
|
|
7829
9855
|
},
|
|
7830
9856
|
{
|
|
7831
|
-
// Image resource
|
|
7832
|
-
|
|
9857
|
+
// Image resource — fully-expanded shape so each `&image` emission
|
|
9858
|
+
// produces a complete `{type, image: {src}}` object inside the
|
|
9859
|
+
// `images[]` array. Chain attrs like `[@zoomDisabled]` fold under
|
|
9860
|
+
// `images[].image` via the `[]` last-element-merge semantic.
|
|
9861
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
7833
9862
|
description: "Resource image tags for logo grave images, used to attach images",
|
|
9863
|
+
exportJsonKey: { images: [{ type: "image", image: { src: "$" } }] },
|
|
7834
9864
|
minCount: 1,
|
|
7835
9865
|
maxCount: Count.infinity
|
|
7836
9866
|
}
|
|
@@ -7994,15 +10024,27 @@ var BITS = {
|
|
|
7994
10024
|
format: TagFormat.plainText,
|
|
7995
10025
|
chain: [
|
|
7996
10026
|
{
|
|
10027
|
+
exportJsonKey: { reference: "$" },
|
|
7997
10028
|
key: ConfigKey.tag_reference,
|
|
7998
10029
|
format: TagFormat.plainText,
|
|
7999
10030
|
description: "Reference tag for the book, used to link to the book in the system",
|
|
8000
|
-
maxCount:
|
|
10031
|
+
maxCount: 1,
|
|
10032
|
+
chain: [
|
|
10033
|
+
{
|
|
10034
|
+
key: ConfigKey.tag_reference,
|
|
10035
|
+
jsonKey: "referenceEnd",
|
|
10036
|
+
exportJsonKey: { referenceEnd: "$" },
|
|
10037
|
+
format: TagFormat.plainText,
|
|
10038
|
+
description: "End reference tag for the book, used to specify a range",
|
|
10039
|
+
maxCount: 1
|
|
10040
|
+
}
|
|
10041
|
+
]
|
|
8001
10042
|
}
|
|
8002
10043
|
]
|
|
8003
10044
|
},
|
|
8004
10045
|
{
|
|
8005
10046
|
/* Allow incorrectly chained reference tag */
|
|
10047
|
+
exportJsonKey: { reference: "$" },
|
|
8006
10048
|
key: ConfigKey.tag_reference,
|
|
8007
10049
|
format: TagFormat.plainText,
|
|
8008
10050
|
description: "Reference tag for the book, used to link to the book in the system"
|
|
@@ -8049,18 +10091,41 @@ var BITS = {
|
|
|
8049
10091
|
format: TagFormat.plainText,
|
|
8050
10092
|
chain: [
|
|
8051
10093
|
{
|
|
10094
|
+
exportJsonKey: { reference: "$" },
|
|
8052
10095
|
key: ConfigKey.tag_reference,
|
|
8053
10096
|
format: TagFormat.plainText,
|
|
8054
10097
|
description: "Reference tag for the book, used to link to the book in the system",
|
|
8055
|
-
maxCount:
|
|
10098
|
+
maxCount: 1,
|
|
10099
|
+
chain: [
|
|
10100
|
+
{
|
|
10101
|
+
key: ConfigKey.tag_reference,
|
|
10102
|
+
jsonKey: "referenceEnd",
|
|
10103
|
+
exportJsonKey: { referenceEnd: "$" },
|
|
10104
|
+
format: TagFormat.plainText,
|
|
10105
|
+
description: "End reference tag for the book, used to specify a range",
|
|
10106
|
+
maxCount: 1
|
|
10107
|
+
}
|
|
10108
|
+
]
|
|
8056
10109
|
}
|
|
8057
10110
|
]
|
|
8058
10111
|
},
|
|
8059
10112
|
{
|
|
8060
10113
|
/* Allow incorrectly chained reference tag */
|
|
10114
|
+
exportJsonKey: { reference: "$" },
|
|
8061
10115
|
key: ConfigKey.tag_reference,
|
|
8062
10116
|
format: TagFormat.plainText,
|
|
8063
|
-
description: "Reference tag for the book, used to link to the book in the system"
|
|
10117
|
+
description: "Reference tag for the book, used to link to the book in the system",
|
|
10118
|
+
maxCount: 1,
|
|
10119
|
+
chain: [
|
|
10120
|
+
{
|
|
10121
|
+
key: ConfigKey.tag_reference,
|
|
10122
|
+
jsonKey: "referenceEnd",
|
|
10123
|
+
exportJsonKey: { referenceEnd: "$" },
|
|
10124
|
+
format: TagFormat.plainText,
|
|
10125
|
+
description: "End reference tag for the book, used to specify a range",
|
|
10126
|
+
maxCount: 1
|
|
10127
|
+
}
|
|
10128
|
+
]
|
|
8064
10129
|
},
|
|
8065
10130
|
{
|
|
8066
10131
|
key: ConfigKey.property_buttonCaption,
|
|
@@ -8085,14 +10150,29 @@ var BITS = {
|
|
|
8085
10150
|
tags: [
|
|
8086
10151
|
{
|
|
8087
10152
|
key: ConfigKey.property_book,
|
|
10153
|
+
// Starter-array shape: each `[@book:value]` chain appends a fresh
|
|
10154
|
+
// `{ book, reference }` entry. The chained `►` (tag_reference) lands
|
|
10155
|
+
// inside the most-recently-appended entry as `reference: $`.
|
|
10156
|
+
exportJsonKey: { book: [{ book: "$" }] },
|
|
8088
10157
|
description: "Book reference for the page, used to link to a specific book",
|
|
8089
10158
|
maxCount: Count.infinity,
|
|
8090
10159
|
chain: [
|
|
8091
10160
|
{
|
|
10161
|
+
exportJsonKey: { reference: "$" },
|
|
8092
10162
|
key: ConfigKey.tag_reference,
|
|
8093
10163
|
format: TagFormat.plainText,
|
|
8094
10164
|
description: "Reference tag for the book, used to link to the book in the system",
|
|
8095
|
-
maxCount:
|
|
10165
|
+
maxCount: 1,
|
|
10166
|
+
chain: [
|
|
10167
|
+
{
|
|
10168
|
+
key: ConfigKey.tag_reference,
|
|
10169
|
+
jsonKey: "referenceEnd",
|
|
10170
|
+
exportJsonKey: { referenceEnd: "$" },
|
|
10171
|
+
format: TagFormat.plainText,
|
|
10172
|
+
description: "End reference tag for the book, used to specify a range",
|
|
10173
|
+
maxCount: 1
|
|
10174
|
+
}
|
|
10175
|
+
]
|
|
8096
10176
|
}
|
|
8097
10177
|
]
|
|
8098
10178
|
},
|
|
@@ -8141,7 +10221,9 @@ var BITS = {
|
|
|
8141
10221
|
format: TagFormat.plainText
|
|
8142
10222
|
}
|
|
8143
10223
|
],
|
|
8144
|
-
|
|
10224
|
+
// page-footer emits cards under `sections` (vs `listItems` for the
|
|
10225
|
+
// sibling exampleList / assignmentList bits) — see JsonGenerator.ts.
|
|
10226
|
+
cardSet: CardSetConfigKey.pageFooterSections
|
|
8145
10227
|
},
|
|
8146
10228
|
[BitType2.legend]: {
|
|
8147
10229
|
since: "3.12.0",
|
|
@@ -8183,6 +10265,20 @@ var BITS = {
|
|
|
8183
10265
|
since: "1.34.0",
|
|
8184
10266
|
baseBitType: BitType2._standard,
|
|
8185
10267
|
description: "Definition list bit, used to create lists of definitions in articles or books",
|
|
10268
|
+
tags: [
|
|
10269
|
+
{
|
|
10270
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10271
|
+
key: ConfigKey.property_example,
|
|
10272
|
+
exportJsonKey: [
|
|
10273
|
+
{ "@keyonly": { isExample: true } },
|
|
10274
|
+
{ "@absent": { isExample: true } },
|
|
10275
|
+
{ isExample: true, example: "$" }
|
|
10276
|
+
],
|
|
10277
|
+
description: "The example(s) for the bit",
|
|
10278
|
+
format: TagFormat.bitmarkText,
|
|
10279
|
+
nullable: true
|
|
10280
|
+
}
|
|
10281
|
+
],
|
|
8186
10282
|
cardSet: CardSetConfigKey.definitionList
|
|
8187
10283
|
},
|
|
8188
10284
|
[BitType2.metaSearchDefaultTerms]: {
|
|
@@ -8205,6 +10301,18 @@ var BITS = {
|
|
|
8205
10301
|
{
|
|
8206
10302
|
key: ConfigKey.group_quizCommon,
|
|
8207
10303
|
description: "Common quiz tags for flashcards"
|
|
10304
|
+
},
|
|
10305
|
+
{
|
|
10306
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10307
|
+
key: ConfigKey.property_example,
|
|
10308
|
+
exportJsonKey: [
|
|
10309
|
+
{ "@keyonly": { isExample: true } },
|
|
10310
|
+
{ "@absent": { isExample: true } },
|
|
10311
|
+
{ isExample: true, example: "$" }
|
|
10312
|
+
],
|
|
10313
|
+
description: "The example(s) for the bit",
|
|
10314
|
+
format: TagFormat.bitmarkText,
|
|
10315
|
+
nullable: true
|
|
8208
10316
|
}
|
|
8209
10317
|
],
|
|
8210
10318
|
cardSet: CardSetConfigKey.flashcard
|
|
@@ -8212,7 +10320,11 @@ var BITS = {
|
|
|
8212
10320
|
[BitType2.flashcard1]: {
|
|
8213
10321
|
since: "1.3.0",
|
|
8214
10322
|
baseBitType: BitType2.flashcard,
|
|
8215
|
-
description: "Flashcard 1 bit"
|
|
10323
|
+
description: "Flashcard 1 bit",
|
|
10324
|
+
// PLAN-085: use the flashcard1 cardset (sections.default.maxCount=1)
|
|
10325
|
+
// instead of inheriting `flashcard`'s unbounded cardset, since this
|
|
10326
|
+
// bit type structurally allows only a single card.
|
|
10327
|
+
cardSet: CardSetConfigKey.flashcard1
|
|
8216
10328
|
},
|
|
8217
10329
|
[BitType2.qAndACard]: {
|
|
8218
10330
|
since: "3.25.0",
|
|
@@ -8247,8 +10359,24 @@ var BITS = {
|
|
|
8247
10359
|
description: "Common quiz tags for highlighted text"
|
|
8248
10360
|
},
|
|
8249
10361
|
{
|
|
8250
|
-
|
|
8251
|
-
|
|
10362
|
+
// Dedicated highlight inline-select chain: tag_true / tag_false
|
|
10363
|
+
// emit `{type:"highlight", attrs:{texts:[{text,isCorrect?}]}}`
|
|
10364
|
+
// inline body nodes via @body-inline. Bit shares no tag IDs with
|
|
10365
|
+
// multiple-choice / multiple-choice-1 (which use group_trueFalse).
|
|
10366
|
+
key: ConfigKey.group_trueFalseInlineHighlight,
|
|
10367
|
+
description: "True/False quiz tags for highlighted text (inline body nodes)"
|
|
10368
|
+
},
|
|
10369
|
+
{
|
|
10370
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10371
|
+
key: ConfigKey.property_example,
|
|
10372
|
+
exportJsonKey: [
|
|
10373
|
+
{ "@keyonly": { isExample: true } },
|
|
10374
|
+
{ "@absent": { isExample: true } },
|
|
10375
|
+
{ isExample: true, example: "$" }
|
|
10376
|
+
],
|
|
10377
|
+
description: "The example(s) for the bit",
|
|
10378
|
+
format: TagFormat.bitmarkText,
|
|
10379
|
+
nullable: true
|
|
8252
10380
|
}
|
|
8253
10381
|
]
|
|
8254
10382
|
},
|
|
@@ -8258,14 +10386,8 @@ var BITS = {
|
|
|
8258
10386
|
description: "Image bit, used to create images in articles or books",
|
|
8259
10387
|
tags: [
|
|
8260
10388
|
{
|
|
8261
|
-
key: ConfigKey.
|
|
8262
|
-
description: "Background wallpaper for
|
|
8263
|
-
chain: [
|
|
8264
|
-
{
|
|
8265
|
-
key: ConfigKey.group_resourceImageCommon,
|
|
8266
|
-
description: "Common resource image tags for images"
|
|
8267
|
-
}
|
|
8268
|
-
]
|
|
10389
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
10390
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
8269
10391
|
},
|
|
8270
10392
|
{
|
|
8271
10393
|
key: ConfigKey.group_resourceBitTags,
|
|
@@ -8368,8 +10490,15 @@ var BITS = {
|
|
|
8368
10490
|
},
|
|
8369
10491
|
[BitType2.imageSeparator]: {
|
|
8370
10492
|
since: "1.4.15",
|
|
8371
|
-
baseBitType: BitType2.
|
|
8372
|
-
description: "Image separator bit, used to create separators in articles or books"
|
|
10493
|
+
baseBitType: BitType2._standard,
|
|
10494
|
+
description: "Image separator bit, used to create separators in articles or books",
|
|
10495
|
+
tags: [
|
|
10496
|
+
{
|
|
10497
|
+
key: ConfigKey.group_imageNoZoom,
|
|
10498
|
+
description: "Image no zoom tags for images, used to define whether images should have zoom functionality"
|
|
10499
|
+
}
|
|
10500
|
+
],
|
|
10501
|
+
resourceAttachmentAllowed: false
|
|
8373
10502
|
},
|
|
8374
10503
|
[BitType2.imageSeparatorAlt]: {
|
|
8375
10504
|
since: "1.16.0",
|
|
@@ -8408,15 +10537,20 @@ var BITS = {
|
|
|
8408
10537
|
},
|
|
8409
10538
|
[BitType2.pageBanner]: {
|
|
8410
10539
|
since: "1.4.3",
|
|
8411
|
-
baseBitType: BitType2.
|
|
10540
|
+
baseBitType: BitType2._standard,
|
|
8412
10541
|
description: "Page banner bit, used to create banners for pages in articles or books",
|
|
8413
10542
|
tags: [
|
|
8414
10543
|
{
|
|
8415
10544
|
key: ConfigKey.property_slug,
|
|
8416
10545
|
description: "Slug for the page banner, used to identify the banner in the system",
|
|
8417
10546
|
format: TagFormat.plainText
|
|
10547
|
+
},
|
|
10548
|
+
{
|
|
10549
|
+
key: ConfigKey.group_imageNoZoom,
|
|
10550
|
+
description: "Image no zoom tags for images, used to define whether images should have zoom functionality"
|
|
8418
10551
|
}
|
|
8419
|
-
]
|
|
10552
|
+
],
|
|
10553
|
+
resourceAttachmentAllowed: false
|
|
8420
10554
|
},
|
|
8421
10555
|
[BitType2.pageHero]: {
|
|
8422
10556
|
since: "1.11.0",
|
|
@@ -8431,7 +10565,7 @@ var BITS = {
|
|
|
8431
10565
|
},
|
|
8432
10566
|
[BitType2.tableImage]: {
|
|
8433
10567
|
since: "1.5.15",
|
|
8434
|
-
baseBitType: BitType2.
|
|
10568
|
+
baseBitType: BitType2.tableExtended,
|
|
8435
10569
|
description: "Table image bit, used to create images in tables in articles or books",
|
|
8436
10570
|
tags: [
|
|
8437
10571
|
{
|
|
@@ -8440,14 +10574,8 @@ var BITS = {
|
|
|
8440
10574
|
format: TagFormat.bitmarkText
|
|
8441
10575
|
},
|
|
8442
10576
|
{
|
|
8443
|
-
key: ConfigKey.
|
|
8444
|
-
description: "Background wallpaper for
|
|
8445
|
-
chain: [
|
|
8446
|
-
{
|
|
8447
|
-
key: ConfigKey.group_resourceImageCommon,
|
|
8448
|
-
description: "Common resource image tags for images"
|
|
8449
|
-
}
|
|
8450
|
-
]
|
|
10577
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
10578
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
8451
10579
|
},
|
|
8452
10580
|
{
|
|
8453
10581
|
key: ConfigKey.group_resourceBitTags,
|
|
@@ -8590,9 +10718,10 @@ var BITS = {
|
|
|
8590
10718
|
description: "Resource bit tags for logo grave images, used to define additional properties"
|
|
8591
10719
|
},
|
|
8592
10720
|
{
|
|
8593
|
-
// Image resource
|
|
8594
|
-
key: ConfigKey.
|
|
10721
|
+
// Image resource — fully-expanded shape (see BitType.extractorImage).
|
|
10722
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
8595
10723
|
description: "Resource image tags for logo grave images, used to attach images",
|
|
10724
|
+
exportJsonKey: { logos: [{ type: "image", image: { src: "$" } }] },
|
|
8596
10725
|
minCount: 1,
|
|
8597
10726
|
maxCount: Count.infinity
|
|
8598
10727
|
}
|
|
@@ -8602,7 +10731,17 @@ var BITS = {
|
|
|
8602
10731
|
[BitType2.prototypeImages]: {
|
|
8603
10732
|
since: "1.6.1",
|
|
8604
10733
|
baseBitType: BitType2.imagesLogoGrave,
|
|
8605
|
-
description: "Prototype images bit, used to create prototype images in articles or books"
|
|
10734
|
+
description: "Prototype images bit, used to create prototype images in articles or books",
|
|
10735
|
+
tags: [
|
|
10736
|
+
{
|
|
10737
|
+
// Override inherited `logos` wrapper with `images` for this bit type.
|
|
10738
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
10739
|
+
description: "Resource image tags for prototype images",
|
|
10740
|
+
exportJsonKey: { images: [{ type: "image", image: { src: "$" } }] },
|
|
10741
|
+
minCount: 1,
|
|
10742
|
+
maxCount: Count.infinity
|
|
10743
|
+
}
|
|
10744
|
+
]
|
|
8606
10745
|
},
|
|
8607
10746
|
[BitType2.internalLink]: {
|
|
8608
10747
|
since: "1.3.0",
|
|
@@ -8610,6 +10749,7 @@ var BITS = {
|
|
|
8610
10749
|
description: "Internal link bit, used to create links to other bits in articles or books",
|
|
8611
10750
|
tags: [
|
|
8612
10751
|
{
|
|
10752
|
+
exportJsonKey: { reference: "$" },
|
|
8613
10753
|
key: ConfigKey.tag_reference,
|
|
8614
10754
|
format: TagFormat.plainText,
|
|
8615
10755
|
description: "Reference tag for the internal link, used to link to the target bit"
|
|
@@ -8628,8 +10768,21 @@ var BITS = {
|
|
|
8628
10768
|
},
|
|
8629
10769
|
{
|
|
8630
10770
|
key: ConfigKey.property_reasonableNumOfChars,
|
|
10771
|
+
exportJsonKey: {},
|
|
8631
10772
|
description: "Reasonable number of characters for the interview, used to limit input size",
|
|
8632
10773
|
format: TagFormat.number
|
|
10774
|
+
},
|
|
10775
|
+
{
|
|
10776
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10777
|
+
key: ConfigKey.property_example,
|
|
10778
|
+
exportJsonKey: [
|
|
10779
|
+
{ "@keyonly": { isExample: true } },
|
|
10780
|
+
{ "@absent": { isExample: true } },
|
|
10781
|
+
{ isExample: true, example: "$" }
|
|
10782
|
+
],
|
|
10783
|
+
description: "The example(s) for the bit",
|
|
10784
|
+
format: TagFormat.bitmarkText,
|
|
10785
|
+
nullable: true
|
|
8633
10786
|
}
|
|
8634
10787
|
],
|
|
8635
10788
|
cardSet: CardSetConfigKey.questions
|
|
@@ -8988,6 +11141,18 @@ var BITS = {
|
|
|
8988
11141
|
{
|
|
8989
11142
|
key: ConfigKey.group_mark,
|
|
8990
11143
|
description: "Mark tags, used to define the content of marks"
|
|
11144
|
+
},
|
|
11145
|
+
{
|
|
11146
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11147
|
+
key: ConfigKey.property_example,
|
|
11148
|
+
exportJsonKey: [
|
|
11149
|
+
{ "@keyonly": { isExample: true } },
|
|
11150
|
+
{ "@absent": { isExample: true } },
|
|
11151
|
+
{ isExample: true, example: "$" }
|
|
11152
|
+
],
|
|
11153
|
+
description: "The example(s) for the bit",
|
|
11154
|
+
format: TagFormat.bitmarkText,
|
|
11155
|
+
nullable: true
|
|
8991
11156
|
}
|
|
8992
11157
|
]
|
|
8993
11158
|
},
|
|
@@ -9003,9 +11168,27 @@ var BITS = {
|
|
|
9003
11168
|
},
|
|
9004
11169
|
{
|
|
9005
11170
|
key: ConfigKey.property_isCaseSensitive,
|
|
11171
|
+
exportJsonKey: {},
|
|
9006
11172
|
description: "Case sensitivity for matching pairs, used to define if matches are case-sensitive",
|
|
9007
11173
|
format: TagFormat.boolean,
|
|
9008
11174
|
defaultValue: "true"
|
|
11175
|
+
},
|
|
11176
|
+
{
|
|
11177
|
+
// Override inherited @example: in `isTopLevelExample` allow-list
|
|
11178
|
+
// (covers match, matchAll, matchReverse, matchAllReverse,
|
|
11179
|
+
// matchSolutionGrouped, matchMatrix, matchAudio, matchPicture).
|
|
11180
|
+
// Bit-level fires emit only `isExample`; the @example value (when
|
|
11181
|
+
// provided) is recorded in the ancestor stack and consumed by
|
|
11182
|
+
// per-pair/per-cell variant overrides — not surfaced at bit scope.
|
|
11183
|
+
key: ConfigKey.property_example,
|
|
11184
|
+
exportJsonKey: [
|
|
11185
|
+
{ "@keyonly": { isExample: true } },
|
|
11186
|
+
{ "@absent": { isExample: true } },
|
|
11187
|
+
{ isExample: true }
|
|
11188
|
+
],
|
|
11189
|
+
description: "The example(s) for the bit",
|
|
11190
|
+
format: TagFormat.bitmarkText,
|
|
11191
|
+
nullable: true
|
|
9009
11192
|
}
|
|
9010
11193
|
],
|
|
9011
11194
|
cardSet: CardSetConfigKey.matchPairs
|
|
@@ -9055,6 +11238,7 @@ var BITS = {
|
|
|
9055
11238
|
tags: [
|
|
9056
11239
|
{
|
|
9057
11240
|
key: ConfigKey.property_reasonableNumOfChars,
|
|
11241
|
+
exportJsonKey: {},
|
|
9058
11242
|
description: "Reasonable number of characters for feedback, used to limit input size",
|
|
9059
11243
|
format: TagFormat.number
|
|
9060
11244
|
}
|
|
@@ -9089,6 +11273,18 @@ var BITS = {
|
|
|
9089
11273
|
{
|
|
9090
11274
|
key: ConfigKey.group_trueFalse,
|
|
9091
11275
|
description: "True/False tags for multiple choice 1 questions"
|
|
11276
|
+
},
|
|
11277
|
+
{
|
|
11278
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11279
|
+
key: ConfigKey.property_example,
|
|
11280
|
+
exportJsonKey: [
|
|
11281
|
+
{ "@keyonly": { isExample: true } },
|
|
11282
|
+
{ "@absent": { isExample: true } },
|
|
11283
|
+
{ isExample: true, example: "$" }
|
|
11284
|
+
],
|
|
11285
|
+
description: "The example(s) for the bit",
|
|
11286
|
+
format: TagFormat.bitmarkText,
|
|
11287
|
+
nullable: true
|
|
9092
11288
|
}
|
|
9093
11289
|
]
|
|
9094
11290
|
},
|
|
@@ -9110,8 +11306,20 @@ var BITS = {
|
|
|
9110
11306
|
{
|
|
9111
11307
|
key: ConfigKey.group_trueFalse,
|
|
9112
11308
|
description: "True/False tags for multiple choice questions"
|
|
9113
|
-
}
|
|
11309
|
+
},
|
|
9114
11310
|
// This is actually for multiple-choice-1, but we support it here as well (as many bits are wrong)
|
|
11311
|
+
{
|
|
11312
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11313
|
+
key: ConfigKey.property_example,
|
|
11314
|
+
exportJsonKey: [
|
|
11315
|
+
{ "@keyonly": { isExample: true } },
|
|
11316
|
+
{ "@absent": { isExample: true } },
|
|
11317
|
+
{ isExample: true, example: "$" }
|
|
11318
|
+
],
|
|
11319
|
+
description: "The example(s) for the bit",
|
|
11320
|
+
format: TagFormat.bitmarkText,
|
|
11321
|
+
nullable: true
|
|
11322
|
+
}
|
|
9115
11323
|
],
|
|
9116
11324
|
cardSet: CardSetConfigKey.quiz
|
|
9117
11325
|
},
|
|
@@ -9131,8 +11339,20 @@ var BITS = {
|
|
|
9131
11339
|
description: "Common quiz tags for multiple choice text questions"
|
|
9132
11340
|
},
|
|
9133
11341
|
{
|
|
9134
|
-
key: ConfigKey.
|
|
11342
|
+
key: ConfigKey.group_trueFalseInlineSelect,
|
|
9135
11343
|
description: "True/False tags for multiple choice text questions"
|
|
11344
|
+
},
|
|
11345
|
+
{
|
|
11346
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11347
|
+
key: ConfigKey.property_example,
|
|
11348
|
+
exportJsonKey: [
|
|
11349
|
+
{ "@keyonly": { isExample: true } },
|
|
11350
|
+
{ "@absent": { isExample: true } },
|
|
11351
|
+
{ isExample: true, example: "$" }
|
|
11352
|
+
],
|
|
11353
|
+
description: "The example(s) for the bit",
|
|
11354
|
+
format: TagFormat.bitmarkText,
|
|
11355
|
+
nullable: true
|
|
9136
11356
|
}
|
|
9137
11357
|
]
|
|
9138
11358
|
},
|
|
@@ -9157,8 +11377,20 @@ var BITS = {
|
|
|
9157
11377
|
description: "Common quiz tags for multiple response 1 questions"
|
|
9158
11378
|
},
|
|
9159
11379
|
{
|
|
9160
|
-
key: ConfigKey.
|
|
11380
|
+
key: ConfigKey.group_trueFalseResponses,
|
|
9161
11381
|
description: "True/False tags for multiple response 1 questions"
|
|
11382
|
+
},
|
|
11383
|
+
{
|
|
11384
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11385
|
+
key: ConfigKey.property_example,
|
|
11386
|
+
exportJsonKey: [
|
|
11387
|
+
{ "@keyonly": { isExample: true } },
|
|
11388
|
+
{ "@absent": { isExample: true } },
|
|
11389
|
+
{ isExample: true, example: "$" }
|
|
11390
|
+
],
|
|
11391
|
+
description: "The example(s) for the bit",
|
|
11392
|
+
format: TagFormat.bitmarkText,
|
|
11393
|
+
nullable: true
|
|
9162
11394
|
}
|
|
9163
11395
|
]
|
|
9164
11396
|
},
|
|
@@ -9178,12 +11410,24 @@ var BITS = {
|
|
|
9178
11410
|
description: "Common quiz tags for multiple response questions"
|
|
9179
11411
|
},
|
|
9180
11412
|
{
|
|
9181
|
-
key: ConfigKey.
|
|
11413
|
+
key: ConfigKey.group_trueFalseResponses,
|
|
9182
11414
|
description: "True/False tags for multiple response questions"
|
|
9183
|
-
}
|
|
11415
|
+
},
|
|
9184
11416
|
// This is actually for multiple-response-1, but we support it here as well (as many bits are wrong)
|
|
11417
|
+
{
|
|
11418
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11419
|
+
key: ConfigKey.property_example,
|
|
11420
|
+
exportJsonKey: [
|
|
11421
|
+
{ "@keyonly": { isExample: true } },
|
|
11422
|
+
{ "@absent": { isExample: true } },
|
|
11423
|
+
{ isExample: true, example: "$" }
|
|
11424
|
+
],
|
|
11425
|
+
description: "The example(s) for the bit",
|
|
11426
|
+
format: TagFormat.bitmarkText,
|
|
11427
|
+
nullable: true
|
|
11428
|
+
}
|
|
9185
11429
|
],
|
|
9186
|
-
cardSet: CardSetConfigKey.
|
|
11430
|
+
cardSet: CardSetConfigKey.quizResponses
|
|
9187
11431
|
},
|
|
9188
11432
|
[BitType2.coachSelfReflectionMultipleResponse]: {
|
|
9189
11433
|
since: "1.3.0",
|
|
@@ -9196,6 +11440,7 @@ var BITS = {
|
|
|
9196
11440
|
description: "Page bit, used to create pages in articles or books",
|
|
9197
11441
|
tags: [
|
|
9198
11442
|
{
|
|
11443
|
+
exportJsonKey: { title: "$" },
|
|
9199
11444
|
key: ConfigKey.tag_title,
|
|
9200
11445
|
description: "Title of the page, used to display the page title"
|
|
9201
11446
|
},
|
|
@@ -9432,6 +11677,8 @@ var BITS = {
|
|
|
9432
11677
|
},
|
|
9433
11678
|
{
|
|
9434
11679
|
key: ConfigKey.resource_platformIcon,
|
|
11680
|
+
jsonKey: "platformIcon|resource(type=image, key=image)",
|
|
11681
|
+
exportJsonKey: { platformIcon: { type: "image", image: { src: "$" } } },
|
|
9435
11682
|
description: "The platform icon",
|
|
9436
11683
|
chain: [
|
|
9437
11684
|
{
|
|
@@ -9467,6 +11714,8 @@ var BITS = {
|
|
|
9467
11714
|
tags: [
|
|
9468
11715
|
{
|
|
9469
11716
|
key: ConfigKey.resource_platformLogo,
|
|
11717
|
+
jsonKey: "platformLogo|resource(type=image, key=image)",
|
|
11718
|
+
exportJsonKey: { platformLogo: { type: "image", image: { src: "$" } } },
|
|
9470
11719
|
description: "The platform logo",
|
|
9471
11720
|
chain: [
|
|
9472
11721
|
{
|
|
@@ -9555,6 +11804,7 @@ var BITS = {
|
|
|
9555
11804
|
{
|
|
9556
11805
|
key: ConfigKey.resource_platformBackgroundImage,
|
|
9557
11806
|
jsonKey: "platformBackgroundImage|resource(type=image, key=image)",
|
|
11807
|
+
exportJsonKey: { platformBackgroundImage: { type: "image", image: { src: "$" } } },
|
|
9558
11808
|
description: "The platform section chat background image",
|
|
9559
11809
|
chain: [
|
|
9560
11810
|
{
|
|
@@ -9648,6 +11898,7 @@ var BITS = {
|
|
|
9648
11898
|
description: "Review note bit, used to create review notes in articles or books",
|
|
9649
11899
|
tags: [
|
|
9650
11900
|
{
|
|
11901
|
+
exportJsonKey: { title: "$" },
|
|
9651
11902
|
key: ConfigKey.tag_title,
|
|
9652
11903
|
description: "Title of the review note, used to display the note title"
|
|
9653
11904
|
},
|
|
@@ -9666,6 +11917,18 @@ var BITS = {
|
|
|
9666
11917
|
key: ConfigKey.property_resolvedBy,
|
|
9667
11918
|
description: "Resolved by for the review note, used to define who resolved the note",
|
|
9668
11919
|
format: TagFormat.plainText
|
|
11920
|
+
},
|
|
11921
|
+
{
|
|
11922
|
+
// Override inherited @example from group_standardTags: string root example.
|
|
11923
|
+
key: ConfigKey.property_example,
|
|
11924
|
+
exportJsonKey: [
|
|
11925
|
+
{ "@keyonly": { isExample: true, example: "true" } },
|
|
11926
|
+
{ "@absent": { isExample: true, example: "true" } },
|
|
11927
|
+
{ isExample: true, example: "$" }
|
|
11928
|
+
],
|
|
11929
|
+
description: "The example text for the review note bit",
|
|
11930
|
+
format: TagFormat.plainText,
|
|
11931
|
+
nullable: true
|
|
9669
11932
|
}
|
|
9670
11933
|
],
|
|
9671
11934
|
rootExampleType: ExampleType.string
|
|
@@ -9718,11 +11981,13 @@ var BITS = {
|
|
|
9718
11981
|
tags: [
|
|
9719
11982
|
// Not sure if these are actually valid here, but include them as they are in the test bit.
|
|
9720
11983
|
{
|
|
11984
|
+
exportJsonKey: { anchor: "$" },
|
|
9721
11985
|
key: ConfigKey.tag_anchor,
|
|
9722
11986
|
format: TagFormat.plainText,
|
|
9723
11987
|
description: "Anchor for the sample solution, used to link to the solution"
|
|
9724
11988
|
},
|
|
9725
11989
|
{
|
|
11990
|
+
exportJsonKey: { reference: "$" },
|
|
9726
11991
|
key: ConfigKey.tag_reference,
|
|
9727
11992
|
format: TagFormat.plainText,
|
|
9728
11993
|
description: "Reference for the sample solution, used to link to the source of the solution"
|
|
@@ -9738,6 +12003,20 @@ var BITS = {
|
|
|
9738
12003
|
{
|
|
9739
12004
|
key: ConfigKey.group_quizCommon,
|
|
9740
12005
|
description: "Common quiz tags for sequences"
|
|
12006
|
+
},
|
|
12007
|
+
{
|
|
12008
|
+
// Override inherited @example from group_standardTags: this bit has
|
|
12009
|
+
// a boolean root example (rootExampleType: boolean), so bit-level
|
|
12010
|
+
// [@example] writes `example: true` in addition to `isExample: true`.
|
|
12011
|
+
key: ConfigKey.property_example,
|
|
12012
|
+
exportJsonKey: [
|
|
12013
|
+
{ "@keyonly": { isExample: true, example: true } },
|
|
12014
|
+
{ "@absent": { isExample: true, example: true } },
|
|
12015
|
+
{ isExample: true, example: "$" }
|
|
12016
|
+
],
|
|
12017
|
+
description: "The example flag for the bit (boolean)",
|
|
12018
|
+
format: TagFormat.boolean,
|
|
12019
|
+
nullable: true
|
|
9741
12020
|
}
|
|
9742
12021
|
],
|
|
9743
12022
|
cardSet: CardSetConfigKey.elements,
|
|
@@ -9845,6 +12124,7 @@ var BITS = {
|
|
|
9845
12124
|
{
|
|
9846
12125
|
key: ConfigKey.property_ratingLevelStart,
|
|
9847
12126
|
jsonKey: "ratingLevelStart.level",
|
|
12127
|
+
exportJsonKey: { ratingLevelStart: { level: "$" } },
|
|
9848
12128
|
description: "Start level for the rating survey, used to define the lowest rating",
|
|
9849
12129
|
format: TagFormat.number,
|
|
9850
12130
|
chain: [
|
|
@@ -9858,6 +12138,7 @@ var BITS = {
|
|
|
9858
12138
|
{
|
|
9859
12139
|
key: ConfigKey.property_ratingLevelEnd,
|
|
9860
12140
|
jsonKey: "ratingLevelEnd.level",
|
|
12141
|
+
exportJsonKey: { ratingLevelEnd: { level: "$" } },
|
|
9861
12142
|
description: "End level for the rating survey, used to define the highest rating",
|
|
9862
12143
|
format: TagFormat.number,
|
|
9863
12144
|
chain: [
|
|
@@ -10009,14 +12290,8 @@ var BITS = {
|
|
|
10009
12290
|
format: TagFormat.bitmarkText
|
|
10010
12291
|
},
|
|
10011
12292
|
{
|
|
10012
|
-
key: ConfigKey.
|
|
10013
|
-
description: "Background wallpaper for
|
|
10014
|
-
chain: [
|
|
10015
|
-
{
|
|
10016
|
-
key: ConfigKey.group_resourceImageCommon,
|
|
10017
|
-
description: "Common resource image tags for images"
|
|
10018
|
-
}
|
|
10019
|
-
]
|
|
12293
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
12294
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
10020
12295
|
},
|
|
10021
12296
|
{
|
|
10022
12297
|
key: ConfigKey.group_resourceBitTags,
|
|
@@ -10393,12 +12668,48 @@ var BITS = {
|
|
|
10393
12668
|
format: TagFormat.plainText
|
|
10394
12669
|
},
|
|
10395
12670
|
{
|
|
12671
|
+
// PLAN-067 Edit #1: true-false-1's `+` / `-` emit a flat
|
|
12672
|
+
// `{ statement, isCorrect }` at bit root (single-statement bit),
|
|
12673
|
+
// not a `choices[]` array. Format is bitmarkText so the statement
|
|
12674
|
+
// body renders as a ProseMirror tree, matching reference fixtures.
|
|
12675
|
+
exportJsonKey: { statement: "$", isCorrect: true },
|
|
10396
12676
|
key: ConfigKey.tag_true,
|
|
10397
|
-
description: "Tag for the true option in the true/false question"
|
|
12677
|
+
description: "Tag for the true option in the true/false question",
|
|
12678
|
+
format: TagFormat.bitmarkText
|
|
10398
12679
|
},
|
|
10399
12680
|
{
|
|
12681
|
+
exportJsonKey: { statement: "$", isCorrect: false },
|
|
10400
12682
|
key: ConfigKey.tag_false,
|
|
10401
|
-
description: "Tag for the false option in the true/false question"
|
|
12683
|
+
description: "Tag for the false option in the true/false question",
|
|
12684
|
+
format: TagFormat.bitmarkText
|
|
12685
|
+
},
|
|
12686
|
+
{
|
|
12687
|
+
// Override inherited @example from group_standardTags: boolean root
|
|
12688
|
+
// example. Note: the legacy reference parser ties the bare-form
|
|
12689
|
+
// example value to `statement.isCorrect`, but the statement is not
|
|
12690
|
+
// yet emitted when this tag fires at bit-header. The pattern below
|
|
12691
|
+
// emits a literal `true` for bare/synthesized and `$` for valued —
|
|
12692
|
+
// sufficient for `[+...]` (correct) statements which dominate the
|
|
12693
|
+
// fixtures; `[-...]` (incorrect) bits with bare `[@example]` would
|
|
12694
|
+
// need either a runtime extension or an explicit `[@example:false]`.
|
|
12695
|
+
//
|
|
12696
|
+
// Format is `boolean` so `[@example:false]` coerces to JSON `false`
|
|
12697
|
+
// (a natural default that gets stripped in optimised mode, matching
|
|
12698
|
+
// BPG's `rootExampleType: boolean`). PlainText would emit the
|
|
12699
|
+
// STRING `"false"` which doesn't strip.
|
|
12700
|
+
key: ConfigKey.property_example,
|
|
12701
|
+
exportJsonKey: [
|
|
12702
|
+
{ "@keyonly": { isExample: true, example: true } },
|
|
12703
|
+
{ "@absent": { isExample: true, example: true } },
|
|
12704
|
+
// `[@example:false]`: emit `isExample: true` only — `example: false`
|
|
12705
|
+
// is the natural default for boolean, stripped in optimised mode.
|
|
12706
|
+
// Mirrors BPG `removeUnwantedProperties` `ignoreAllFalse: true`.
|
|
12707
|
+
{ "@value=false": { isExample: true } },
|
|
12708
|
+
{ isExample: true, example: "$" }
|
|
12709
|
+
],
|
|
12710
|
+
description: "The example flag for the bit (boolean)",
|
|
12711
|
+
format: TagFormat.boolean,
|
|
12712
|
+
nullable: true
|
|
10402
12713
|
}
|
|
10403
12714
|
],
|
|
10404
12715
|
rootExampleType: ExampleType.boolean
|
|
@@ -10422,6 +12733,18 @@ var BITS = {
|
|
|
10422
12733
|
key: ConfigKey.property_labelFalse,
|
|
10423
12734
|
description: "Label for the false option in the true/false question",
|
|
10424
12735
|
format: TagFormat.plainText
|
|
12736
|
+
},
|
|
12737
|
+
{
|
|
12738
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
12739
|
+
key: ConfigKey.property_example,
|
|
12740
|
+
exportJsonKey: [
|
|
12741
|
+
{ "@keyonly": { isExample: true } },
|
|
12742
|
+
{ "@absent": { isExample: true } },
|
|
12743
|
+
{ isExample: true, example: "$" }
|
|
12744
|
+
],
|
|
12745
|
+
description: "The example(s) for the bit",
|
|
12746
|
+
format: TagFormat.bitmarkText,
|
|
12747
|
+
nullable: true
|
|
10425
12748
|
}
|
|
10426
12749
|
],
|
|
10427
12750
|
cardSet: CardSetConfigKey.statements
|
|
@@ -10611,6 +12934,11 @@ var BITS = {
|
|
|
10611
12934
|
baseBitType: BitType2.vendorStripePricingTable,
|
|
10612
12935
|
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",
|
|
10613
12936
|
tags: [
|
|
12937
|
+
{
|
|
12938
|
+
key: ConfigKey.property_stripePricingTableDescriptiveName,
|
|
12939
|
+
description: "Descriptive name for the Stripe pricing table",
|
|
12940
|
+
format: TagFormat.plainText
|
|
12941
|
+
},
|
|
10614
12942
|
{
|
|
10615
12943
|
key: ConfigKey.property_printOnRequestCustomerId,
|
|
10616
12944
|
description: "Print-on-request customer ID, used to identify the customer for the print-on-request flow",
|
|
@@ -10981,6 +13309,8 @@ var Config = class {
|
|
|
10981
13309
|
maxCount: 1,
|
|
10982
13310
|
chain: tag.chain,
|
|
10983
13311
|
jsonKey: tag.jsonKey,
|
|
13312
|
+
exportJsonKey: tag.exportJsonKey,
|
|
13313
|
+
hasExportJsonKey: tag.hasExportJsonKey,
|
|
10984
13314
|
deprecated: tag.deprecated
|
|
10985
13315
|
});
|
|
10986
13316
|
finalResourceTags[k] = newTag;
|
|
@@ -11085,7 +13415,7 @@ var instance2 = new Config();
|
|
|
11085
13415
|
// src/generated/package_info.ts
|
|
11086
13416
|
var PACKAGE_INFO = {
|
|
11087
13417
|
"name": "@gmb/bitmark-parser-generator",
|
|
11088
|
-
"version": "5.
|
|
13418
|
+
"version": "5.24.0",
|
|
11089
13419
|
"author": "Get More Brain Ltd",
|
|
11090
13420
|
"license": "ISC",
|
|
11091
13421
|
"description": "A bitmark parser and generator using Peggy.js"
|
|
@@ -11679,6 +14009,8 @@ var NodeType = {
|
|
|
11679
14009
|
gmbExternalShopItems: "gmbExternalShopItems",
|
|
11680
14010
|
groupTag: "groupTag",
|
|
11681
14011
|
groupTagValue: "groupTagValue",
|
|
14012
|
+
gUri: "gUri",
|
|
14013
|
+
gUriValue: "gUriValue",
|
|
11682
14014
|
handInAcceptFileType: "handInAcceptFileType",
|
|
11683
14015
|
handInAcceptFileTypeValue: "handInAcceptFileTypeValue",
|
|
11684
14016
|
handInInstruction: "handInInstruction",
|
|
@@ -12021,6 +14353,8 @@ var NodeType = {
|
|
|
12021
14353
|
solution: "solution",
|
|
12022
14354
|
solutions: "solutions",
|
|
12023
14355
|
solutionsValue: "solutionsValue",
|
|
14356
|
+
sourceBB: "sourceBB",
|
|
14357
|
+
sourceBBValue: "sourceBBValue",
|
|
12024
14358
|
sourceDocument: "sourceDocument",
|
|
12025
14359
|
sourceDocumentValue: "sourceDocumentValue",
|
|
12026
14360
|
sourceRL: "sourceRL",
|
|
@@ -12046,6 +14380,8 @@ var NodeType = {
|
|
|
12046
14380
|
stillImageFilmLink: "stillImageFilmLink",
|
|
12047
14381
|
stripePricingTableId: "stripePricingTableId",
|
|
12048
14382
|
stripePricingTableIdValue: "stripePricingTableIdValue",
|
|
14383
|
+
stripePricingTableDescriptiveName: "stripePricingTableDescriptiveName",
|
|
14384
|
+
stripePricingTableDescriptiveNameValue: "stripePricingTableDescriptiveNameValue",
|
|
12049
14385
|
stripePublishableKey: "stripePublishableKey",
|
|
12050
14386
|
stripePublishableKeyValue: "stripePublishableKeyValue",
|
|
12051
14387
|
subject: "subject",
|
|
@@ -24901,6 +27237,7 @@ var Builder = class extends BaseBuilder {
|
|
|
24901
27237
|
isCommented: data.isCommented,
|
|
24902
27238
|
// Properties
|
|
24903
27239
|
id: this.toAstProperty(bitType, ConfigKey.property_id, data.id, options),
|
|
27240
|
+
gUri: this.toAstProperty(bitType, ConfigKey.property_gUri, data.gUri, options),
|
|
24904
27241
|
internalComment: this.toAstProperty(
|
|
24905
27242
|
bitType,
|
|
24906
27243
|
ConfigKey.property_internalComment,
|
|
@@ -25112,6 +27449,7 @@ var Builder = class extends BaseBuilder {
|
|
|
25112
27449
|
data.extractorInternal,
|
|
25113
27450
|
options
|
|
25114
27451
|
),
|
|
27452
|
+
sourceBB: this.normaliseSourceBB(data.sourceBB),
|
|
25115
27453
|
levelCEFRp: this.toAstProperty(
|
|
25116
27454
|
bitType,
|
|
25117
27455
|
ConfigKey.property_levelCEFRp,
|
|
@@ -25469,6 +27807,12 @@ var Builder = class extends BaseBuilder {
|
|
|
25469
27807
|
data.stripePricingTableId,
|
|
25470
27808
|
options
|
|
25471
27809
|
),
|
|
27810
|
+
stripePricingTableDescriptiveName: this.toAstProperty(
|
|
27811
|
+
bitType,
|
|
27812
|
+
ConfigKey.property_stripePricingTableDescriptiveName,
|
|
27813
|
+
data.stripePricingTableDescriptiveName,
|
|
27814
|
+
options
|
|
27815
|
+
),
|
|
25472
27816
|
stripePublishableKey: this.toAstProperty(
|
|
25473
27817
|
bitType,
|
|
25474
27818
|
ConfigKey.property_stripePublishableKey,
|
|
@@ -26132,6 +28476,19 @@ var Builder = class extends BaseBuilder {
|
|
|
26132
28476
|
nodes = Object.values(combinedNodes);
|
|
26133
28477
|
return nodes.length > 0 ? nodes : void 0;
|
|
26134
28478
|
}
|
|
28479
|
+
/**
|
|
28480
|
+
* Normalise a sourceBB input into the AST shape (always number[][]).
|
|
28481
|
+
* Accepts a single 4-number tuple or an array of tuples; returns undefined when empty.
|
|
28482
|
+
*/
|
|
28483
|
+
normaliseSourceBB(data) {
|
|
28484
|
+
if (data == null) return void 0;
|
|
28485
|
+
if (!Array.isArray(data) || data.length === 0) return void 0;
|
|
28486
|
+
const isNested = data.some(Array.isArray);
|
|
28487
|
+
const tuples = (isNested ? data : [data]).filter(
|
|
28488
|
+
(t) => Array.isArray(t) && t.length === 4 && t.every((n) => typeof n === "number")
|
|
28489
|
+
);
|
|
28490
|
+
return tuples.length > 0 ? tuples : void 0;
|
|
28491
|
+
}
|
|
26135
28492
|
/**
|
|
26136
28493
|
* Build groupTag node
|
|
26137
28494
|
*
|
|
@@ -28451,6 +30808,23 @@ var BitmarkGenerator = class extends AstWalkerGenerator {
|
|
|
28451
30808
|
format: TagFormat.plainText
|
|
28452
30809
|
});
|
|
28453
30810
|
}
|
|
30811
|
+
// bitmarkAst -> bits -> bitsValue -> sourceBB
|
|
30812
|
+
enter_sourceBB(node, route) {
|
|
30813
|
+
const parent = this.getParentNode(route);
|
|
30814
|
+
if (parent?.key !== NodeType.bitsValue) return false;
|
|
30815
|
+
const tuples = node.value;
|
|
30816
|
+
if (!Array.isArray(tuples) || tuples.length === 0) return false;
|
|
30817
|
+
this.writeProperty(
|
|
30818
|
+
"sourceBB",
|
|
30819
|
+
tuples.map((t) => t.join(", ")),
|
|
30820
|
+
route,
|
|
30821
|
+
{
|
|
30822
|
+
format: TagFormat.plainText,
|
|
30823
|
+
array: true
|
|
30824
|
+
}
|
|
30825
|
+
);
|
|
30826
|
+
return false;
|
|
30827
|
+
}
|
|
28454
30828
|
// bitmarkAst -> bits -> bitsValue -> questions -> questionsValue -> additionalSolutions -> additionalSolutionsValue
|
|
28455
30829
|
leaf_additionalSolutionsValue(node, route) {
|
|
28456
30830
|
const parent = this.getParentNode(route, 2);
|
|
@@ -30574,6 +32948,16 @@ var JsonGenerator = class extends AstWalkerGenerator {
|
|
|
30574
32948
|
enter_ratingLevelEnd(node, route) {
|
|
30575
32949
|
return this.standardHandler(node, route, NodeType.bitsValue, { array: false });
|
|
30576
32950
|
}
|
|
32951
|
+
// bitmarkAst -> bits -> bitsValue -> sourceBB
|
|
32952
|
+
enter_sourceBB(node, route) {
|
|
32953
|
+
const tuples = node.value;
|
|
32954
|
+
const parent = this.getParentNode(route);
|
|
32955
|
+
if (parent?.key !== NodeType.bitsValue) return false;
|
|
32956
|
+
if (tuples && tuples.length > 0) {
|
|
32957
|
+
this.bitJson.sourceBB = tuples.length === 1 ? tuples[0] : tuples;
|
|
32958
|
+
}
|
|
32959
|
+
return false;
|
|
32960
|
+
}
|
|
30577
32961
|
// bitmarkAst -> bits -> bitsValue -> productId
|
|
30578
32962
|
enter_productId(node, route) {
|
|
30579
32963
|
const productIds = node.value;
|
|
@@ -33656,6 +36040,7 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
33656
36040
|
const cardSetType = bitConfig.cardSet?.configKey;
|
|
33657
36041
|
switch (cardSetType) {
|
|
33658
36042
|
case CardSetConfigKey.flashcard:
|
|
36043
|
+
case CardSetConfigKey.flashcard1:
|
|
33659
36044
|
case CardSetConfigKey.definitionList:
|
|
33660
36045
|
result = parseFlashcardOrDefinitionList(context, bitType, processedCardSet);
|
|
33661
36046
|
break;
|
|
@@ -33669,6 +36054,7 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
33669
36054
|
result = parseFeedback(context, bitType, processedCardSet);
|
|
33670
36055
|
break;
|
|
33671
36056
|
case CardSetConfigKey.quiz:
|
|
36057
|
+
case CardSetConfigKey.quizResponses:
|
|
33672
36058
|
result = parseQuiz(context, bitType, processedCardSet, choicesV1, responsesV1);
|
|
33673
36059
|
break;
|
|
33674
36060
|
case CardSetConfigKey.questions:
|
|
@@ -33695,6 +36081,7 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
33695
36081
|
break;
|
|
33696
36082
|
case CardSetConfigKey.clozeList:
|
|
33697
36083
|
case CardSetConfigKey.exampleBitList:
|
|
36084
|
+
case CardSetConfigKey.pageFooterSections:
|
|
33698
36085
|
case CardSetConfigKey.bookReferenceList:
|
|
33699
36086
|
result = parseCardBits(context, bitType, textFormat, processedCardSet);
|
|
33700
36087
|
break;
|
|
@@ -35252,6 +37639,17 @@ function propertyContentProcessor(context, contentDepth, tagsConfig, content, ta
|
|
|
35252
37639
|
format: TextFormat2.bitmarkText,
|
|
35253
37640
|
location: TextLocation2.tag
|
|
35254
37641
|
});
|
|
37642
|
+
case TagFormat.coordinates:
|
|
37643
|
+
const coordRaw = instance3.unbreakscape(v2, {
|
|
37644
|
+
format: TextFormat2.plainText,
|
|
37645
|
+
location: TextLocation2.tag
|
|
37646
|
+
});
|
|
37647
|
+
if (coordRaw == null) return void 0;
|
|
37648
|
+
const coordParts = coordRaw.split(",").map((p) => instance6.asNumber(p.trim()));
|
|
37649
|
+
if (coordParts.length !== 4 || coordParts.some((n) => n == null)) {
|
|
37650
|
+
return void 0;
|
|
37651
|
+
}
|
|
37652
|
+
return coordParts;
|
|
35255
37653
|
}
|
|
35256
37654
|
}
|
|
35257
37655
|
return instance3.unbreakscape(v2, {
|
|
@@ -35288,6 +37686,8 @@ function propertyContentProcessor(context, contentDepth, tagsConfig, content, ta
|
|
|
35288
37686
|
minCount: 1,
|
|
35289
37687
|
chain: void 0,
|
|
35290
37688
|
jsonKey: void 0,
|
|
37689
|
+
exportJsonKey: void 0,
|
|
37690
|
+
hasExportJsonKey: false,
|
|
35291
37691
|
format: TagFormat.bitmarkText,
|
|
35292
37692
|
values: void 0,
|
|
35293
37693
|
defaultValue: void 0,
|
|
@@ -35298,19 +37698,18 @@ function propertyContentProcessor(context, contentDepth, tagsConfig, content, ta
|
|
|
35298
37698
|
}
|
|
35299
37699
|
|
|
35300
37700
|
// src/parser/bitmark/peg/contentProcessors/ReferenceTagContentProcessor.ts
|
|
35301
|
-
function referenceTagContentProcessor(
|
|
35302
|
-
const { value } = content;
|
|
37701
|
+
function referenceTagContentProcessor(context, _contentDepth, tagsConfig, content, target) {
|
|
37702
|
+
const { value, chain } = content;
|
|
35303
37703
|
const trimmedStringValue = stringUtils.trimmedString(value);
|
|
35304
|
-
|
|
35305
|
-
|
|
35306
|
-
|
|
35307
|
-
|
|
35308
|
-
|
|
35309
|
-
|
|
35310
|
-
|
|
35311
|
-
|
|
35312
|
-
|
|
35313
|
-
});
|
|
37704
|
+
target.reference = instance3.unbreakscape(trimmedStringValue, {
|
|
37705
|
+
format: TextFormat2.bitmarkText,
|
|
37706
|
+
location: TextLocation2.tag
|
|
37707
|
+
});
|
|
37708
|
+
if (Array.isArray(chain) && chain.length > 0) {
|
|
37709
|
+
const sub = context.bitContentProcessor(ContentDepth.Chain, tagsConfig, chain);
|
|
37710
|
+
if (sub.reference != null) {
|
|
37711
|
+
target.referenceEnd = sub.reference;
|
|
37712
|
+
}
|
|
35314
37713
|
}
|
|
35315
37714
|
}
|
|
35316
37715
|
|
|
@@ -35996,7 +38395,6 @@ var BitmarkPegParserProcessor = class {
|
|
|
35996
38395
|
result.markConfig = [];
|
|
35997
38396
|
result.extraProperties = {};
|
|
35998
38397
|
result.internalComments = [];
|
|
35999
|
-
let seenReference = false;
|
|
36000
38398
|
let inFooter = false;
|
|
36001
38399
|
const bodyParts = [];
|
|
36002
38400
|
let bodyTextPart = instance3.EMPTY_STRING;
|
|
@@ -36032,15 +38430,7 @@ var BitmarkPegParserProcessor = class {
|
|
|
36032
38430
|
defaultTagContentProcessor(this.context, contentDepth, tagsConfig, content, result);
|
|
36033
38431
|
break;
|
|
36034
38432
|
case TypeKey.Reference:
|
|
36035
|
-
referenceTagContentProcessor(
|
|
36036
|
-
this.context,
|
|
36037
|
-
contentDepth,
|
|
36038
|
-
tagsConfig,
|
|
36039
|
-
content,
|
|
36040
|
-
result,
|
|
36041
|
-
seenReference
|
|
36042
|
-
);
|
|
36043
|
-
seenReference = true;
|
|
38433
|
+
referenceTagContentProcessor(this.context, contentDepth, tagsConfig, content, result);
|
|
36044
38434
|
break;
|
|
36045
38435
|
case TypeKey.Title:
|
|
36046
38436
|
titleTagContentProcessor(this.context, contentDepth, tagsConfig, content, result);
|
|
@@ -40420,6 +42810,117 @@ var JsonStringGenerator = class {
|
|
|
40420
42810
|
}
|
|
40421
42811
|
};
|
|
40422
42812
|
|
|
42813
|
+
// src/utils/BoundingBox.ts
|
|
42814
|
+
function toBbox(arr) {
|
|
42815
|
+
if (!Array.isArray(arr) || arr.length !== 4) return null;
|
|
42816
|
+
if (!arr.every(Number.isFinite)) return null;
|
|
42817
|
+
return [arr[0], arr[1], arr[2], arr[3]];
|
|
42818
|
+
}
|
|
42819
|
+
function parseSourceBB(sourceBB) {
|
|
42820
|
+
if (sourceBB == null) return [];
|
|
42821
|
+
if (!Array.isArray(sourceBB) || sourceBB.length === 0) return [];
|
|
42822
|
+
const isNested = sourceBB.some(Array.isArray);
|
|
42823
|
+
const candidates = isNested ? sourceBB : [sourceBB];
|
|
42824
|
+
const out = [];
|
|
42825
|
+
for (const candidate of candidates) {
|
|
42826
|
+
const box = toBbox(candidate);
|
|
42827
|
+
if (box) out.push(box);
|
|
42828
|
+
}
|
|
42829
|
+
return out;
|
|
42830
|
+
}
|
|
42831
|
+
function boundingBoxIntersects(a, b) {
|
|
42832
|
+
return a[0] < b[2] && a[2] > b[0] && a[1] < b[3] && a[3] > b[1];
|
|
42833
|
+
}
|
|
42834
|
+
function boundingBoxUnion(boxes) {
|
|
42835
|
+
if (boxes.length === 0) return null;
|
|
42836
|
+
let [x0, y0, x1, y1] = boxes[0];
|
|
42837
|
+
for (let i = 1; i < boxes.length; i++) {
|
|
42838
|
+
const b = boxes[i];
|
|
42839
|
+
if (b[0] < x0) x0 = b[0];
|
|
42840
|
+
if (b[1] < y0) y0 = b[1];
|
|
42841
|
+
if (b[2] > x1) x1 = b[2];
|
|
42842
|
+
if (b[3] > y1) y1 = b[3];
|
|
42843
|
+
}
|
|
42844
|
+
return [x0, y0, x1, y1];
|
|
42845
|
+
}
|
|
42846
|
+
var BoundingBoxIndex = class _BoundingBoxIndex {
|
|
42847
|
+
constructor(entries) {
|
|
42848
|
+
__publicField(this, "_entries");
|
|
42849
|
+
__publicField(this, "bitmarkParser", new BitmarkParserGenerator());
|
|
42850
|
+
this._entries = entries;
|
|
42851
|
+
}
|
|
42852
|
+
/**
|
|
42853
|
+
* Build an index from already-parsed bits. Bits without a parseable
|
|
42854
|
+
* `sourceBB` are dropped. Order of the input is preserved.
|
|
42855
|
+
*
|
|
42856
|
+
* Pass `options.sourceRL` to scope the index to a single source page —
|
|
42857
|
+
* bits whose `sourceRL` doesn't match (or is absent) are excluded.
|
|
42858
|
+
*/
|
|
42859
|
+
static fromBits(wrappers, options) {
|
|
42860
|
+
const filterSourceRL = options?.sourceRL;
|
|
42861
|
+
const entries = [];
|
|
42862
|
+
for (const wrapper of wrappers) {
|
|
42863
|
+
if (!wrapper?.bit) continue;
|
|
42864
|
+
if (filterSourceRL !== void 0 && wrapper.bit.sourceRL !== filterSourceRL) {
|
|
42865
|
+
continue;
|
|
42866
|
+
}
|
|
42867
|
+
const boxes = parseSourceBB(wrapper.bit.sourceBB);
|
|
42868
|
+
if (boxes.length === 0) continue;
|
|
42869
|
+
entries.push({ bit: wrapper.bit, wrapper, boxes });
|
|
42870
|
+
}
|
|
42871
|
+
return new _BoundingBoxIndex(entries);
|
|
42872
|
+
}
|
|
42873
|
+
/** All bits with at least one valid `sourceBB`, in input order. */
|
|
42874
|
+
get entries() {
|
|
42875
|
+
return this._entries;
|
|
42876
|
+
}
|
|
42877
|
+
/**
|
|
42878
|
+
* Bits whose ANY `sourceBB` box intersects `query` (strict overlap —
|
|
42879
|
+
* touching-only edges do NOT count as an intersection).
|
|
42880
|
+
*/
|
|
42881
|
+
intersecting(query) {
|
|
42882
|
+
const matches = [];
|
|
42883
|
+
for (const entry of this._entries) {
|
|
42884
|
+
if (entry.boxes.some((box) => boundingBoxIntersects(query, box))) {
|
|
42885
|
+
matches.push(entry);
|
|
42886
|
+
}
|
|
42887
|
+
}
|
|
42888
|
+
return matches;
|
|
42889
|
+
}
|
|
42890
|
+
/**
|
|
42891
|
+
* Flat list of every individual `sourceBB` box that intersects `query`.
|
|
42892
|
+
* For a multi-box bit, only the boxes that themselves intersected are
|
|
42893
|
+
* returned.
|
|
42894
|
+
*/
|
|
42895
|
+
intersectingBoxes(query) {
|
|
42896
|
+
const matches = [];
|
|
42897
|
+
for (const entry of this._entries) {
|
|
42898
|
+
for (const box of entry.boxes) {
|
|
42899
|
+
if (boundingBoxIntersects(query, box)) matches.push(box);
|
|
42900
|
+
}
|
|
42901
|
+
}
|
|
42902
|
+
return matches;
|
|
42903
|
+
}
|
|
42904
|
+
/**
|
|
42905
|
+
* Smallest axis-aligned box that fully encloses every individual `sourceBB`
|
|
42906
|
+
* box that intersected the query. For a multi-box bit, only the boxes that
|
|
42907
|
+
* themselves intersected contribute to the union — non-intersecting boxes
|
|
42908
|
+
* from the same bit are ignored. Returns `null` if no box matches.
|
|
42909
|
+
*/
|
|
42910
|
+
enclosingBoundingBox(query) {
|
|
42911
|
+
return boundingBoxUnion(this.intersectingBoxes(query));
|
|
42912
|
+
}
|
|
42913
|
+
/** Render selected bits back to bitmark text. Empty input returns `''`. */
|
|
42914
|
+
toBitmark(entries) {
|
|
42915
|
+
if (entries.length === 0) return "";
|
|
42916
|
+
const wrappers = entries.map((e) => e.wrapper);
|
|
42917
|
+
return this.bitmarkParser.convert(wrappers, {
|
|
42918
|
+
outputFormat: Output.bitmark,
|
|
42919
|
+
bitmarkOptions: { prettifyJson: true }
|
|
42920
|
+
});
|
|
42921
|
+
}
|
|
42922
|
+
};
|
|
42923
|
+
|
|
40423
42924
|
// src/index.ts
|
|
40424
42925
|
init();
|
|
40425
42926
|
export {
|
|
@@ -40432,6 +42933,7 @@ export {
|
|
|
40432
42933
|
BitmarkStringGenerator,
|
|
40433
42934
|
BitmarkVersion,
|
|
40434
42935
|
BodyTextFormat,
|
|
42936
|
+
BoundingBoxIndex,
|
|
40435
42937
|
Builder,
|
|
40436
42938
|
CardSetVersion,
|
|
40437
42939
|
InfoFormat,
|