@gmb/bitmark-parser-generator 5.23.0 → 5.25.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 +2897 -167
- package/dist/browser/cjs/index.cjs.map +1 -1
- package/dist/browser/cjs/index.d.cts +195 -1
- package/dist/browser/esm/index.d.ts +195 -1
- package/dist/browser/esm/index.js +2895 -167
- package/dist/browser/esm/index.js.map +1 -1
- package/dist/cli/main.js +3039 -229
- package/dist/cli/main.js.map +1 -1
- package/dist/index.cjs +2924 -171
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +195 -1
- package/dist/index.d.ts +195 -1
- package/dist/index.js +2922 -171
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
|
@@ -230,6 +230,7 @@ var BitType2 = {
|
|
|
230
230
|
dangerAlt: "danger-alt",
|
|
231
231
|
dangerCollapsible: "danger-collapsible",
|
|
232
232
|
definitionList: "definition-list",
|
|
233
|
+
definitionListCollapsible: "definition-list-collapsible",
|
|
233
234
|
definitionTerm: "definition-term",
|
|
234
235
|
deleted: "deleted",
|
|
235
236
|
details: "details",
|
|
@@ -510,6 +511,8 @@ var BitType2 = {
|
|
|
510
511
|
smartStandardArticleNonNormativeCollapsible: "smart-standard-article-non-normative-collapsible",
|
|
511
512
|
smartStandardArticleNormative: "smart-standard-article-normative",
|
|
512
513
|
smartStandardArticleNormativeCollapsible: "smart-standard-article-normative-collapsible",
|
|
514
|
+
smartStandardDefinitionListNonNormative: "smart-standard-definition-list-non-normative",
|
|
515
|
+
smartStandardDefinitionListNormative: "smart-standard-definition-list-normative",
|
|
513
516
|
smartStandardExampleNonNormative: "smart-standard-example-non-normative",
|
|
514
517
|
smartStandardExampleNonNormativeCollapsible: "smart-standard-example-non-normative-collapsible",
|
|
515
518
|
smartStandardExampleNormative: "smart-standard-example-normative",
|
|
@@ -560,6 +563,8 @@ var BitType2 = {
|
|
|
560
563
|
smartStandardTableNormativeCollapsible: "smart-standard-table-normative-collapsible",
|
|
561
564
|
standardArticleNonNormative: "standard-article-non-normative",
|
|
562
565
|
standardArticleNormative: "standard-article-normative",
|
|
566
|
+
standardDefinitionListNonNormative: "standard-definition-list-non-normative",
|
|
567
|
+
standardDefinitionListNormative: "standard-definition-list-normative",
|
|
563
568
|
standardExampleNonNormative: "standard-example-non-normative",
|
|
564
569
|
standardExampleNormative: "standard-example-normative",
|
|
565
570
|
standardImageFigureNonNormative: "standard-image-figure-non-normative",
|
|
@@ -729,10 +734,13 @@ var TextFormat2 = {
|
|
|
729
734
|
import "@ncoderz/superenum";
|
|
730
735
|
var CardSetConfigKey = {
|
|
731
736
|
flashcard: "flashcard",
|
|
737
|
+
flashcard1: "flashcard1",
|
|
732
738
|
definitionList: "definitionList",
|
|
739
|
+
definitionListPlain: "definitionListPlain",
|
|
733
740
|
elements: "elements",
|
|
734
741
|
statements: "statements",
|
|
735
742
|
quiz: "quiz",
|
|
743
|
+
quizResponses: "quizResponses",
|
|
736
744
|
feedback: "feedback",
|
|
737
745
|
questions: "questions",
|
|
738
746
|
matchPairs: "matchPairs",
|
|
@@ -744,6 +752,7 @@ var CardSetConfigKey = {
|
|
|
744
752
|
pronunciationTable: "pronunciationTable",
|
|
745
753
|
botActionResponses: "botActionResponses",
|
|
746
754
|
exampleBitList: "exampleBitList",
|
|
755
|
+
pageFooterSections: "pageFooterSections",
|
|
747
756
|
clozeList: "clozeList",
|
|
748
757
|
ingredients: "ingredients",
|
|
749
758
|
// DEPRECATED - TO BE REMOVED IN THE FUTURE
|
|
@@ -1160,12 +1169,17 @@ var groupKeys = {
|
|
|
1160
1169
|
group_standardAllBits: "group_standardAllBits",
|
|
1161
1170
|
group_standardItemLead: "group_standardItemLead",
|
|
1162
1171
|
group_standardItemLeadInstructionHint: "group_standardItemLeadInstructionHint",
|
|
1172
|
+
group_standardInstructionHint: "group_standardInstructionHint",
|
|
1163
1173
|
group_standardTags: "group_standardTags",
|
|
1174
|
+
group_standardTagsNoItemLead: "group_standardTagsNoItemLead",
|
|
1164
1175
|
group_imageSource: "group_imageSource",
|
|
1165
1176
|
group_technicalTerm: "group_technicalTerm",
|
|
1166
1177
|
group_person: "group_person",
|
|
1167
1178
|
group_gap: "group_gap",
|
|
1168
1179
|
group_trueFalse: "group_trueFalse",
|
|
1180
|
+
group_trueFalseInlineHighlight: "group_trueFalseInlineHighlight",
|
|
1181
|
+
group_trueFalseInlineSelect: "group_trueFalseInlineSelect",
|
|
1182
|
+
group_trueFalseResponses: "group_trueFalseResponses",
|
|
1169
1183
|
group_markConfig: "group_markConfig",
|
|
1170
1184
|
group_mark: "group_mark",
|
|
1171
1185
|
group_bookCommon: "group_bookCommon",
|
|
@@ -1173,14 +1187,18 @@ var groupKeys = {
|
|
|
1173
1187
|
group_advertisingCommon: "group_advertisingCommon",
|
|
1174
1188
|
group_platformStylesCommon: "group_platformStylesCommon",
|
|
1175
1189
|
group_quizCommon: "group_quizCommon",
|
|
1190
|
+
group_backgroundWallpaper: "group_backgroundWallpaper",
|
|
1191
|
+
group_imageNoZoom: "group_imageNoZoom",
|
|
1176
1192
|
group_resourceBitTags: "group_resourceBitTags",
|
|
1177
1193
|
group_resourceCommon: "group_resourceCommon",
|
|
1178
1194
|
group_resourceImageCommon: "group_resourceImageCommon",
|
|
1195
|
+
group_resourceImageCommonNoZoom: "group_resourceImageCommonNoZoom",
|
|
1179
1196
|
group_resourceAudioCommon: "group_resourceAudioCommon",
|
|
1180
1197
|
group_resourceVideoCommon: "group_resourceVideoCommon",
|
|
1181
1198
|
group_resourceIcon: "group_resourceIcon",
|
|
1182
1199
|
// Alias for image
|
|
1183
1200
|
group_resourceImage: "group_resourceImage",
|
|
1201
|
+
group_resourceImageNoZoom: "group_resourceImageNoZoom",
|
|
1184
1202
|
group_resourceImageEmbed: "group_resourceImageEmbed",
|
|
1185
1203
|
group_resourceImageLink: "group_resourceImageLink",
|
|
1186
1204
|
group_resourceImageResponsive: "group_resourceImageResponsive",
|
|
@@ -1332,6 +1350,7 @@ var propertyKeys = {
|
|
|
1332
1350
|
property_enforceUpdateOverUserInput: "@enforceUpdateOverUserInput",
|
|
1333
1351
|
property_extractorExtractionTimestamp: "@extractorExtractionTimestamp",
|
|
1334
1352
|
property_isCaseSensitive: "@isCaseSensitive",
|
|
1353
|
+
property_isCollapsible: "@isCollapsible",
|
|
1335
1354
|
property_isInfoOnly: "@isInfoOnly",
|
|
1336
1355
|
property_isPublic: "@isPublic",
|
|
1337
1356
|
property_isTemplate: "@isTemplate",
|
|
@@ -1457,6 +1476,7 @@ var propertyKeys = {
|
|
|
1457
1476
|
property_src4x: "@src4x",
|
|
1458
1477
|
property_srcAlt: "@srcAlt",
|
|
1459
1478
|
property_stripePricingTableId: "@stripePricingTableId",
|
|
1479
|
+
property_stripePricingTableDescriptiveName: "@stripePricingTableDescriptiveName",
|
|
1460
1480
|
property_stripePublishableKey: "@stripePublishableKey",
|
|
1461
1481
|
property_subject: "@subject",
|
|
1462
1482
|
property_subtype: "@subtype",
|
|
@@ -2208,7 +2228,7 @@ var CARDSETS = {
|
|
|
2208
2228
|
variants: [
|
|
2209
2229
|
{
|
|
2210
2230
|
jsonKey: "question.text",
|
|
2211
|
-
exportJsonKey: { question: { text: "$" } },
|
|
2231
|
+
exportJsonKey: [{ "@absent": { question: {} } }, { question: { text: "$" } }],
|
|
2212
2232
|
tags: [
|
|
2213
2233
|
{
|
|
2214
2234
|
key: ConfigKey.group_standardTags,
|
|
@@ -2224,6 +2244,136 @@ var CARDSETS = {
|
|
|
2224
2244
|
description: "Icon resource for the flashcard.",
|
|
2225
2245
|
jsonKey: "question.icon|resource(type=image, key=image)",
|
|
2226
2246
|
exportJsonKey: { question: { icon: { type: "image", image: { src: "$" } } } }
|
|
2247
|
+
},
|
|
2248
|
+
{
|
|
2249
|
+
key: ConfigKey.property_example,
|
|
2250
|
+
exportJsonKey: [
|
|
2251
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2252
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2253
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2254
|
+
],
|
|
2255
|
+
description: "Example marker for the flashcard question.",
|
|
2256
|
+
format: TagFormat.bitmarkText,
|
|
2257
|
+
nullable: true
|
|
2258
|
+
}
|
|
2259
|
+
]
|
|
2260
|
+
}
|
|
2261
|
+
]
|
|
2262
|
+
},
|
|
2263
|
+
{
|
|
2264
|
+
name: "answer",
|
|
2265
|
+
variants: [
|
|
2266
|
+
{
|
|
2267
|
+
jsonKey: "answer.text",
|
|
2268
|
+
exportJsonKey: [{ "@absent": { answer: {} } }, { answer: { text: "$" } }],
|
|
2269
|
+
tags: [
|
|
2270
|
+
{
|
|
2271
|
+
key: ConfigKey.group_standardTags,
|
|
2272
|
+
description: "Standard tags for the flashcard."
|
|
2273
|
+
},
|
|
2274
|
+
{
|
|
2275
|
+
exportJsonKey: { title: "$" },
|
|
2276
|
+
key: ConfigKey.tag_title,
|
|
2277
|
+
description: "Title of the flashcard."
|
|
2278
|
+
},
|
|
2279
|
+
{
|
|
2280
|
+
key: ConfigKey.group_resourceIcon,
|
|
2281
|
+
description: "Icon resource for the flashcard.",
|
|
2282
|
+
jsonKey: "answer.icon|resource(type=image, key=image)",
|
|
2283
|
+
exportJsonKey: { answer: { icon: { type: "image", image: { src: "$" } } } }
|
|
2284
|
+
},
|
|
2285
|
+
{
|
|
2286
|
+
key: ConfigKey.property_example,
|
|
2287
|
+
exportJsonKey: [
|
|
2288
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2289
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2290
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2291
|
+
],
|
|
2292
|
+
description: "Example marker for the flashcard answer.",
|
|
2293
|
+
format: TagFormat.bitmarkText,
|
|
2294
|
+
nullable: true
|
|
2295
|
+
}
|
|
2296
|
+
]
|
|
2297
|
+
},
|
|
2298
|
+
{
|
|
2299
|
+
jsonKey: "alternativeAnswers[].text",
|
|
2300
|
+
exportJsonKey: { alternativeAnswers: [{ text: "$" }] },
|
|
2301
|
+
tags: [
|
|
2302
|
+
{
|
|
2303
|
+
key: ConfigKey.group_standardTags,
|
|
2304
|
+
description: "Standard tags for the flashcard."
|
|
2305
|
+
},
|
|
2306
|
+
{
|
|
2307
|
+
exportJsonKey: { title: "$" },
|
|
2308
|
+
key: ConfigKey.tag_title,
|
|
2309
|
+
description: "Title of the flashcard."
|
|
2310
|
+
},
|
|
2311
|
+
{
|
|
2312
|
+
key: ConfigKey.group_resourceIcon,
|
|
2313
|
+
description: "Icon resource for the flashcard.",
|
|
2314
|
+
jsonKey: "alternativeAnswers[].icon|resource(type=image, key=image)",
|
|
2315
|
+
exportJsonKey: {
|
|
2316
|
+
alternativeAnswers: [{ icon: { type: "image", image: { src: "$" } } }]
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
],
|
|
2320
|
+
repeatCount: Count.infinity
|
|
2321
|
+
}
|
|
2322
|
+
]
|
|
2323
|
+
}
|
|
2324
|
+
]
|
|
2325
|
+
},
|
|
2326
|
+
//
|
|
2327
|
+
// flashcard1 — single-card variant of flashcard. Same shape, but capped
|
|
2328
|
+
// at one card via `sections.default.maxCount = 1` (PLAN-085). Used by
|
|
2329
|
+
// the `flashcard-1` bit type; the multi-card `flashcard` and
|
|
2330
|
+
// `q-and-a-card` bit types continue to use the unbounded `flashcard`
|
|
2331
|
+
// cardset.
|
|
2332
|
+
//
|
|
2333
|
+
[CardSetConfigKey.flashcard1]: {
|
|
2334
|
+
jsonKey: "cards",
|
|
2335
|
+
exportJsonKey: { cards: "$" },
|
|
2336
|
+
sections: {
|
|
2337
|
+
default: {
|
|
2338
|
+
jsonKey: "cards",
|
|
2339
|
+
exportJsonKey: { cards: "$" },
|
|
2340
|
+
isDefault: true,
|
|
2341
|
+
maxCount: 1
|
|
2342
|
+
}
|
|
2343
|
+
},
|
|
2344
|
+
sides: [
|
|
2345
|
+
{
|
|
2346
|
+
name: "question",
|
|
2347
|
+
variants: [
|
|
2348
|
+
{
|
|
2349
|
+
jsonKey: "question.text",
|
|
2350
|
+
exportJsonKey: [{ "@absent": { question: {} } }, { question: { text: "$" } }],
|
|
2351
|
+
tags: [
|
|
2352
|
+
{
|
|
2353
|
+
key: ConfigKey.group_standardTags,
|
|
2354
|
+
description: "Standard tags for the flashcard."
|
|
2355
|
+
},
|
|
2356
|
+
{
|
|
2357
|
+
exportJsonKey: { title: "$" },
|
|
2358
|
+
key: ConfigKey.tag_title,
|
|
2359
|
+
description: "Title of the flashcard."
|
|
2360
|
+
},
|
|
2361
|
+
{
|
|
2362
|
+
key: ConfigKey.group_resourceIcon,
|
|
2363
|
+
description: "Icon resource for the flashcard.",
|
|
2364
|
+
jsonKey: "question.icon|resource(type=image, key=image)",
|
|
2365
|
+
exportJsonKey: { question: { icon: { type: "image", image: { src: "$" } } } }
|
|
2366
|
+
},
|
|
2367
|
+
{
|
|
2368
|
+
key: ConfigKey.property_example,
|
|
2369
|
+
exportJsonKey: [
|
|
2370
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2371
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2372
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2373
|
+
],
|
|
2374
|
+
description: "Example marker for the flashcard question.",
|
|
2375
|
+
format: TagFormat.bitmarkText,
|
|
2376
|
+
nullable: true
|
|
2227
2377
|
}
|
|
2228
2378
|
]
|
|
2229
2379
|
}
|
|
@@ -2234,7 +2384,7 @@ var CARDSETS = {
|
|
|
2234
2384
|
variants: [
|
|
2235
2385
|
{
|
|
2236
2386
|
jsonKey: "answer.text",
|
|
2237
|
-
exportJsonKey: { answer: { text: "$" } },
|
|
2387
|
+
exportJsonKey: [{ "@absent": { answer: {} } }, { answer: { text: "$" } }],
|
|
2238
2388
|
tags: [
|
|
2239
2389
|
{
|
|
2240
2390
|
key: ConfigKey.group_standardTags,
|
|
@@ -2250,6 +2400,17 @@ var CARDSETS = {
|
|
|
2250
2400
|
description: "Icon resource for the flashcard.",
|
|
2251
2401
|
jsonKey: "answer.icon|resource(type=image, key=image)",
|
|
2252
2402
|
exportJsonKey: { answer: { icon: { type: "image", image: { src: "$" } } } }
|
|
2403
|
+
},
|
|
2404
|
+
{
|
|
2405
|
+
key: ConfigKey.property_example,
|
|
2406
|
+
exportJsonKey: [
|
|
2407
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2408
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2409
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2410
|
+
],
|
|
2411
|
+
description: "Example marker for the flashcard answer.",
|
|
2412
|
+
format: TagFormat.bitmarkText,
|
|
2413
|
+
nullable: true
|
|
2253
2414
|
}
|
|
2254
2415
|
]
|
|
2255
2416
|
},
|
|
@@ -2293,7 +2454,7 @@ var CARDSETS = {
|
|
|
2293
2454
|
variants: [
|
|
2294
2455
|
{
|
|
2295
2456
|
jsonKey: "term.text",
|
|
2296
|
-
exportJsonKey: { term: { text: "$" } },
|
|
2457
|
+
exportJsonKey: [{ "@absent": { term: {} } }, { term: { text: "$" } }],
|
|
2297
2458
|
tags: [
|
|
2298
2459
|
{
|
|
2299
2460
|
key: ConfigKey.group_standardTags,
|
|
@@ -2312,6 +2473,17 @@ var CARDSETS = {
|
|
|
2312
2473
|
format: TagFormat.plainText,
|
|
2313
2474
|
jsonKey: "term.icon|resource(type=image, key=image)",
|
|
2314
2475
|
exportJsonKey: { term: { icon: { type: "image", image: { src: "$" } } } }
|
|
2476
|
+
},
|
|
2477
|
+
{
|
|
2478
|
+
key: ConfigKey.property_example,
|
|
2479
|
+
exportJsonKey: [
|
|
2480
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2481
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2482
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2483
|
+
],
|
|
2484
|
+
description: "Example marker for the definition term.",
|
|
2485
|
+
format: TagFormat.bitmarkText,
|
|
2486
|
+
nullable: true
|
|
2315
2487
|
}
|
|
2316
2488
|
]
|
|
2317
2489
|
}
|
|
@@ -2322,7 +2494,7 @@ var CARDSETS = {
|
|
|
2322
2494
|
variants: [
|
|
2323
2495
|
{
|
|
2324
2496
|
jsonKey: "definition.text",
|
|
2325
|
-
exportJsonKey: { definition: { text: "$" } },
|
|
2497
|
+
exportJsonKey: [{ "@absent": { definition: {} } }, { definition: { text: "$" } }],
|
|
2326
2498
|
tags: [
|
|
2327
2499
|
{
|
|
2328
2500
|
key: ConfigKey.group_standardTags,
|
|
@@ -2340,6 +2512,17 @@ var CARDSETS = {
|
|
|
2340
2512
|
description: "Icon resource for the definition.",
|
|
2341
2513
|
jsonKey: "definition.icon|resource(type=image, key=image)",
|
|
2342
2514
|
exportJsonKey: { definition: { icon: { type: "image", image: { src: "$" } } } }
|
|
2515
|
+
},
|
|
2516
|
+
{
|
|
2517
|
+
key: ConfigKey.property_example,
|
|
2518
|
+
exportJsonKey: [
|
|
2519
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2520
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2521
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2522
|
+
],
|
|
2523
|
+
description: "Example marker for the definition.",
|
|
2524
|
+
format: TagFormat.bitmarkText,
|
|
2525
|
+
nullable: true
|
|
2343
2526
|
}
|
|
2344
2527
|
]
|
|
2345
2528
|
},
|
|
@@ -2372,6 +2555,126 @@ var CARDSETS = {
|
|
|
2372
2555
|
]
|
|
2373
2556
|
},
|
|
2374
2557
|
//
|
|
2558
|
+
// definition-list-plain
|
|
2559
|
+
//
|
|
2560
|
+
// Same shape as `definitionList`, but every variant body is rendered as
|
|
2561
|
+
// plain text (string), not bitmark+ AST. Used by
|
|
2562
|
+
// `meta-search-default-terms` / `meta-search-default-topics`, which need
|
|
2563
|
+
// term/definition text emitted verbatim instead of as a ProseMirror tree.
|
|
2564
|
+
//
|
|
2565
|
+
[CardSetConfigKey.definitionListPlain]: {
|
|
2566
|
+
jsonKey: "definitions",
|
|
2567
|
+
exportJsonKey: { definitions: "$" },
|
|
2568
|
+
sides: [
|
|
2569
|
+
{
|
|
2570
|
+
name: "term",
|
|
2571
|
+
variants: [
|
|
2572
|
+
{
|
|
2573
|
+
jsonKey: "term.text",
|
|
2574
|
+
exportJsonKey: [{ "@absent": { term: {} } }, { term: { text: "$" } }],
|
|
2575
|
+
format: TextFormat2.plainText,
|
|
2576
|
+
tags: [
|
|
2577
|
+
{
|
|
2578
|
+
key: ConfigKey.group_standardTags,
|
|
2579
|
+
description: "Standard tags for the definition."
|
|
2580
|
+
},
|
|
2581
|
+
{
|
|
2582
|
+
key: ConfigKey.tag_title,
|
|
2583
|
+
description: "Title of the definition.",
|
|
2584
|
+
format: TagFormat.plainText,
|
|
2585
|
+
jsonKey: "^heading.forKeys",
|
|
2586
|
+
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2587
|
+
},
|
|
2588
|
+
{
|
|
2589
|
+
key: ConfigKey.group_resourceIcon,
|
|
2590
|
+
description: "Icon resource for the definition.",
|
|
2591
|
+
format: TagFormat.plainText,
|
|
2592
|
+
jsonKey: "term.icon|resource(type=image, key=image)",
|
|
2593
|
+
exportJsonKey: { term: { icon: { type: "image", image: { src: "$" } } } }
|
|
2594
|
+
},
|
|
2595
|
+
{
|
|
2596
|
+
key: ConfigKey.property_example,
|
|
2597
|
+
exportJsonKey: [
|
|
2598
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2599
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2600
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2601
|
+
],
|
|
2602
|
+
description: "Example marker for the definition term.",
|
|
2603
|
+
format: TagFormat.bitmarkText,
|
|
2604
|
+
nullable: true
|
|
2605
|
+
}
|
|
2606
|
+
]
|
|
2607
|
+
}
|
|
2608
|
+
]
|
|
2609
|
+
},
|
|
2610
|
+
{
|
|
2611
|
+
name: "definition",
|
|
2612
|
+
variants: [
|
|
2613
|
+
{
|
|
2614
|
+
jsonKey: "definition.text",
|
|
2615
|
+
exportJsonKey: [{ "@absent": { definition: {} } }, { definition: { text: "$" } }],
|
|
2616
|
+
format: TextFormat2.plainText,
|
|
2617
|
+
tags: [
|
|
2618
|
+
{
|
|
2619
|
+
key: ConfigKey.group_standardTags,
|
|
2620
|
+
description: "Standard tags for the definition."
|
|
2621
|
+
},
|
|
2622
|
+
{
|
|
2623
|
+
key: ConfigKey.tag_title,
|
|
2624
|
+
description: "Title of the definition.",
|
|
2625
|
+
format: TagFormat.plainText,
|
|
2626
|
+
jsonKey: "^heading.forValues",
|
|
2627
|
+
exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
|
|
2628
|
+
},
|
|
2629
|
+
{
|
|
2630
|
+
key: ConfigKey.group_resourceIcon,
|
|
2631
|
+
description: "Icon resource for the definition.",
|
|
2632
|
+
jsonKey: "definition.icon|resource(type=image, key=image)",
|
|
2633
|
+
exportJsonKey: { definition: { icon: { type: "image", image: { src: "$" } } } }
|
|
2634
|
+
},
|
|
2635
|
+
{
|
|
2636
|
+
key: ConfigKey.property_example,
|
|
2637
|
+
exportJsonKey: [
|
|
2638
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2639
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2640
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2641
|
+
],
|
|
2642
|
+
description: "Example marker for the definition.",
|
|
2643
|
+
format: TagFormat.bitmarkText,
|
|
2644
|
+
nullable: true
|
|
2645
|
+
}
|
|
2646
|
+
]
|
|
2647
|
+
},
|
|
2648
|
+
{
|
|
2649
|
+
jsonKey: "alternativeDefinitions[].text",
|
|
2650
|
+
exportJsonKey: { alternativeDefinitions: [{ text: "$" }] },
|
|
2651
|
+
format: TextFormat2.plainText,
|
|
2652
|
+
tags: [
|
|
2653
|
+
{
|
|
2654
|
+
key: ConfigKey.group_standardTags,
|
|
2655
|
+
description: "Standard tags for the definition."
|
|
2656
|
+
},
|
|
2657
|
+
{
|
|
2658
|
+
exportJsonKey: { title: "$" },
|
|
2659
|
+
key: ConfigKey.tag_title,
|
|
2660
|
+
description: "Title of the definition."
|
|
2661
|
+
},
|
|
2662
|
+
{
|
|
2663
|
+
key: ConfigKey.group_resourceIcon,
|
|
2664
|
+
description: "Icon resource for the definition.",
|
|
2665
|
+
jsonKey: "alternativeDefinitions[].icon|resource(type=image, key=image)",
|
|
2666
|
+
exportJsonKey: {
|
|
2667
|
+
alternativeDefinitions: [{ icon: { type: "image", image: { src: "$" } } }]
|
|
2668
|
+
}
|
|
2669
|
+
}
|
|
2670
|
+
],
|
|
2671
|
+
repeatCount: Count.infinity
|
|
2672
|
+
}
|
|
2673
|
+
]
|
|
2674
|
+
}
|
|
2675
|
+
]
|
|
2676
|
+
},
|
|
2677
|
+
//
|
|
2375
2678
|
// match-pairs
|
|
2376
2679
|
//
|
|
2377
2680
|
[CardSetConfigKey.matchPairs]: {
|
|
@@ -2384,11 +2687,51 @@ var CARDSETS = {
|
|
|
2384
2687
|
{
|
|
2385
2688
|
jsonKey: "key",
|
|
2386
2689
|
exportJsonKey: { key: "$" },
|
|
2690
|
+
format: TextFormat2.plainText,
|
|
2387
2691
|
tags: [
|
|
2388
2692
|
{
|
|
2389
2693
|
key: ConfigKey.group_standardTags,
|
|
2390
2694
|
description: "Standard tags for the match pair."
|
|
2391
2695
|
},
|
|
2696
|
+
{
|
|
2697
|
+
// Pair-level example: emit `isExample` alongside `example`
|
|
2698
|
+
// (matches OLD parser's per-pair allow-list behaviour).
|
|
2699
|
+
//
|
|
2700
|
+
// PLAN-074: a valued cascade source (`[@example:V]` anywhere
|
|
2701
|
+
// in the cardset) fills each pair's `example` with `V`
|
|
2702
|
+
// once per pair from the keys-side cascade fire (single
|
|
2703
|
+
// parsed_variant per pair — no per-value duplication).
|
|
2704
|
+
//
|
|
2705
|
+
// PLAN-076 NOTE: matchPairs (TAG 415) KEEPS `example: '$'`
|
|
2706
|
+
// at the pair-object level. BPG `parseMatchPairs`
|
|
2707
|
+
// (`CardContentProcessor.ts:714-723`) emits ONE example
|
|
2708
|
+
// per PAIR (the `exampleCard` accumulator), placed at the
|
|
2709
|
+
// pair object. Unlike matchMatrix (per-cell example),
|
|
2710
|
+
// matchPairs has no nested per-cell layer, so the pair-key
|
|
2711
|
+
// `[@example:V]` must double-emit as the visible field.
|
|
2712
|
+
// Confirmed via `chaining` fixture: `match-solution-grouped`
|
|
2713
|
+
// expects `example: "packen"` at pair-object level from
|
|
2714
|
+
// `die Koffer[%1][@example:packen]`. Original PLAN-076
|
|
2715
|
+
// draft applied to both keys-side tags; the matchPairs
|
|
2716
|
+
// half was reverted after fixture parity testing.
|
|
2717
|
+
key: ConfigKey.property_example,
|
|
2718
|
+
exportJsonKey: [
|
|
2719
|
+
{ "@keyonly": { isExample: true, "@bit": { isExample: true } } },
|
|
2720
|
+
{
|
|
2721
|
+
predicates: ["@absent", { $cascade: "*" }],
|
|
2722
|
+
rule: {
|
|
2723
|
+
isExample: true,
|
|
2724
|
+
example: "$cascade",
|
|
2725
|
+
"@bit": { isExample: true }
|
|
2726
|
+
}
|
|
2727
|
+
},
|
|
2728
|
+
{ "@absent": { isExample: true } },
|
|
2729
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2730
|
+
],
|
|
2731
|
+
description: "Example marker / value on the match pair.",
|
|
2732
|
+
format: TagFormat.bitmarkText,
|
|
2733
|
+
nullable: true
|
|
2734
|
+
},
|
|
2392
2735
|
{
|
|
2393
2736
|
key: ConfigKey.tag_title,
|
|
2394
2737
|
description: "Title of the match pair.",
|
|
@@ -2397,9 +2740,19 @@ var CARDSETS = {
|
|
|
2397
2740
|
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2398
2741
|
},
|
|
2399
2742
|
{
|
|
2743
|
+
// PLAN-084: gate the key-side `@absent → $ancestor` cascade
|
|
2744
|
+
// synth with `@variantLacksTag=isCaseSensitive` so the rule
|
|
2745
|
+
// only fires when NO variant in the active card explicitly
|
|
2746
|
+
// carries `[@isCaseSensitive]`. When a value-side variant
|
|
2747
|
+
// carries the tag (e.g. `[@isCaseSensitive:false]`), the
|
|
2748
|
+
// synth is skipped here; the value-side explicit fire owns
|
|
2749
|
+
// the pair-level emission.
|
|
2400
2750
|
key: ConfigKey.property_isCaseSensitive,
|
|
2401
2751
|
exportJsonKey: [
|
|
2402
|
-
{
|
|
2752
|
+
{
|
|
2753
|
+
predicates: ["@absent", { "@variantLacksTag": "@isCaseSensitive" }],
|
|
2754
|
+
rule: { isCaseSensitive: "$ancestor" }
|
|
2755
|
+
},
|
|
2403
2756
|
{ isCaseSensitive: "$" }
|
|
2404
2757
|
],
|
|
2405
2758
|
description: "Property to indicate if the match is case sensitive.",
|
|
@@ -2428,10 +2781,85 @@ var CARDSETS = {
|
|
|
2428
2781
|
{
|
|
2429
2782
|
jsonKey: "values[]",
|
|
2430
2783
|
exportJsonKey: { values: ["$"] },
|
|
2784
|
+
format: TextFormat2.plainText,
|
|
2431
2785
|
tags: [
|
|
2432
2786
|
{
|
|
2433
|
-
|
|
2434
|
-
|
|
2787
|
+
// PLAN-084: value-side excludes item/lead/pageNumber/marginNumber.
|
|
2788
|
+
// BPG `parseMatchPairs` does `delete tags.item; delete tags.lead;`
|
|
2789
|
+
// for sideIdx > 0; the schema-side equivalent is to use a
|
|
2790
|
+
// group_standardTags variant that omits group_standardItemLead.
|
|
2791
|
+
key: ConfigKey.group_standardTagsNoItemLead,
|
|
2792
|
+
description: "Standard tags for the match pair (values side, no item/lead)."
|
|
2793
|
+
},
|
|
2794
|
+
{
|
|
2795
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.6: cascade-fired
|
|
2796
|
+
// `@example` from the bit header fills each pair's
|
|
2797
|
+
// `example` with the pair's first value (mirrors BPG's
|
|
2798
|
+
// `fillStringExample(pairs, __defaultExample=values[0])`).
|
|
2799
|
+
//
|
|
2800
|
+
// PLAN-074: the cascade-source-VALUE branch is handled by
|
|
2801
|
+
// TAG 415 (keys side) which fires once per pair — keeping
|
|
2802
|
+
// it here would emit `example` twice per pair (one per
|
|
2803
|
+
// values-side parsed_variant) and merge them into a
|
|
2804
|
+
// multi-paragraph array.
|
|
2805
|
+
//
|
|
2806
|
+
// PLAN-075: bare `$parent` reads the parent variant fire's
|
|
2807
|
+
// source `$` value (the current `++`-iteration's value
|
|
2808
|
+
// text). For single-value pairs this matches the old
|
|
2809
|
+
// `$parent.values[0]`; for multi-value pairs with
|
|
2810
|
+
// `[@example]` attached to a non-first value, it correctly
|
|
2811
|
+
// resolves to that value.
|
|
2812
|
+
//
|
|
2813
|
+
// PLAN-077: dual `[@absent, { '$cascade': '*' }]` rule
|
|
2814
|
+
// routes pair-key `[@example:V]` (a per-pair cascade
|
|
2815
|
+
// source, bound via per-card CascadeCounters scope) and
|
|
2816
|
+
// bit-header `[@example:V]` (cardset cascade) into the
|
|
2817
|
+
// pair-level `example` via `$cascade`. The aggregator in
|
|
2818
|
+
// `populate_variants` fires this rule ONCE per pair (BPG
|
|
2819
|
+
// `parseMatchPairs` `exampleCard` precedence), avoiding
|
|
2820
|
+
// per-iter pollution.
|
|
2821
|
+
key: ConfigKey.property_example,
|
|
2822
|
+
exportJsonKey: [
|
|
2823
|
+
// PLAN-084: bare `[@example]` on a values-side variant fires
|
|
2824
|
+
// once per pair (first-wins, mirrors BPG `parseMatchPairs`
|
|
2825
|
+
// `exampleCard` + `pushDownTree` set-if-null semantic).
|
|
2826
|
+
// `maxEmits: 1` enforced inside the per-pair cascade-counter
|
|
2827
|
+
// scope opened by `build_card_item`.
|
|
2828
|
+
{
|
|
2829
|
+
predicates: ["@keyonly"],
|
|
2830
|
+
maxEmits: 1,
|
|
2831
|
+
rule: {
|
|
2832
|
+
isExample: true,
|
|
2833
|
+
example: "$parent",
|
|
2834
|
+
"@bit": { isExample: true }
|
|
2835
|
+
}
|
|
2836
|
+
},
|
|
2837
|
+
{
|
|
2838
|
+
predicates: ["@absent", { $cascade: "*" }],
|
|
2839
|
+
rule: {
|
|
2840
|
+
isExample: true,
|
|
2841
|
+
example: "$cascade",
|
|
2842
|
+
"@bit": { isExample: true }
|
|
2843
|
+
}
|
|
2844
|
+
},
|
|
2845
|
+
{
|
|
2846
|
+
"@absent": {
|
|
2847
|
+
isExample: true,
|
|
2848
|
+
example: "$parent",
|
|
2849
|
+
"@bit": { isExample: true }
|
|
2850
|
+
}
|
|
2851
|
+
},
|
|
2852
|
+
// PLAN-084: same cap applies to the explicit-value `[@example:V]`
|
|
2853
|
+
// form so per-`++`-iter values-side fires also first-win.
|
|
2854
|
+
{
|
|
2855
|
+
predicates: [],
|
|
2856
|
+
maxEmits: 1,
|
|
2857
|
+
rule: { isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2858
|
+
}
|
|
2859
|
+
],
|
|
2860
|
+
description: "Example marker / value on the match pair (values side).",
|
|
2861
|
+
format: TagFormat.bitmarkText,
|
|
2862
|
+
nullable: true
|
|
2435
2863
|
},
|
|
2436
2864
|
{
|
|
2437
2865
|
key: ConfigKey.tag_title,
|
|
@@ -2441,9 +2869,13 @@ var CARDSETS = {
|
|
|
2441
2869
|
exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
|
|
2442
2870
|
},
|
|
2443
2871
|
{
|
|
2872
|
+
// PLAN-084: symmetric @variantLacksTag gating with the key-side.
|
|
2444
2873
|
key: ConfigKey.property_isCaseSensitive,
|
|
2445
2874
|
exportJsonKey: [
|
|
2446
|
-
{
|
|
2875
|
+
{
|
|
2876
|
+
predicates: ["@absent", { "@variantLacksTag": "@isCaseSensitive" }],
|
|
2877
|
+
rule: { isCaseSensitive: "$ancestor" }
|
|
2878
|
+
},
|
|
2447
2879
|
{ isCaseSensitive: "$" }
|
|
2448
2880
|
],
|
|
2449
2881
|
description: "Property to indicate if the match is case sensitive.",
|
|
@@ -2469,6 +2901,7 @@ var CARDSETS = {
|
|
|
2469
2901
|
{
|
|
2470
2902
|
jsonKey: "key",
|
|
2471
2903
|
exportJsonKey: { key: "$" },
|
|
2904
|
+
format: TextFormat2.plainText,
|
|
2472
2905
|
tags: [
|
|
2473
2906
|
{
|
|
2474
2907
|
key: ConfigKey.group_standardTags,
|
|
@@ -2498,10 +2931,12 @@ var CARDSETS = {
|
|
|
2498
2931
|
{
|
|
2499
2932
|
jsonKey: "values[]",
|
|
2500
2933
|
exportJsonKey: { values: ["$"] },
|
|
2934
|
+
format: TextFormat2.plainText,
|
|
2501
2935
|
tags: [
|
|
2502
2936
|
{
|
|
2503
|
-
|
|
2504
|
-
|
|
2937
|
+
// PLAN-084: value-side excludes item/lead/pageNumber/marginNumber.
|
|
2938
|
+
key: ConfigKey.group_standardTagsNoItemLead,
|
|
2939
|
+
description: "Standard tags for the audio match pair (values side, no item/lead)."
|
|
2505
2940
|
},
|
|
2506
2941
|
{
|
|
2507
2942
|
key: ConfigKey.tag_title,
|
|
@@ -2534,6 +2969,7 @@ var CARDSETS = {
|
|
|
2534
2969
|
{
|
|
2535
2970
|
jsonKey: "key",
|
|
2536
2971
|
exportJsonKey: { key: "$" },
|
|
2972
|
+
format: TextFormat2.plainText,
|
|
2537
2973
|
tags: [
|
|
2538
2974
|
{
|
|
2539
2975
|
key: ConfigKey.group_standardTags,
|
|
@@ -2563,10 +2999,12 @@ var CARDSETS = {
|
|
|
2563
2999
|
{
|
|
2564
3000
|
jsonKey: "values[]",
|
|
2565
3001
|
exportJsonKey: { values: ["$"] },
|
|
3002
|
+
format: TextFormat2.plainText,
|
|
2566
3003
|
tags: [
|
|
2567
3004
|
{
|
|
2568
|
-
|
|
2569
|
-
|
|
3005
|
+
// PLAN-084: value-side excludes item/lead/pageNumber/marginNumber.
|
|
3006
|
+
key: ConfigKey.group_standardTagsNoItemLead,
|
|
3007
|
+
description: "Standard tags for the image match pair (values side, no item/lead)."
|
|
2570
3008
|
},
|
|
2571
3009
|
{
|
|
2572
3010
|
key: ConfigKey.tag_title,
|
|
@@ -2599,20 +3037,49 @@ var CARDSETS = {
|
|
|
2599
3037
|
{
|
|
2600
3038
|
jsonKey: "key",
|
|
2601
3039
|
exportJsonKey: { key: "$" },
|
|
3040
|
+
format: TextFormat2.plainText,
|
|
2602
3041
|
tags: [
|
|
2603
3042
|
{
|
|
2604
3043
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2605
3044
|
description: "Standard tags for lead, instruction, and hint."
|
|
2606
3045
|
},
|
|
2607
3046
|
{
|
|
3047
|
+
// PLAN-076: drop `example: '$'` from valued rule — pair-key
|
|
3048
|
+
// `[@example:V]` is consumed as the per-pair cascade source.
|
|
3049
|
+
// PLAN-077 R14 follow-up: investigation showed the fixture
|
|
3050
|
+
// reference is INCONSISTENT — bits without a cardset-level
|
|
3051
|
+
// cascade (e.g. bit 3 `[@example:Y]should be...`) expect
|
|
3052
|
+
// pair-level `example: V` at pair scope, but bits WITH a
|
|
3053
|
+
// cardset cascade (e.g. bit 8 `[@example:99]` in title-row
|
|
3054
|
+
// PLUS pair-key `[@example:Y]`) expect NO pair-level
|
|
3055
|
+
// example. Emitting `example: $` here satisfies bit 3 but
|
|
3056
|
+
// breaks bit 8; dropping it satisfies bit 8 but breaks bit
|
|
3057
|
+
// 3. Conditional emission would require runtime gating on
|
|
3058
|
+
// the cardset cascade scope state. Left dropped pending a
|
|
3059
|
+
// dedicated plan — accepted divergence on bit 3's pair-
|
|
3060
|
+
// level emission (cells still get the per-cell `example`
|
|
3061
|
+
// correctly via PLAN-077 §4.2 + §4.3).
|
|
2608
3062
|
key: ConfigKey.property_example,
|
|
2609
3063
|
exportJsonKey: [
|
|
2610
|
-
{
|
|
2611
|
-
|
|
2612
|
-
|
|
3064
|
+
{
|
|
3065
|
+
"@keyonly": {
|
|
3066
|
+
isExample: true,
|
|
3067
|
+
"@bit": { isExample: true },
|
|
3068
|
+
"@card": { isExample: true }
|
|
3069
|
+
}
|
|
3070
|
+
},
|
|
3071
|
+
{
|
|
3072
|
+
"@absent": {
|
|
3073
|
+
isExample: true,
|
|
3074
|
+
"@bit": { isExample: true },
|
|
3075
|
+
"@card": { isExample: true }
|
|
3076
|
+
}
|
|
3077
|
+
},
|
|
3078
|
+
{ isExample: true, "@bit": { isExample: true }, "@card": { isExample: true } }
|
|
2613
3079
|
],
|
|
2614
3080
|
description: "Example text for the match matrix.",
|
|
2615
|
-
format: TagFormat.plainText
|
|
3081
|
+
format: TagFormat.plainText,
|
|
3082
|
+
nullable: true
|
|
2616
3083
|
},
|
|
2617
3084
|
{
|
|
2618
3085
|
key: ConfigKey.tag_title,
|
|
@@ -2640,35 +3107,96 @@ var CARDSETS = {
|
|
|
2640
3107
|
variants: [
|
|
2641
3108
|
{
|
|
2642
3109
|
jsonKey: "cells[{s}].values[]",
|
|
2643
|
-
exportJsonKey:
|
|
3110
|
+
exportJsonKey: [
|
|
3111
|
+
// PLAN-085 / R14: the positional-blank emission for an
|
|
3112
|
+
// effectively-absent cell side fires ONLY when the active
|
|
3113
|
+
// card has at least one `[#]` variant fire. This matches
|
|
3114
|
+
// BPG `extractHeadingCard`'s `isHeading` gate: when no
|
|
3115
|
+
// `[#]` exists anywhere in the title card, BPG returns
|
|
3116
|
+
// undefined and no `heading` is emitted. The phantom
|
|
3117
|
+
// `forValues:['']` placeholder is appropriate only when
|
|
3118
|
+
// the card is being treated as a title-row.
|
|
3119
|
+
{
|
|
3120
|
+
predicates: ["@absent", { "@variantHasTag": "#" }],
|
|
3121
|
+
rule: { "@bit": { heading: { forValues: [""] } } }
|
|
3122
|
+
},
|
|
3123
|
+
{ cells: { $s: { values: ["$"] } } }
|
|
3124
|
+
],
|
|
3125
|
+
format: TextFormat2.plainText,
|
|
2644
3126
|
tags: [
|
|
2645
3127
|
{
|
|
2646
3128
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2647
3129
|
description: "Standard tags for lead, instruction, and hint."
|
|
2648
3130
|
},
|
|
2649
3131
|
{
|
|
3132
|
+
// PLAN-075: bare `$parent` reads the parent variant fire's
|
|
3133
|
+
// source `$` value (the current `++`-iteration's cell text).
|
|
3134
|
+
// Replaces `$parent.values[0]` which pinned to position 0
|
|
3135
|
+
// regardless of which `++`-value `[@example]` was on.
|
|
3136
|
+
//
|
|
3137
|
+
// PLAN-077: dual `[@absent, { '$cascade': '*' }]` rule
|
|
3138
|
+
// routes pair-key `[@example:V]` (a per-pair cascade
|
|
3139
|
+
// source, bound via per-card CascadeCounters scope) and
|
|
3140
|
+
// bit-header `[@example:V]` (cardset cascade) into the
|
|
3141
|
+
// per-cell `example` via `$cascade`. The aggregator in
|
|
3142
|
+
// `populate_variants` fires this rule ONCE per cell (BPG
|
|
3143
|
+
// `parseMatchMatrix` `exampleSide` precedence), avoiding
|
|
3144
|
+
// per-iter pollution.
|
|
3145
|
+
// @card scope-shift writes matrix-row container isExample.
|
|
2650
3146
|
key: ConfigKey.property_example,
|
|
2651
3147
|
exportJsonKey: [
|
|
2652
3148
|
{
|
|
2653
3149
|
"@keyonly": {
|
|
2654
|
-
cells: { $s: { isExample: true, example: "$parent
|
|
2655
|
-
"@bit": { isExample: true }
|
|
3150
|
+
cells: { $s: { isExample: true, example: "$parent" } },
|
|
3151
|
+
"@bit": { isExample: true },
|
|
3152
|
+
"@card": { isExample: true }
|
|
2656
3153
|
}
|
|
2657
3154
|
},
|
|
2658
3155
|
{
|
|
2659
|
-
"@absent"
|
|
3156
|
+
predicates: ["@absent", { $cascade: "*" }],
|
|
3157
|
+
rule: {
|
|
3158
|
+
cells: { $s: { isExample: true, example: "$cascade" } },
|
|
3159
|
+
"@bit": { isExample: true },
|
|
3160
|
+
"@card": { isExample: true }
|
|
3161
|
+
}
|
|
2660
3162
|
},
|
|
2661
|
-
{
|
|
3163
|
+
{
|
|
3164
|
+
"@absent": {
|
|
3165
|
+
cells: { $s: { isExample: true, example: "$parent" } },
|
|
3166
|
+
"@bit": { isExample: true },
|
|
3167
|
+
"@card": { isExample: true }
|
|
3168
|
+
}
|
|
3169
|
+
},
|
|
3170
|
+
{
|
|
3171
|
+
cells: { $s: { isExample: true, example: "$" } },
|
|
3172
|
+
"@bit": { isExample: true },
|
|
3173
|
+
"@card": { isExample: true }
|
|
3174
|
+
}
|
|
2662
3175
|
],
|
|
2663
3176
|
description: "Example text for the match matrix.",
|
|
2664
|
-
format: TagFormat.
|
|
3177
|
+
format: TagFormat.bitmarkText,
|
|
3178
|
+
nullable: true
|
|
2665
3179
|
},
|
|
2666
3180
|
{
|
|
3181
|
+
// PLAN-085 / R14: bare `[#]` on a value-side emits the
|
|
3182
|
+
// empty-string positional blank into `forValues` so the
|
|
3183
|
+
// array stays aligned with the cell positions (matches BPG
|
|
3184
|
+
// `extractHeadingCard`'s "all value-side headings present"
|
|
3185
|
+
// shape). The `@keyonly` rule is required for two reasons:
|
|
3186
|
+
// 1) it provides an emission for bare `[#]` (the `$` sigil
|
|
3187
|
+
// in the unconditional rule has no source for bare); and
|
|
3188
|
+
// 2) the presence of any `@keyonly` rule disables the
|
|
3189
|
+
// optimised-mode `should_suppress_outcome` strip (see
|
|
3190
|
+
// `forward_emit.rs`) so the resulting `forValues: [""]`
|
|
3191
|
+
// survives the all-natural-defaults check.
|
|
2667
3192
|
key: ConfigKey.tag_title,
|
|
2668
3193
|
description: "Title of the match matrix.",
|
|
2669
3194
|
format: TagFormat.plainText,
|
|
2670
3195
|
jsonKey: "^heading.forValues",
|
|
2671
|
-
exportJsonKey:
|
|
3196
|
+
exportJsonKey: [
|
|
3197
|
+
{ "@keyonly": { "@bit": { heading: { forValues: [""] } } } },
|
|
3198
|
+
{ "@bit": { heading: { forValues: ["$"] } } }
|
|
3199
|
+
]
|
|
2672
3200
|
},
|
|
2673
3201
|
{
|
|
2674
3202
|
key: ConfigKey.property_isCaseSensitive,
|
|
@@ -2717,6 +3245,35 @@ var CARDSETS = {
|
|
|
2717
3245
|
{
|
|
2718
3246
|
key: ConfigKey.group_standardTags,
|
|
2719
3247
|
description: "Standard tags for the statement."
|
|
3248
|
+
},
|
|
3249
|
+
{
|
|
3250
|
+
// PLAN-072: cascade-fired `@example` from the bit header
|
|
3251
|
+
// fills each statement entry's `example` with the entry's
|
|
3252
|
+
// own `isCorrect`, mirroring BPG's `pushExampleDownTree`
|
|
3253
|
+
// for the statements cardset. Per-array-item strip removes
|
|
3254
|
+
// `example: false` from incorrect entries so only correct
|
|
3255
|
+
// entries retain `example: true`.
|
|
3256
|
+
key: ConfigKey.property_example,
|
|
3257
|
+
exportJsonKey: [
|
|
3258
|
+
{
|
|
3259
|
+
"@keyonly": {
|
|
3260
|
+
isExample: true,
|
|
3261
|
+
example: true,
|
|
3262
|
+
"@bit": { isExample: true }
|
|
3263
|
+
}
|
|
3264
|
+
},
|
|
3265
|
+
{
|
|
3266
|
+
"@absent": {
|
|
3267
|
+
isExample: true,
|
|
3268
|
+
example: "$parent.isCorrect",
|
|
3269
|
+
"@bit": { isExample: true }
|
|
3270
|
+
}
|
|
3271
|
+
},
|
|
3272
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3273
|
+
],
|
|
3274
|
+
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`.",
|
|
3275
|
+
format: TagFormat.boolean,
|
|
3276
|
+
nullable: true
|
|
2720
3277
|
}
|
|
2721
3278
|
],
|
|
2722
3279
|
bodyAllowed: false
|
|
@@ -2745,6 +3302,71 @@ var CARDSETS = {
|
|
|
2745
3302
|
{
|
|
2746
3303
|
key: ConfigKey.group_standardTags,
|
|
2747
3304
|
description: "Standard tags for the quiz."
|
|
3305
|
+
},
|
|
3306
|
+
{
|
|
3307
|
+
// ALIGN-EXAMPLE-CASCADE §3.2: variant-level cascade for
|
|
3308
|
+
// quiz choices is delegated to group_trueFalse's
|
|
3309
|
+
// chain-child `@example` (`+` chain with maxEmits:1 +
|
|
3310
|
+
// `@parent.isCorrect=true`). Variant-level `@absent`
|
|
3311
|
+
// would over-fire on subsequent correct choices and on
|
|
3312
|
+
// incorrect ones — drop it.
|
|
3313
|
+
key: ConfigKey.property_example,
|
|
3314
|
+
exportJsonKey: [
|
|
3315
|
+
{ "@keyonly": { isExample: true, "@bit": { isExample: true } } },
|
|
3316
|
+
{ isExample: true, "@bit": { isExample: true } }
|
|
3317
|
+
],
|
|
3318
|
+
description: "Example marker on the quiz choice (entry-local only; cascade handled by group_trueFalse chain-children).",
|
|
3319
|
+
format: TagFormat.boolean,
|
|
3320
|
+
nullable: true
|
|
3321
|
+
}
|
|
3322
|
+
],
|
|
3323
|
+
bodyAllowed: false
|
|
3324
|
+
}
|
|
3325
|
+
]
|
|
3326
|
+
}
|
|
3327
|
+
]
|
|
3328
|
+
},
|
|
3329
|
+
//
|
|
3330
|
+
// quiz (responses)
|
|
3331
|
+
//
|
|
3332
|
+
[CardSetConfigKey.quizResponses]: {
|
|
3333
|
+
jsonKey: "quizzes",
|
|
3334
|
+
exportJsonKey: { quizzes: "$" },
|
|
3335
|
+
sides: [
|
|
3336
|
+
{
|
|
3337
|
+
name: "responses",
|
|
3338
|
+
variants: [
|
|
3339
|
+
{
|
|
3340
|
+
jsonKey: null,
|
|
3341
|
+
tags: [
|
|
3342
|
+
{
|
|
3343
|
+
key: ConfigKey.group_trueFalseResponses,
|
|
3344
|
+
description: "Group for true/false questions."
|
|
3345
|
+
},
|
|
3346
|
+
{
|
|
3347
|
+
key: ConfigKey.group_standardTags,
|
|
3348
|
+
description: "Standard tags for the quiz."
|
|
3349
|
+
},
|
|
3350
|
+
{
|
|
3351
|
+
// PLAN-072: cascade-fired `@example` from the bit header
|
|
3352
|
+
// fills each response entry's `example` with the entry's
|
|
3353
|
+
// own `isCorrect`, mirroring BPG's `pushExampleDownTree`
|
|
3354
|
+
// for the quiz-responses cardset (statements-style).
|
|
3355
|
+
key: ConfigKey.property_example,
|
|
3356
|
+
exportJsonKey: [
|
|
3357
|
+
{ "@keyonly": { isExample: true, "@bit": { isExample: true } } },
|
|
3358
|
+
{
|
|
3359
|
+
"@absent": {
|
|
3360
|
+
isExample: true,
|
|
3361
|
+
example: "$parent.isCorrect",
|
|
3362
|
+
"@bit": { isExample: true }
|
|
3363
|
+
}
|
|
3364
|
+
},
|
|
3365
|
+
{ isExample: true, "@bit": { isExample: true } }
|
|
3366
|
+
],
|
|
3367
|
+
description: "Example marker on the quiz response; cascade from bit-header fills `example` with the entry\u2019s own `isCorrect`.",
|
|
3368
|
+
format: TagFormat.boolean,
|
|
3369
|
+
nullable: true
|
|
2748
3370
|
}
|
|
2749
3371
|
],
|
|
2750
3372
|
bodyAllowed: false
|
|
@@ -2770,6 +3392,73 @@ var CARDSETS = {
|
|
|
2770
3392
|
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
2771
3393
|
description: "Standard tags for lead, instruction, and hint."
|
|
2772
3394
|
},
|
|
3395
|
+
{
|
|
3396
|
+
// Feedback choices: `[+]` / `[-]` map to choice + `requireReason`
|
|
3397
|
+
// (NOT `isCorrect` like trueFalse). Shadow the inherited
|
|
3398
|
+
// `tag_true` / `tag_false` from `group_trueFalse` to emit the
|
|
3399
|
+
// feedback-specific shape.
|
|
3400
|
+
//
|
|
3401
|
+
// Chain @example: `[+ X][@example]` writes
|
|
3402
|
+
// `isExample/example` onto the X choice only. BPG's
|
|
3403
|
+
// `setIsExampleFlags` (Builder.ts:4041-4172) does NOT
|
|
3404
|
+
// iterate `cardNode.feedbacks` — so unlike multipleChoice,
|
|
3405
|
+
// there is no bubble to bit-level or feedbacks-level
|
|
3406
|
+
// isExample. Pattern omits `@bit` scope-shift accordingly.
|
|
3407
|
+
// No `@absent`/`@parent.isCorrect` cascade rules either:
|
|
3408
|
+
// BPG's `pushExampleDownTree` (Builder.ts:3777-3849) has
|
|
3409
|
+
// no feedback dispatch, so bit-header `[@example]` does
|
|
3410
|
+
// not flow into feedback choices.
|
|
3411
|
+
key: ConfigKey.tag_true,
|
|
3412
|
+
exportJsonKey: { choices: [{ choice: "$", requireReason: true }] },
|
|
3413
|
+
description: "Reason-required choice for feedback (`[+]`).",
|
|
3414
|
+
maxCount: Count.infinity,
|
|
3415
|
+
format: TagFormat.plainText,
|
|
3416
|
+
chain: [
|
|
3417
|
+
{
|
|
3418
|
+
key: ConfigKey.property_example,
|
|
3419
|
+
exportJsonKey: [
|
|
3420
|
+
{ "@keyonly": { isExample: true, example: true } },
|
|
3421
|
+
{ isExample: true, example: "$" }
|
|
3422
|
+
],
|
|
3423
|
+
description: "Per-choice example marker for feedback `[+]`.",
|
|
3424
|
+
format: TagFormat.boolean,
|
|
3425
|
+
maxCount: 1,
|
|
3426
|
+
nullable: true
|
|
3427
|
+
},
|
|
3428
|
+
{
|
|
3429
|
+
// `[+ X][! foo]` chains `!` (instruction) onto the
|
|
3430
|
+
// choice; same for `[?]` (hint), `[%]` (item),
|
|
3431
|
+
// `[%2]`/`[%3]`/`[%4]` (lead/pageNumber/marginNumber).
|
|
3432
|
+
// Mirrors group_trueFalse's `+` chain shape.
|
|
3433
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3434
|
+
description: "Item, lead, page number, margin number, instruction and hint chained onto the feedback choice."
|
|
3435
|
+
}
|
|
3436
|
+
]
|
|
3437
|
+
},
|
|
3438
|
+
{
|
|
3439
|
+
key: ConfigKey.tag_false,
|
|
3440
|
+
exportJsonKey: { choices: [{ choice: "$", requireReason: false }] },
|
|
3441
|
+
description: "Reason-not-required choice for feedback (`[-]`).",
|
|
3442
|
+
maxCount: Count.infinity,
|
|
3443
|
+
format: TagFormat.plainText,
|
|
3444
|
+
chain: [
|
|
3445
|
+
{
|
|
3446
|
+
key: ConfigKey.property_example,
|
|
3447
|
+
exportJsonKey: [
|
|
3448
|
+
{ "@keyonly": { isExample: true, example: true } },
|
|
3449
|
+
{ isExample: true, example: "$" }
|
|
3450
|
+
],
|
|
3451
|
+
description: "Per-choice example marker for feedback `[-]`.",
|
|
3452
|
+
format: TagFormat.boolean,
|
|
3453
|
+
maxCount: 1,
|
|
3454
|
+
nullable: true
|
|
3455
|
+
},
|
|
3456
|
+
{
|
|
3457
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
3458
|
+
description: "Item, lead, page number, margin number, instruction and hint chained onto the feedback choice."
|
|
3459
|
+
}
|
|
3460
|
+
]
|
|
3461
|
+
},
|
|
2773
3462
|
{
|
|
2774
3463
|
key: ConfigKey.group_trueFalse,
|
|
2775
3464
|
description: "Group for true/false feedback."
|
|
@@ -2790,31 +3479,71 @@ var CARDSETS = {
|
|
|
2790
3479
|
name: "reason",
|
|
2791
3480
|
variants: [
|
|
2792
3481
|
{
|
|
3482
|
+
// PLAN: feedback.reason — Object-only variant pattern. Per
|
|
3483
|
+
// SYNTAX.md §8.1, sibling tag emissions do NOT auto-wrap
|
|
3484
|
+
// under `reason.*`; each tag here spells out the full path.
|
|
3485
|
+
// Body is a plain string (BPG `parseFeedback` uses
|
|
3486
|
+
// `cardBodyStr ?? ''` for `reason.text`).
|
|
2793
3487
|
jsonKey: "reason.text",
|
|
2794
3488
|
exportJsonKey: { reason: { text: "$" } },
|
|
3489
|
+
format: TextFormat2.plainText,
|
|
2795
3490
|
tags: [
|
|
2796
3491
|
{
|
|
2797
|
-
|
|
2798
|
-
|
|
3492
|
+
// Instruction lands under reason. Hint/item/lead/etc.
|
|
3493
|
+
// omitted: not exercised by any fixture and BPG's
|
|
3494
|
+
// `parseFeedback` spreads only the tags actually present
|
|
3495
|
+
// — adding the rest can be done lazily as fixtures
|
|
3496
|
+
// require them, with the same `{reason: {…}}` wrapper.
|
|
3497
|
+
key: ConfigKey.tag_instruction,
|
|
3498
|
+
exportJsonKey: { reason: { instruction: "$" } },
|
|
3499
|
+
description: "Instruction for the feedback reason.",
|
|
3500
|
+
format: TagFormat.bitmarkText
|
|
2799
3501
|
},
|
|
2800
3502
|
{
|
|
2801
3503
|
key: ConfigKey.property_reasonableNumOfChars,
|
|
2802
3504
|
exportJsonKey: [
|
|
2803
|
-
{ "@absent": { reasonableNumOfChars: "$ancestor" } },
|
|
2804
|
-
{ reasonableNumOfChars: "$" }
|
|
3505
|
+
{ "@absent": { reason: { reasonableNumOfChars: "$ancestor" } } },
|
|
3506
|
+
{ reason: { reasonableNumOfChars: "$" } }
|
|
2805
3507
|
],
|
|
2806
3508
|
description: "Property for reasonable number of characters.",
|
|
2807
3509
|
format: TagFormat.number
|
|
2808
3510
|
},
|
|
2809
3511
|
{
|
|
3512
|
+
// ALIGN-EXAMPLE-CASCADE §3.9: `feedback.reason` is NOT in
|
|
3513
|
+
// BPG's `pushExampleDownTree` dispatch — no bit-header
|
|
3514
|
+
// cascade. Local emission only.
|
|
3515
|
+
//
|
|
3516
|
+
// Both `reason.example` and `feedbacks[].example` are
|
|
3517
|
+
// `TextAst` per BPG's schema — paragraph arrays. Format
|
|
3518
|
+
// here is `bitmarkText` so `$` coerces to a paragraph
|
|
3519
|
+
// array at both write sites.
|
|
2810
3520
|
key: ConfigKey.property_example,
|
|
2811
3521
|
exportJsonKey: [
|
|
2812
|
-
{
|
|
2813
|
-
|
|
2814
|
-
|
|
3522
|
+
{
|
|
3523
|
+
// Bare `[@example]`: reason.example is TextAst — BPG
|
|
3524
|
+
// coerces the boolean default to a paragraph
|
|
3525
|
+
// containing the string "true". feedbacks[].example
|
|
3526
|
+
// is not TextAst, stays a boolean. Two literal writes.
|
|
3527
|
+
"@keyonly": {
|
|
3528
|
+
reason: {
|
|
3529
|
+
isExample: true,
|
|
3530
|
+
example: [{ type: "paragraph", content: [{ text: "true", type: "text" }] }]
|
|
3531
|
+
},
|
|
3532
|
+
isExample: true,
|
|
3533
|
+
example: true,
|
|
3534
|
+
"@bit": { isExample: true }
|
|
3535
|
+
}
|
|
3536
|
+
},
|
|
3537
|
+
{
|
|
3538
|
+
reason: { isExample: true, example: "$" },
|
|
3539
|
+
isExample: true,
|
|
3540
|
+
example: "$",
|
|
3541
|
+
"@bit": { isExample: true }
|
|
3542
|
+
}
|
|
2815
3543
|
],
|
|
2816
|
-
description: "Example text for the feedback.",
|
|
2817
|
-
format: TagFormat.
|
|
3544
|
+
description: "Example text for the feedback reason (entry-local only; no bit-header cascade).",
|
|
3545
|
+
format: TagFormat.bitmarkText,
|
|
3546
|
+
nullable: true
|
|
2818
3547
|
},
|
|
2819
3548
|
{
|
|
2820
3549
|
key: ConfigKey.tag_title,
|
|
@@ -2878,6 +3607,39 @@ var CARDSETS = {
|
|
|
2878
3607
|
{
|
|
2879
3608
|
key: ConfigKey.group_standardTags,
|
|
2880
3609
|
description: "Standard tags for the question."
|
|
3610
|
+
},
|
|
3611
|
+
{
|
|
3612
|
+
// ALIGN-EXAMPLE-CASCADE §3.10: `questions` is NOT in BPG's
|
|
3613
|
+
// `pushExampleDownTree` dispatch — bit-header `[@example]`
|
|
3614
|
+
// does not propagate `example`/`isExample` onto question
|
|
3615
|
+
// entries. Only entry-local `[@example]` fires.
|
|
3616
|
+
//
|
|
3617
|
+
// BPG's `BaseBuilder.toExample` for interview questions
|
|
3618
|
+
// (Builder.ts:2575,2588) uses `data.__sampleSolutionAst`
|
|
3619
|
+
// as `defaultExample` — bare `[@example]` (which sets
|
|
3620
|
+
// `__isDefaultExample=true, example=undefined`) emits the
|
|
3621
|
+
// parsed sample-solution AST in the `example` slot. The
|
|
3622
|
+
// `@keyonly` rule mirrors that runtime behaviour via
|
|
3623
|
+
// `$parent.sampleSolution` — the chain-walker's post-walk
|
|
3624
|
+
// retry resolves this once the sibling `[@sampleSolution]`
|
|
3625
|
+
// chain has merged into the shared scope (interview's
|
|
3626
|
+
// `[@example]` typically precedes `[@sampleSolution]` in
|
|
3627
|
+
// source). Format coercion turns the resolved string
|
|
3628
|
+
// value into a PM tree.
|
|
3629
|
+
key: ConfigKey.property_example,
|
|
3630
|
+
exportJsonKey: [
|
|
3631
|
+
{
|
|
3632
|
+
"@keyonly": {
|
|
3633
|
+
isExample: true,
|
|
3634
|
+
example: "$parent.sampleSolution",
|
|
3635
|
+
"@bit": { isExample: true }
|
|
3636
|
+
}
|
|
3637
|
+
},
|
|
3638
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3639
|
+
],
|
|
3640
|
+
description: "Example marker for the question (entry-local only; no bit-header cascade).",
|
|
3641
|
+
format: TagFormat.bitmarkText,
|
|
3642
|
+
nullable: true
|
|
2881
3643
|
}
|
|
2882
3644
|
]
|
|
2883
3645
|
}
|
|
@@ -2904,14 +3666,16 @@ var CARDSETS = {
|
|
|
2904
3666
|
description: "Standard tags for lead, instruction, and hint."
|
|
2905
3667
|
},
|
|
2906
3668
|
{
|
|
3669
|
+
// ALIGN-EXAMPLE-CASCADE §3.11: `elements` is NOT in BPG's
|
|
3670
|
+
// `pushExampleDownTree` dispatch — no bit-header cascade.
|
|
2907
3671
|
key: ConfigKey.property_example,
|
|
2908
3672
|
exportJsonKey: [
|
|
2909
3673
|
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2910
|
-
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2911
3674
|
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2912
3675
|
],
|
|
2913
|
-
description: "Example text for the element.",
|
|
2914
|
-
format: TagFormat.plainText
|
|
3676
|
+
description: "Example text for the element (entry-local only; no bit-header cascade).",
|
|
3677
|
+
format: TagFormat.plainText,
|
|
3678
|
+
nullable: true
|
|
2915
3679
|
}
|
|
2916
3680
|
],
|
|
2917
3681
|
repeatCount: Count.infinity
|
|
@@ -2923,9 +3687,57 @@ var CARDSETS = {
|
|
|
2923
3687
|
//
|
|
2924
3688
|
// table
|
|
2925
3689
|
//
|
|
3690
|
+
// PLAN-079: supports BOTH source formats and collapses to the same basic
|
|
3691
|
+
// output (`{ columns?, data, columnWidths? }`):
|
|
3692
|
+
//
|
|
3693
|
+
// 1. Basic format — first card carries `[#X]` markers (fire `tag_title`
|
|
3694
|
+
// → `^table.columns[]`); subsequent cards are body rows. Cards have
|
|
3695
|
+
// no qualifier, so they route to the `table-body` (default) section.
|
|
3696
|
+
//
|
|
3697
|
+
// 2. Extended format — `==== table-header ====` / `==== table-footer ====`
|
|
3698
|
+
// qualifiers. The `table-header` section uses `@cardIndex=0` to route
|
|
3699
|
+
// the first header card's cells to `columns` and demote remaining
|
|
3700
|
+
// header cards (rows) into `data`. Per-cell `[@tableRowSpan]` /
|
|
3701
|
+
// `[@tableScope]` / `[@tableCellType]` tags are valid-but-unmapped
|
|
3702
|
+
// here (no per-cell metadata in basic shape) — declared on the cell
|
|
3703
|
+
// variant below.
|
|
3704
|
+
//
|
|
2926
3705
|
[CardSetConfigKey.table]: {
|
|
2927
|
-
jsonKey:
|
|
2928
|
-
exportJsonKey:
|
|
3706
|
+
jsonKey: null,
|
|
3707
|
+
exportJsonKey: null,
|
|
3708
|
+
sections: {
|
|
3709
|
+
"table-header": {
|
|
3710
|
+
// First header card's row of cells → `columns`. Subsequent header
|
|
3711
|
+
// cards' rows → `data` (per-card append; `[$]` shape because
|
|
3712
|
+
// per-card emission fires once per card, multiple fires deep_merge-
|
|
3713
|
+
// append). PLAN-079 + PLAN-080: predicates inside exportJsonKey
|
|
3714
|
+
// both ROUTE cards to this section (when no explicit `==== table-
|
|
3715
|
+
// header ====` qualifier) and SELECT the rule body once routed.
|
|
3716
|
+
// First rule = first card with any `[#]` → `columns`; second rule
|
|
3717
|
+
// = subsequent cards in this section → `data` (per-row append).
|
|
3718
|
+
jsonKey: "table.columns",
|
|
3719
|
+
exportJsonKey: [
|
|
3720
|
+
{
|
|
3721
|
+
predicates: [{ "@cardIndex": 0 }, { "@variantHasTag": "#" }],
|
|
3722
|
+
rule: { "@bit": { table: { columns: "$" } } }
|
|
3723
|
+
},
|
|
3724
|
+
{ "@cardIndex=0": { "@bit": { table: { columns: "$" } } } },
|
|
3725
|
+
{ "@bit": { table: { data: ["$"] } } }
|
|
3726
|
+
]
|
|
3727
|
+
},
|
|
3728
|
+
"table-body": {
|
|
3729
|
+
// Batched emission: `$` is the entire 2D array of body card rows.
|
|
3730
|
+
// This is the default section (no qualifier → cards land here).
|
|
3731
|
+
jsonKey: "table.data",
|
|
3732
|
+
exportJsonKey: { "@bit": { table: { data: "$" } } },
|
|
3733
|
+
isDefault: true
|
|
3734
|
+
},
|
|
3735
|
+
"table-footer": {
|
|
3736
|
+
// Batched emission: `$` is the entire 2D array of footer rows.
|
|
3737
|
+
jsonKey: "table.data",
|
|
3738
|
+
exportJsonKey: { "@bit": { table: { data: "$" } } }
|
|
3739
|
+
}
|
|
3740
|
+
},
|
|
2929
3741
|
sides: [
|
|
2930
3742
|
{
|
|
2931
3743
|
name: "cell",
|
|
@@ -2966,6 +3778,8 @@ var CARDSETS = {
|
|
|
2966
3778
|
},
|
|
2967
3779
|
{
|
|
2968
3780
|
key: ConfigKey.property_tableColWidth,
|
|
3781
|
+
jsonKey: "^table.columnWidths[{s}]",
|
|
3782
|
+
exportJsonKey: { "@bit": { table: { columnWidths: { $s: "$" } } } },
|
|
2969
3783
|
description: "Width for the column.",
|
|
2970
3784
|
format: TagFormat.number
|
|
2971
3785
|
}
|
|
@@ -2984,7 +3798,22 @@ var CARDSETS = {
|
|
|
2984
3798
|
sections: {
|
|
2985
3799
|
"table-header": {
|
|
2986
3800
|
jsonKey: "table.header.rows",
|
|
2987
|
-
|
|
3801
|
+
// PLAN-080: section dispatch via predicates inside exportJsonKey.
|
|
3802
|
+
// Cards with no explicit `==== table-header ====` qualifier
|
|
3803
|
+
// route here if FIRST CARD contains any `[#]` tag in any
|
|
3804
|
+
// variant. Explicit-qualifier cards fall through to the
|
|
3805
|
+
// unconditional fallback rule. Both rules use the per-card
|
|
3806
|
+
// append shape `rows: ['$']` — the runtime triggers per-card
|
|
3807
|
+
// emission whenever the pattern carries predicates, and each
|
|
3808
|
+
// fire appends a single-element array (multi-fire deep-merge
|
|
3809
|
+
// concatenates).
|
|
3810
|
+
exportJsonKey: [
|
|
3811
|
+
{
|
|
3812
|
+
predicates: [{ "@cardIndex": 0 }, { "@variantHasTag": "#" }],
|
|
3813
|
+
rule: { table: { header: { rows: ["$"] } } }
|
|
3814
|
+
},
|
|
3815
|
+
{ table: { header: { rows: ["$"] } } }
|
|
3816
|
+
],
|
|
2988
3817
|
sideJsonKey: "cells[{s}]|set(title=true)",
|
|
2989
3818
|
sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } }
|
|
2990
3819
|
},
|
|
@@ -3017,13 +3846,13 @@ var CARDSETS = {
|
|
|
3017
3846
|
},
|
|
3018
3847
|
{
|
|
3019
3848
|
key: ConfigKey.tag_title,
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
},
|
|
3026
|
-
description: "Title of the table cell."
|
|
3849
|
+
// PLAN-080: the `[#]` tag writes its text to the cell's
|
|
3850
|
+
// `content` field. When the card is in the `table-header`
|
|
3851
|
+
// section, the section's sideExportJsonKey wraps each
|
|
3852
|
+
// cell with `title: true` automatically.
|
|
3853
|
+
jsonKey: "content",
|
|
3854
|
+
exportJsonKey: { content: "$" },
|
|
3855
|
+
description: "Title text of the table cell (header rows)."
|
|
3027
3856
|
},
|
|
3028
3857
|
{
|
|
3029
3858
|
key: ConfigKey.property_tableCellType,
|
|
@@ -3055,6 +3884,9 @@ var CARDSETS = {
|
|
|
3055
3884
|
},
|
|
3056
3885
|
{
|
|
3057
3886
|
key: ConfigKey.property_tableColWidth,
|
|
3887
|
+
// PLAN-080: write to the cell's `colwidth` field.
|
|
3888
|
+
jsonKey: "colwidth",
|
|
3889
|
+
exportJsonKey: { colwidth: "$" },
|
|
3058
3890
|
description: "Width for the column.",
|
|
3059
3891
|
format: TagFormat.number
|
|
3060
3892
|
}
|
|
@@ -3092,7 +3924,8 @@ var CARDSETS = {
|
|
|
3092
3924
|
{
|
|
3093
3925
|
key: ConfigKey.resource_audio,
|
|
3094
3926
|
description: "Audio resource for the pronunciation table.",
|
|
3095
|
-
jsonKey: "audio"
|
|
3927
|
+
jsonKey: "audio",
|
|
3928
|
+
exportJsonKey: { audio: { type: "audio", audio: { src: "$" } } }
|
|
3096
3929
|
}
|
|
3097
3930
|
],
|
|
3098
3931
|
repeatCount: Count.infinity
|
|
@@ -3163,14 +3996,17 @@ var CARDSETS = {
|
|
|
3163
3996
|
format: TagFormat.plainText
|
|
3164
3997
|
},
|
|
3165
3998
|
{
|
|
3999
|
+
// ALIGN-EXAMPLE-CASCADE §3.12: `bot-action-responses` is
|
|
4000
|
+
// NOT in BPG's `pushExampleDownTree` dispatch — no bit-
|
|
4001
|
+
// header cascade.
|
|
3166
4002
|
key: ConfigKey.property_example,
|
|
3167
4003
|
exportJsonKey: [
|
|
3168
4004
|
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
3169
|
-
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
3170
4005
|
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3171
4006
|
],
|
|
3172
|
-
description: "Example text for the bot action response.",
|
|
3173
|
-
format: TagFormat.plainText
|
|
4007
|
+
description: "Example text for the bot action response (entry-local only; no bit-header cascade).",
|
|
4008
|
+
format: TagFormat.plainText,
|
|
4009
|
+
nullable: true
|
|
3174
4010
|
}
|
|
3175
4011
|
]
|
|
3176
4012
|
}
|
|
@@ -3236,6 +4072,38 @@ var CARDSETS = {
|
|
|
3236
4072
|
]
|
|
3237
4073
|
},
|
|
3238
4074
|
//
|
|
4075
|
+
// page-footer-sections — mirrors example-bit-list but emits cards under
|
|
4076
|
+
// `sections` instead of `listItems`. BPG's JsonGenerator special-cases
|
|
4077
|
+
// BitType.pageFooter in code; this dedicated cardSet expresses the same
|
|
4078
|
+
// routing as pure config so the Rust serializer can pick it up.
|
|
4079
|
+
//
|
|
4080
|
+
[CardSetConfigKey.pageFooterSections]: {
|
|
4081
|
+
jsonKey: "sections",
|
|
4082
|
+
exportJsonKey: { sections: "$" },
|
|
4083
|
+
sides: [
|
|
4084
|
+
{
|
|
4085
|
+
name: "item",
|
|
4086
|
+
variants: [
|
|
4087
|
+
{
|
|
4088
|
+
jsonKey: "body",
|
|
4089
|
+
exportJsonKey: { body: "$" },
|
|
4090
|
+
tags: [
|
|
4091
|
+
{
|
|
4092
|
+
key: ConfigKey.group_standardTags,
|
|
4093
|
+
description: "Standard tags for page-footer section bits."
|
|
4094
|
+
},
|
|
4095
|
+
{
|
|
4096
|
+
exportJsonKey: { title: "$" },
|
|
4097
|
+
key: ConfigKey.tag_title,
|
|
4098
|
+
description: "Title of the page-footer section."
|
|
4099
|
+
}
|
|
4100
|
+
]
|
|
4101
|
+
}
|
|
4102
|
+
]
|
|
4103
|
+
}
|
|
4104
|
+
]
|
|
4105
|
+
},
|
|
4106
|
+
//
|
|
3239
4107
|
// ingredients
|
|
3240
4108
|
//
|
|
3241
4109
|
[CardSetConfigKey.ingredients]: {
|
|
@@ -3566,7 +4434,11 @@ var GROUPS = {
|
|
|
3566
4434
|
{
|
|
3567
4435
|
key: ConfigKey.property_groupTag,
|
|
3568
4436
|
jsonKey: "groupTag.name",
|
|
3569
|
-
|
|
4437
|
+
// PLAN-063: starter-array shape with `@id` declares entity-merge
|
|
4438
|
+
// semantics — repeated `[@groupTag: name]` occurrences with the
|
|
4439
|
+
// same value fold into one entry; chained `@tag` children's
|
|
4440
|
+
// arrays merge as sets.
|
|
4441
|
+
exportJsonKey: { groupTag: [{ "@id": "name", name: "$" }] },
|
|
3570
4442
|
description: "The group tag(s) for the bit",
|
|
3571
4443
|
format: TagFormat.plainText,
|
|
3572
4444
|
maxCount: Count.infinity,
|
|
@@ -3739,6 +4611,24 @@ var GROUPS = {
|
|
|
3739
4611
|
}
|
|
3740
4612
|
]
|
|
3741
4613
|
},
|
|
4614
|
+
[ConfigKey.group_standardInstructionHint]: {
|
|
4615
|
+
type: GroupConfigType.standard,
|
|
4616
|
+
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).",
|
|
4617
|
+
tags: [
|
|
4618
|
+
{
|
|
4619
|
+
exportJsonKey: { instruction: "$" },
|
|
4620
|
+
key: ConfigKey.tag_instruction,
|
|
4621
|
+
name: "Instruction",
|
|
4622
|
+
description: "The instruction for the bit"
|
|
4623
|
+
},
|
|
4624
|
+
{
|
|
4625
|
+
exportJsonKey: { hint: "$" },
|
|
4626
|
+
key: ConfigKey.tag_hint,
|
|
4627
|
+
name: "Hint",
|
|
4628
|
+
description: "The hint for the bit"
|
|
4629
|
+
}
|
|
4630
|
+
]
|
|
4631
|
+
},
|
|
3742
4632
|
[ConfigKey.group_standardTags]: {
|
|
3743
4633
|
type: GroupConfigType.standard,
|
|
3744
4634
|
description: "Standard tags which apply to MOST (but not all) bits",
|
|
@@ -3752,17 +4642,45 @@ var GROUPS = {
|
|
|
3752
4642
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3753
4643
|
},
|
|
3754
4644
|
{
|
|
3755
|
-
// Bit-level example tag
|
|
3756
|
-
//
|
|
3757
|
-
//
|
|
4645
|
+
// Bit-level example tag (default — non-`isTopLevelExample` bits):
|
|
4646
|
+
// - bare `[@example]`: consume only (records cascade marker, emits
|
|
4647
|
+
// nothing at bit-level — OLD parser scrubs bit-level isExample
|
|
4648
|
+
// for bits NOT in its `isTopLevelExample` allow-list).
|
|
4649
|
+
// - synthesized (descendant cascade): still emits `isExample: true`
|
|
4650
|
+
// at the descendant scope.
|
|
4651
|
+
// - valued `[@example:text]`: emit the example value only; bit-level
|
|
4652
|
+
// `isExample` is left to bubble from descendants.
|
|
4653
|
+
// Bits in the OLD parser's allow-list (flashcard, definitionList,
|
|
4654
|
+
// sequence, multipleChoice, trueFalse, cloze*, mark, interview,
|
|
4655
|
+
// matchMatrix, match, essay, etc.) override this entry with the
|
|
4656
|
+
// legacy emit-isExample shape.
|
|
3758
4657
|
key: ConfigKey.property_example,
|
|
3759
|
-
exportJsonKey: [
|
|
3760
|
-
{ "@keyonly": { isExample: true } },
|
|
3761
|
-
{ "@absent": { isExample: true } },
|
|
3762
|
-
{ isExample: true, example: "$" }
|
|
3763
|
-
],
|
|
4658
|
+
exportJsonKey: [{ "@keyonly": {} }, { "@absent": { isExample: true } }, { example: "$" }],
|
|
3764
4659
|
description: "The example(s) for the bit",
|
|
3765
|
-
format: TagFormat.bitmarkText
|
|
4660
|
+
format: TagFormat.bitmarkText,
|
|
4661
|
+
nullable: true
|
|
4662
|
+
}
|
|
4663
|
+
]
|
|
4664
|
+
},
|
|
4665
|
+
[ConfigKey.group_standardTagsNoItemLead]: {
|
|
4666
|
+
type: GroupConfigType.standard,
|
|
4667
|
+
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).",
|
|
4668
|
+
tags: [
|
|
4669
|
+
{
|
|
4670
|
+
key: ConfigKey.group_standardAllBits,
|
|
4671
|
+
description: "All standard tags which apply to all bits"
|
|
4672
|
+
},
|
|
4673
|
+
{
|
|
4674
|
+
key: ConfigKey.group_standardInstructionHint,
|
|
4675
|
+
description: "Instruction and hint tags only (no item/lead chain)."
|
|
4676
|
+
},
|
|
4677
|
+
{
|
|
4678
|
+
// Mirror of group_standardTags property_example entry.
|
|
4679
|
+
key: ConfigKey.property_example,
|
|
4680
|
+
exportJsonKey: [{ "@keyonly": {} }, { "@absent": { isExample: true } }, { example: "$" }],
|
|
4681
|
+
description: "The example(s) for the bit",
|
|
4682
|
+
format: TagFormat.bitmarkText,
|
|
4683
|
+
nullable: true
|
|
3766
4684
|
}
|
|
3767
4685
|
]
|
|
3768
4686
|
},
|
|
@@ -3827,8 +4745,8 @@ var GROUPS = {
|
|
|
3827
4745
|
tags: [
|
|
3828
4746
|
{
|
|
3829
4747
|
key: ConfigKey.property_person,
|
|
3830
|
-
jsonKey: "
|
|
3831
|
-
exportJsonKey: {
|
|
4748
|
+
jsonKey: "person.name",
|
|
4749
|
+
exportJsonKey: { person: { name: "$" } },
|
|
3832
4750
|
description: "A person",
|
|
3833
4751
|
format: TagFormat.plainText,
|
|
3834
4752
|
chain: [
|
|
@@ -3848,8 +4766,8 @@ var GROUPS = {
|
|
|
3848
4766
|
{
|
|
3849
4767
|
// Deprecated (parter renamed to person)
|
|
3850
4768
|
key: ConfigKey.property_partner,
|
|
3851
|
-
jsonKey: "
|
|
3852
|
-
exportJsonKey: {
|
|
4769
|
+
jsonKey: "person.name",
|
|
4770
|
+
exportJsonKey: { person: { name: "$" } },
|
|
3853
4771
|
description: "A partner",
|
|
3854
4772
|
format: TagFormat.plainText,
|
|
3855
4773
|
chain: [
|
|
@@ -3873,7 +4791,9 @@ var GROUPS = {
|
|
|
3873
4791
|
description: "Gap chain",
|
|
3874
4792
|
tags: [
|
|
3875
4793
|
{
|
|
3876
|
-
exportJsonKey: {
|
|
4794
|
+
exportJsonKey: {
|
|
4795
|
+
"@body-inline": { type: "gap", attrs: { solutions: ["$"] } }
|
|
4796
|
+
},
|
|
3877
4797
|
key: ConfigKey.tag_gap,
|
|
3878
4798
|
description: "The value of a gap in the content",
|
|
3879
4799
|
maxCount: Count.infinity,
|
|
@@ -3892,27 +4812,37 @@ var GROUPS = {
|
|
|
3892
4812
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3893
4813
|
},
|
|
3894
4814
|
{
|
|
4815
|
+
// BPG ExampleTagContentProcessor.ts:91-95 reads
|
|
4816
|
+
// `__solutionsAst[length - 1]` — the solution closest to the
|
|
4817
|
+
// `[@example]` tag at parse time. Our chain accumulator is built
|
|
4818
|
+
// incrementally (scope.rs `parent.merge` after each tag), so at
|
|
4819
|
+
// the moment `[@example]` fires, `solutions` only contains the
|
|
4820
|
+
// preceding `[_x]` entries — `[-1]` resolves to the closest one.
|
|
4821
|
+
// E.g. `[_cloze][_gap][@example]` → solutions=["cloze","gap"],
|
|
4822
|
+
// `[-1]`="gap"; `[_solution][@example][_problem]` →
|
|
4823
|
+
// solutions=["solution"], `[-1]`="solution".
|
|
3895
4824
|
key: ConfigKey.property_example,
|
|
3896
4825
|
jsonKey: "example",
|
|
3897
4826
|
exportJsonKey: [
|
|
3898
4827
|
{
|
|
3899
4828
|
"@keyonly": {
|
|
3900
4829
|
isExample: true,
|
|
3901
|
-
example: "$parent.solutions[
|
|
4830
|
+
example: "$parent.solutions[-1]",
|
|
3902
4831
|
"@bit": { isExample: true }
|
|
3903
4832
|
}
|
|
3904
4833
|
},
|
|
3905
4834
|
{
|
|
3906
4835
|
"@absent": {
|
|
3907
4836
|
isExample: true,
|
|
3908
|
-
example: "$parent.solutions[
|
|
4837
|
+
example: "$parent.solutions[-1]",
|
|
3909
4838
|
"@bit": { isExample: true }
|
|
3910
4839
|
}
|
|
3911
4840
|
},
|
|
3912
4841
|
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3913
4842
|
],
|
|
3914
4843
|
description: "An example for the gap",
|
|
3915
|
-
format: TagFormat.bitmarkText
|
|
4844
|
+
format: TagFormat.bitmarkText,
|
|
4845
|
+
nullable: true
|
|
3916
4846
|
},
|
|
3917
4847
|
{
|
|
3918
4848
|
key: ConfigKey.property_isCaseSensitive,
|
|
@@ -3961,6 +4891,99 @@ var GROUPS = {
|
|
|
3961
4891
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
3962
4892
|
},
|
|
3963
4893
|
{
|
|
4894
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.2: cascade-fired
|
|
4895
|
+
// `@example` from the bit header marks EVERY choice with
|
|
4896
|
+
// `isExample: true` (matches BPG output), but only the
|
|
4897
|
+
// FIRST correct choice gets `example: true` (BPG
|
|
4898
|
+
// `fillBooleanExample(..., firstCorrectOnly=true)`).
|
|
4899
|
+
//
|
|
4900
|
+
// Two `@absent` rules, picked first-match-wins:
|
|
4901
|
+
// 1. Verbose form gated on `@parent.isCorrect=true` with
|
|
4902
|
+
// `maxEmits:1` — fires once for the first correct.
|
|
4903
|
+
// 2. Plain `@absent` — fires on every remaining entry
|
|
4904
|
+
// (subsequent corrects and all incorrects), emitting
|
|
4905
|
+
// `isExample` only.
|
|
4906
|
+
// The `serialize_cards` cascade-counter scope holds the cap
|
|
4907
|
+
// across the whole cardset.
|
|
4908
|
+
// @card scope-shift writes choice-container isExample (e.g.
|
|
4909
|
+
// `quizzes[i].isExample`) — was previously provided by the
|
|
4910
|
+
// universal `bubble_is_example` post-walk, which was removed
|
|
4911
|
+
// in favour of explicit per-tag config. SYNTAX.md §8.
|
|
4912
|
+
key: ConfigKey.property_example,
|
|
4913
|
+
jsonKey: "example",
|
|
4914
|
+
exportJsonKey: [
|
|
4915
|
+
{
|
|
4916
|
+
"@keyonly": {
|
|
4917
|
+
isExample: true,
|
|
4918
|
+
example: "$parent.isCorrect",
|
|
4919
|
+
"@bit": { isExample: true },
|
|
4920
|
+
"@card": { isExample: true }
|
|
4921
|
+
}
|
|
4922
|
+
},
|
|
4923
|
+
{
|
|
4924
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
4925
|
+
maxEmits: 1,
|
|
4926
|
+
rule: {
|
|
4927
|
+
isExample: true,
|
|
4928
|
+
example: true,
|
|
4929
|
+
"@bit": { isExample: true },
|
|
4930
|
+
"@card": { isExample: true }
|
|
4931
|
+
}
|
|
4932
|
+
},
|
|
4933
|
+
{
|
|
4934
|
+
"@absent": {
|
|
4935
|
+
isExample: true,
|
|
4936
|
+
"@bit": { isExample: true },
|
|
4937
|
+
"@card": { isExample: true }
|
|
4938
|
+
}
|
|
4939
|
+
},
|
|
4940
|
+
{
|
|
4941
|
+
isExample: true,
|
|
4942
|
+
example: "$",
|
|
4943
|
+
"@bit": { isExample: true },
|
|
4944
|
+
"@card": { isExample: true }
|
|
4945
|
+
}
|
|
4946
|
+
],
|
|
4947
|
+
description: "An example for the true/false statement/question",
|
|
4948
|
+
format: TagFormat.boolean,
|
|
4949
|
+
nullable: true
|
|
4950
|
+
}
|
|
4951
|
+
]
|
|
4952
|
+
},
|
|
4953
|
+
{
|
|
4954
|
+
exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
|
|
4955
|
+
key: ConfigKey.tag_false,
|
|
4956
|
+
description: "False value for a true/false statement/question",
|
|
4957
|
+
maxCount: Count.infinity,
|
|
4958
|
+
format: TagFormat.plainText,
|
|
4959
|
+
chain: [
|
|
4960
|
+
{
|
|
4961
|
+
key: ConfigKey.tag_true,
|
|
4962
|
+
jsonKey: "choices[]|set(isCorrect=true)",
|
|
4963
|
+
exportJsonKey: { choices: [{ choice: "$", isCorrect: true }] },
|
|
4964
|
+
description: "True values for a true/false statement/question",
|
|
4965
|
+
maxCount: Count.infinity,
|
|
4966
|
+
format: TagFormat.plainText
|
|
4967
|
+
},
|
|
4968
|
+
{
|
|
4969
|
+
key: ConfigKey.tag_false,
|
|
4970
|
+
jsonKey: "choices[]|set(isCorrect=false)",
|
|
4971
|
+
exportJsonKey: { choices: [{ choice: "$", isCorrect: false }] },
|
|
4972
|
+
description: "False values for a true/false statement/question",
|
|
4973
|
+
maxCount: Count.infinity,
|
|
4974
|
+
format: TagFormat.plainText
|
|
4975
|
+
},
|
|
4976
|
+
{
|
|
4977
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
4978
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
4979
|
+
},
|
|
4980
|
+
{
|
|
4981
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.2: cascade-fired
|
|
4982
|
+
// `@example` on a `-` (incorrect choice) emits
|
|
4983
|
+
// `isExample: true` only — no `example` (BPG fixtures show
|
|
4984
|
+
// `isExample` on every choice, but `example` only on the
|
|
4985
|
+
// first correct via firstCorrectOnly cascade).
|
|
4986
|
+
// @card scope-shift writes choice-container isExample.
|
|
3964
4987
|
key: ConfigKey.property_example,
|
|
3965
4988
|
jsonKey: "example",
|
|
3966
4989
|
exportJsonKey: [
|
|
@@ -3968,25 +4991,99 @@ var GROUPS = {
|
|
|
3968
4991
|
"@keyonly": {
|
|
3969
4992
|
isExample: true,
|
|
3970
4993
|
example: "$parent.isCorrect",
|
|
3971
|
-
"@bit": { isExample: true }
|
|
4994
|
+
"@bit": { isExample: true },
|
|
4995
|
+
"@card": { isExample: true }
|
|
3972
4996
|
}
|
|
3973
4997
|
},
|
|
3974
4998
|
{
|
|
3975
4999
|
"@absent": {
|
|
5000
|
+
isExample: true,
|
|
5001
|
+
"@bit": { isExample: true },
|
|
5002
|
+
"@card": { isExample: true }
|
|
5003
|
+
}
|
|
5004
|
+
},
|
|
5005
|
+
{
|
|
5006
|
+
isExample: true,
|
|
5007
|
+
example: "$",
|
|
5008
|
+
"@bit": { isExample: true },
|
|
5009
|
+
"@card": { isExample: true }
|
|
5010
|
+
}
|
|
5011
|
+
],
|
|
5012
|
+
description: "An example for the true/false statement/question (incorrect entry \u2014 isExample only on cascade)",
|
|
5013
|
+
format: TagFormat.boolean,
|
|
5014
|
+
nullable: true
|
|
5015
|
+
}
|
|
5016
|
+
]
|
|
5017
|
+
}
|
|
5018
|
+
]
|
|
5019
|
+
},
|
|
5020
|
+
[ConfigKey.group_trueFalseResponses]: {
|
|
5021
|
+
type: GroupConfigType.standard,
|
|
5022
|
+
description: "True/False Responses chain",
|
|
5023
|
+
tags: [
|
|
5024
|
+
{
|
|
5025
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: true }] },
|
|
5026
|
+
key: ConfigKey.tag_true,
|
|
5027
|
+
description: "True value for a true/false statement/question",
|
|
5028
|
+
maxCount: Count.infinity,
|
|
5029
|
+
format: TagFormat.plainText,
|
|
5030
|
+
chain: [
|
|
5031
|
+
{
|
|
5032
|
+
key: ConfigKey.tag_true,
|
|
5033
|
+
jsonKey: "responses[]|set(isCorrect=true)",
|
|
5034
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: true }] },
|
|
5035
|
+
description: "True values for a true/false statement/question",
|
|
5036
|
+
maxCount: Count.infinity,
|
|
5037
|
+
format: TagFormat.plainText
|
|
5038
|
+
},
|
|
5039
|
+
{
|
|
5040
|
+
key: ConfigKey.tag_false,
|
|
5041
|
+
jsonKey: "responses[]|set(isCorrect=false)",
|
|
5042
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: false }] },
|
|
5043
|
+
description: "False values for a true/false statement/question",
|
|
5044
|
+
maxCount: Count.infinity,
|
|
5045
|
+
format: TagFormat.plainText
|
|
5046
|
+
},
|
|
5047
|
+
{
|
|
5048
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5049
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5050
|
+
},
|
|
5051
|
+
{
|
|
5052
|
+
// @card scope-shift writes response-container isExample.
|
|
5053
|
+
key: ConfigKey.property_example,
|
|
5054
|
+
jsonKey: "example",
|
|
5055
|
+
exportJsonKey: [
|
|
5056
|
+
{
|
|
5057
|
+
"@keyonly": {
|
|
3976
5058
|
isExample: true,
|
|
3977
5059
|
example: "$parent.isCorrect",
|
|
3978
|
-
"@bit": { isExample: true }
|
|
5060
|
+
"@bit": { isExample: true },
|
|
5061
|
+
"@card": { isExample: true }
|
|
3979
5062
|
}
|
|
3980
5063
|
},
|
|
3981
|
-
{
|
|
5064
|
+
{
|
|
5065
|
+
"@absent": {
|
|
5066
|
+
isExample: "$parent.isCorrect",
|
|
5067
|
+
example: "$parent.isCorrect",
|
|
5068
|
+
"@bit": { isExample: "$parent.isCorrect" },
|
|
5069
|
+
"@card": { isExample: "$parent.isCorrect" }
|
|
5070
|
+
}
|
|
5071
|
+
},
|
|
5072
|
+
{
|
|
5073
|
+
isExample: true,
|
|
5074
|
+
example: "$",
|
|
5075
|
+
"@bit": { isExample: true },
|
|
5076
|
+
"@card": { isExample: true }
|
|
5077
|
+
}
|
|
3982
5078
|
],
|
|
3983
5079
|
description: "An example for the true/false statement/question",
|
|
3984
|
-
format: TagFormat.
|
|
5080
|
+
format: TagFormat.boolean,
|
|
5081
|
+
nullable: true
|
|
3985
5082
|
}
|
|
3986
5083
|
]
|
|
3987
5084
|
},
|
|
3988
5085
|
{
|
|
3989
|
-
exportJsonKey: {
|
|
5086
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: false }] },
|
|
3990
5087
|
key: ConfigKey.tag_false,
|
|
3991
5088
|
description: "False value for a true/false statement/question",
|
|
3992
5089
|
maxCount: Count.infinity,
|
|
@@ -3994,16 +5091,16 @@ var GROUPS = {
|
|
|
3994
5091
|
chain: [
|
|
3995
5092
|
{
|
|
3996
5093
|
key: ConfigKey.tag_true,
|
|
3997
|
-
jsonKey: "
|
|
3998
|
-
exportJsonKey: {
|
|
5094
|
+
jsonKey: "responses[]|set(isCorrect=true)",
|
|
5095
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: true }] },
|
|
3999
5096
|
description: "True values for a true/false statement/question",
|
|
4000
5097
|
maxCount: Count.infinity,
|
|
4001
5098
|
format: TagFormat.plainText
|
|
4002
5099
|
},
|
|
4003
5100
|
{
|
|
4004
5101
|
key: ConfigKey.tag_false,
|
|
4005
|
-
jsonKey: "
|
|
4006
|
-
exportJsonKey: {
|
|
5102
|
+
jsonKey: "responses[]|set(isCorrect=false)",
|
|
5103
|
+
exportJsonKey: { responses: [{ response: "$", isCorrect: false }] },
|
|
4007
5104
|
description: "False values for a true/false statement/question",
|
|
4008
5105
|
maxCount: Count.infinity,
|
|
4009
5106
|
format: TagFormat.plainText
|
|
@@ -4013,6 +5110,7 @@ var GROUPS = {
|
|
|
4013
5110
|
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
4014
5111
|
},
|
|
4015
5112
|
{
|
|
5113
|
+
// @card scope-shift writes response-container isExample.
|
|
4016
5114
|
key: ConfigKey.property_example,
|
|
4017
5115
|
jsonKey: "example",
|
|
4018
5116
|
exportJsonKey: [
|
|
@@ -4020,20 +5118,333 @@ var GROUPS = {
|
|
|
4020
5118
|
"@keyonly": {
|
|
4021
5119
|
isExample: true,
|
|
4022
5120
|
example: "$parent.isCorrect",
|
|
4023
|
-
"@bit": { isExample: true }
|
|
5121
|
+
"@bit": { isExample: true },
|
|
5122
|
+
"@card": { isExample: true }
|
|
4024
5123
|
}
|
|
4025
5124
|
},
|
|
4026
5125
|
{
|
|
4027
5126
|
"@absent": {
|
|
4028
5127
|
isExample: true,
|
|
4029
5128
|
example: "$parent.isCorrect",
|
|
4030
|
-
"@bit": { isExample: true }
|
|
5129
|
+
"@bit": { isExample: true },
|
|
5130
|
+
"@card": { isExample: true }
|
|
4031
5131
|
}
|
|
4032
5132
|
},
|
|
4033
|
-
{
|
|
5133
|
+
{
|
|
5134
|
+
isExample: true,
|
|
5135
|
+
example: "$",
|
|
5136
|
+
"@bit": { isExample: true },
|
|
5137
|
+
"@card": { isExample: true }
|
|
5138
|
+
}
|
|
4034
5139
|
],
|
|
4035
5140
|
description: "An example for the true/false statement/question",
|
|
4036
|
-
format: TagFormat.
|
|
5141
|
+
format: TagFormat.boolean,
|
|
5142
|
+
nullable: true
|
|
5143
|
+
}
|
|
5144
|
+
]
|
|
5145
|
+
}
|
|
5146
|
+
]
|
|
5147
|
+
},
|
|
5148
|
+
[ConfigKey.group_trueFalseInlineSelect]: {
|
|
5149
|
+
type: GroupConfigType.standard,
|
|
5150
|
+
description: "True/False chain composed inline (select body-bit). +/- tags are consume-only at bit level.",
|
|
5151
|
+
tags: [
|
|
5152
|
+
{
|
|
5153
|
+
exportJsonKey: {
|
|
5154
|
+
"@body-inline": {
|
|
5155
|
+
type: "select",
|
|
5156
|
+
attrs: { options: [{ text: "$", isCorrect: true }] }
|
|
5157
|
+
}
|
|
5158
|
+
},
|
|
5159
|
+
key: ConfigKey.tag_true,
|
|
5160
|
+
description: "True value for an inline select body bit",
|
|
5161
|
+
maxCount: Count.infinity,
|
|
5162
|
+
format: TagFormat.plainText,
|
|
5163
|
+
chain: [
|
|
5164
|
+
{
|
|
5165
|
+
key: ConfigKey.tag_true,
|
|
5166
|
+
exportJsonKey: {},
|
|
5167
|
+
description: "True values for an inline select body bit",
|
|
5168
|
+
maxCount: Count.infinity,
|
|
5169
|
+
format: TagFormat.plainText
|
|
5170
|
+
},
|
|
5171
|
+
{
|
|
5172
|
+
key: ConfigKey.tag_false,
|
|
5173
|
+
exportJsonKey: {},
|
|
5174
|
+
description: "False values for an inline select body bit",
|
|
5175
|
+
maxCount: Count.infinity,
|
|
5176
|
+
format: TagFormat.plainText
|
|
5177
|
+
},
|
|
5178
|
+
{
|
|
5179
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5180
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5181
|
+
},
|
|
5182
|
+
{
|
|
5183
|
+
// PLAN-083: cascade-fired `@example` from bit header fires
|
|
5184
|
+
// `isExample:true, example:true` on the FIRST CORRECT option
|
|
5185
|
+
// only (BPG `fillBooleanExample(select.options,
|
|
5186
|
+
// firstCorrectOnly=true)`). Mirrors group_trueFalseInlineHighlight.
|
|
5187
|
+
// Every rule also bubbles `@bit:{isExample:true}` (idempotent
|
|
5188
|
+
// OR — any cascade ⇒ bit marked) and
|
|
5189
|
+
// `@body-inline:{attrs:{isExample:true}}` (node-level marker
|
|
5190
|
+
// on the select node).
|
|
5191
|
+
key: ConfigKey.property_example,
|
|
5192
|
+
jsonKey: "example",
|
|
5193
|
+
exportJsonKey: [
|
|
5194
|
+
{
|
|
5195
|
+
"@keyonly": {
|
|
5196
|
+
isExample: true,
|
|
5197
|
+
example: "$parent.isCorrect",
|
|
5198
|
+
"@bit": { isExample: true },
|
|
5199
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5200
|
+
}
|
|
5201
|
+
},
|
|
5202
|
+
{
|
|
5203
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5204
|
+
maxEmits: 1,
|
|
5205
|
+
rule: {
|
|
5206
|
+
isExample: true,
|
|
5207
|
+
example: true,
|
|
5208
|
+
"@bit": { isExample: true },
|
|
5209
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5210
|
+
}
|
|
5211
|
+
},
|
|
5212
|
+
{
|
|
5213
|
+
isExample: true,
|
|
5214
|
+
example: "$",
|
|
5215
|
+
"@bit": { isExample: true },
|
|
5216
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5217
|
+
}
|
|
5218
|
+
],
|
|
5219
|
+
description: "An example for the inline select option (first correct only)",
|
|
5220
|
+
format: TagFormat.boolean,
|
|
5221
|
+
nullable: true
|
|
5222
|
+
}
|
|
5223
|
+
]
|
|
5224
|
+
},
|
|
5225
|
+
{
|
|
5226
|
+
exportJsonKey: {
|
|
5227
|
+
"@body-inline": {
|
|
5228
|
+
type: "select",
|
|
5229
|
+
attrs: { options: [{ text: "$", isCorrect: false }] }
|
|
5230
|
+
}
|
|
5231
|
+
},
|
|
5232
|
+
key: ConfigKey.tag_false,
|
|
5233
|
+
description: "False value for an inline select body bit",
|
|
5234
|
+
maxCount: Count.infinity,
|
|
5235
|
+
format: TagFormat.plainText,
|
|
5236
|
+
chain: [
|
|
5237
|
+
{
|
|
5238
|
+
key: ConfigKey.tag_true,
|
|
5239
|
+
exportJsonKey: {},
|
|
5240
|
+
description: "True values for an inline select body bit",
|
|
5241
|
+
maxCount: Count.infinity,
|
|
5242
|
+
format: TagFormat.plainText
|
|
5243
|
+
},
|
|
5244
|
+
{
|
|
5245
|
+
key: ConfigKey.tag_false,
|
|
5246
|
+
exportJsonKey: {},
|
|
5247
|
+
description: "False values for an inline select body bit",
|
|
5248
|
+
maxCount: Count.infinity,
|
|
5249
|
+
format: TagFormat.plainText
|
|
5250
|
+
},
|
|
5251
|
+
{
|
|
5252
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5253
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5254
|
+
},
|
|
5255
|
+
{
|
|
5256
|
+
// PLAN-083: identical to the `+` lead's chain @example —
|
|
5257
|
+
// cascade reaches the first correct option regardless of
|
|
5258
|
+
// which lead (+/-) opens the chain. Every firing rule bubbles
|
|
5259
|
+
// `@bit:{isExample:true}` and `@body-inline:{attrs:{isExample:true}}`.
|
|
5260
|
+
key: ConfigKey.property_example,
|
|
5261
|
+
jsonKey: "example",
|
|
5262
|
+
exportJsonKey: [
|
|
5263
|
+
{
|
|
5264
|
+
"@keyonly": {
|
|
5265
|
+
isExample: true,
|
|
5266
|
+
example: "$parent.isCorrect",
|
|
5267
|
+
"@bit": { isExample: true },
|
|
5268
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5269
|
+
}
|
|
5270
|
+
},
|
|
5271
|
+
{
|
|
5272
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5273
|
+
maxEmits: 1,
|
|
5274
|
+
rule: {
|
|
5275
|
+
isExample: true,
|
|
5276
|
+
example: true,
|
|
5277
|
+
"@bit": { isExample: true },
|
|
5278
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5279
|
+
}
|
|
5280
|
+
},
|
|
5281
|
+
{
|
|
5282
|
+
isExample: true,
|
|
5283
|
+
example: "$",
|
|
5284
|
+
"@bit": { isExample: true },
|
|
5285
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5286
|
+
}
|
|
5287
|
+
],
|
|
5288
|
+
description: "An example for the inline select option (first correct only)",
|
|
5289
|
+
format: TagFormat.boolean,
|
|
5290
|
+
nullable: true
|
|
5291
|
+
}
|
|
5292
|
+
]
|
|
5293
|
+
}
|
|
5294
|
+
]
|
|
5295
|
+
},
|
|
5296
|
+
[ConfigKey.group_trueFalseInlineHighlight]: {
|
|
5297
|
+
type: GroupConfigType.standard,
|
|
5298
|
+
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.',
|
|
5299
|
+
tags: [
|
|
5300
|
+
{
|
|
5301
|
+
exportJsonKey: {
|
|
5302
|
+
"@body-inline": {
|
|
5303
|
+
type: "highlight",
|
|
5304
|
+
attrs: { texts: [{ text: "$", isCorrect: true }] }
|
|
5305
|
+
}
|
|
5306
|
+
},
|
|
5307
|
+
key: ConfigKey.tag_true,
|
|
5308
|
+
description: "Highlighted span in the body (correct)",
|
|
5309
|
+
maxCount: Count.infinity,
|
|
5310
|
+
format: TagFormat.plainText,
|
|
5311
|
+
chain: [
|
|
5312
|
+
{
|
|
5313
|
+
key: ConfigKey.tag_true,
|
|
5314
|
+
exportJsonKey: {},
|
|
5315
|
+
description: "Highlighted span values (correct)",
|
|
5316
|
+
maxCount: Count.infinity,
|
|
5317
|
+
format: TagFormat.plainText
|
|
5318
|
+
},
|
|
5319
|
+
{
|
|
5320
|
+
key: ConfigKey.tag_false,
|
|
5321
|
+
exportJsonKey: {},
|
|
5322
|
+
description: "Highlighted span values (incorrect)",
|
|
5323
|
+
maxCount: Count.infinity,
|
|
5324
|
+
format: TagFormat.plainText
|
|
5325
|
+
},
|
|
5326
|
+
{
|
|
5327
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5328
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5329
|
+
},
|
|
5330
|
+
{
|
|
5331
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.13: cascade-fired
|
|
5332
|
+
// `@example` from the bit header fires `example: true` +
|
|
5333
|
+
// `isExample: true` on the FIRST correct highlight only
|
|
5334
|
+
// (BPG `fillBooleanExample(highlight.texts,
|
|
5335
|
+
// firstCorrectOnly=true)`). Incorrect highlights get
|
|
5336
|
+
// nothing (unlike choices, the highlight-text fixture
|
|
5337
|
+
// shows no `isExample` on incorrect entries).
|
|
5338
|
+
key: ConfigKey.property_example,
|
|
5339
|
+
jsonKey: "example",
|
|
5340
|
+
exportJsonKey: [
|
|
5341
|
+
{
|
|
5342
|
+
"@keyonly": {
|
|
5343
|
+
isExample: true,
|
|
5344
|
+
example: "$parent.isCorrect",
|
|
5345
|
+
"@bit": { isExample: true },
|
|
5346
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5347
|
+
}
|
|
5348
|
+
},
|
|
5349
|
+
{
|
|
5350
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5351
|
+
maxEmits: 1,
|
|
5352
|
+
rule: {
|
|
5353
|
+
isExample: true,
|
|
5354
|
+
example: true,
|
|
5355
|
+
"@bit": { isExample: true },
|
|
5356
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5357
|
+
}
|
|
5358
|
+
},
|
|
5359
|
+
{
|
|
5360
|
+
isExample: true,
|
|
5361
|
+
example: "$",
|
|
5362
|
+
"@bit": { isExample: true },
|
|
5363
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5364
|
+
}
|
|
5365
|
+
],
|
|
5366
|
+
description: "An example for the highlighted span (first correct only)",
|
|
5367
|
+
format: TagFormat.boolean,
|
|
5368
|
+
nullable: true
|
|
5369
|
+
}
|
|
5370
|
+
]
|
|
5371
|
+
},
|
|
5372
|
+
{
|
|
5373
|
+
// PLAN-083 follow-up (2026-05-22): mirror the select `-` lead shape
|
|
5374
|
+
// by writing `isCorrect: false`. Without it, `$parent.isCorrect` in
|
|
5375
|
+
// chain-child @example rules resolves to ParentPathMissing for `-`
|
|
5376
|
+
// entries (e.g. `[-fish][@example]`), so the @keyonly rule falls
|
|
5377
|
+
// through and nothing fires. The natural-default strip removes
|
|
5378
|
+
// `isCorrect: false` from the final texts entries (matches fixture).
|
|
5379
|
+
exportJsonKey: {
|
|
5380
|
+
"@body-inline": {
|
|
5381
|
+
type: "highlight",
|
|
5382
|
+
attrs: { texts: [{ text: "$", isCorrect: false }] }
|
|
5383
|
+
}
|
|
5384
|
+
},
|
|
5385
|
+
key: ConfigKey.tag_false,
|
|
5386
|
+
description: "Highlighted span in the body (incorrect)",
|
|
5387
|
+
maxCount: Count.infinity,
|
|
5388
|
+
format: TagFormat.plainText,
|
|
5389
|
+
chain: [
|
|
5390
|
+
{
|
|
5391
|
+
key: ConfigKey.tag_true,
|
|
5392
|
+
exportJsonKey: {},
|
|
5393
|
+
description: "Highlighted span values (correct)",
|
|
5394
|
+
maxCount: Count.infinity,
|
|
5395
|
+
format: TagFormat.plainText
|
|
5396
|
+
},
|
|
5397
|
+
{
|
|
5398
|
+
key: ConfigKey.tag_false,
|
|
5399
|
+
exportJsonKey: {},
|
|
5400
|
+
description: "Highlighted span values (incorrect)",
|
|
5401
|
+
maxCount: Count.infinity,
|
|
5402
|
+
format: TagFormat.plainText
|
|
5403
|
+
},
|
|
5404
|
+
{
|
|
5405
|
+
key: ConfigKey.group_standardItemLeadInstructionHint,
|
|
5406
|
+
description: "Item, lead, page number, margin number, instruction and hint tags"
|
|
5407
|
+
},
|
|
5408
|
+
{
|
|
5409
|
+
// PLAN-072 + ALIGN-EXAMPLE-CASCADE §3.13: cascade-fired
|
|
5410
|
+
// `@example` on a `-` (incorrect highlight) emits nothing
|
|
5411
|
+
// (highlight-text fixture has no `isExample` on incorrect
|
|
5412
|
+
// entries; firstCorrectOnly cascade skips them entirely).
|
|
5413
|
+
// No `@absent` rule.
|
|
5414
|
+
// PLAN-083: identical to the `+` lead's chain @example —
|
|
5415
|
+
// cascade reaches the first correct option regardless of
|
|
5416
|
+
// which lead (+/-) opens the chain.
|
|
5417
|
+
key: ConfigKey.property_example,
|
|
5418
|
+
jsonKey: "example",
|
|
5419
|
+
exportJsonKey: [
|
|
5420
|
+
{
|
|
5421
|
+
"@keyonly": {
|
|
5422
|
+
isExample: true,
|
|
5423
|
+
example: "$parent.isCorrect",
|
|
5424
|
+
"@bit": { isExample: true },
|
|
5425
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5426
|
+
}
|
|
5427
|
+
},
|
|
5428
|
+
{
|
|
5429
|
+
predicates: ["@absent", { "@parent.isCorrect": true }],
|
|
5430
|
+
maxEmits: 1,
|
|
5431
|
+
rule: {
|
|
5432
|
+
isExample: true,
|
|
5433
|
+
example: true,
|
|
5434
|
+
"@bit": { isExample: true },
|
|
5435
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5436
|
+
}
|
|
5437
|
+
},
|
|
5438
|
+
{
|
|
5439
|
+
isExample: true,
|
|
5440
|
+
example: "$",
|
|
5441
|
+
"@bit": { isExample: true },
|
|
5442
|
+
"@body-inline": { attrs: { isExample: true } }
|
|
5443
|
+
}
|
|
5444
|
+
],
|
|
5445
|
+
description: "An example for the highlighted span (first correct only)",
|
|
5446
|
+
format: TagFormat.boolean,
|
|
5447
|
+
nullable: true
|
|
4037
5448
|
}
|
|
4038
5449
|
]
|
|
4039
5450
|
}
|
|
@@ -4046,7 +5457,11 @@ var GROUPS = {
|
|
|
4046
5457
|
{
|
|
4047
5458
|
key: ConfigKey.property_mark,
|
|
4048
5459
|
jsonKey: "marks.mark",
|
|
4049
|
-
|
|
5460
|
+
// `emphasis: 'underline'` is the per-entry default for mark
|
|
5461
|
+
// configs — mirrors the hardcoded default in BPG
|
|
5462
|
+
// `MarkConfigChainContentProcessor.ts:55-58`. Chained
|
|
5463
|
+
// `[@emphasis:…]` overrides via deep-merge into `marks[-1]`.
|
|
5464
|
+
exportJsonKey: { marks: [{ mark: "$", emphasis: "underline" }] },
|
|
4050
5465
|
description: "The mark configuration",
|
|
4051
5466
|
format: TagFormat.plainText,
|
|
4052
5467
|
maxCount: Count.infinity,
|
|
@@ -4070,7 +5485,9 @@ var GROUPS = {
|
|
|
4070
5485
|
description: "Mark chain",
|
|
4071
5486
|
tags: [
|
|
4072
5487
|
{
|
|
4073
|
-
exportJsonKey: {
|
|
5488
|
+
exportJsonKey: {
|
|
5489
|
+
"@body-inline": { type: "mark", attrs: { solution: "$" } }
|
|
5490
|
+
},
|
|
4074
5491
|
key: ConfigKey.tag_mark,
|
|
4075
5492
|
description: "The marked content",
|
|
4076
5493
|
maxCount: Count.infinity,
|
|
@@ -4079,19 +5496,30 @@ var GROUPS = {
|
|
|
4079
5496
|
{
|
|
4080
5497
|
key: ConfigKey.property_mark,
|
|
4081
5498
|
jsonKey: "mark",
|
|
5499
|
+
exportJsonKey: { mark: "$" },
|
|
4082
5500
|
description: "The mark configuration",
|
|
4083
5501
|
format: TagFormat.plainText
|
|
4084
5502
|
},
|
|
4085
5503
|
{
|
|
4086
5504
|
key: ConfigKey.property_example,
|
|
4087
5505
|
jsonKey: "example",
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
5506
|
+
// Per-mark `@example` is a boolean toggle. BPG's runtime
|
|
5507
|
+
// `ExampleTagContentProcessor.handleDefaultOnlyExample`
|
|
5508
|
+
// (lines 147-161) normalises ANY `[@example]` or
|
|
5509
|
+
// `[@example:V]` on a mark body-bit to
|
|
5510
|
+
// `__isDefaultExample=true, example=undefined`; the
|
|
5511
|
+
// downstream `toExample(_, _, defaultExample=true)` in
|
|
5512
|
+
// `BaseBuilder.ts:80-87` then emits `example: true`
|
|
5513
|
+
// regardless of source. Declare a single unconditional
|
|
5514
|
+
// boolean-shape rule so the exported schema matches that
|
|
5515
|
+
// runtime semantic instead of the misleading `example: $`
|
|
5516
|
+
// shape (which would only fire if `handleDefaultOnlyExample`
|
|
5517
|
+
// were removed). `@bit: {isExample: true}` cascades the
|
|
5518
|
+
// marker — but NOT the `example` value — to bit root.
|
|
5519
|
+
exportJsonKey: { isExample: true, example: true, "@bit": { isExample: true } },
|
|
4093
5520
|
description: "An example for the marked content",
|
|
4094
|
-
format: TagFormat.
|
|
5521
|
+
format: TagFormat.boolean,
|
|
5522
|
+
nullable: true
|
|
4095
5523
|
}
|
|
4096
5524
|
]
|
|
4097
5525
|
}
|
|
@@ -4520,6 +5948,42 @@ var GROUPS = {
|
|
|
4520
5948
|
}
|
|
4521
5949
|
]
|
|
4522
5950
|
},
|
|
5951
|
+
[ConfigKey.group_backgroundWallpaper]: {
|
|
5952
|
+
type: GroupConfigType.standard,
|
|
5953
|
+
description: "Background wallpaper tags",
|
|
5954
|
+
tags: [
|
|
5955
|
+
{
|
|
5956
|
+
key: ConfigKey.resource_backgroundWallpaper,
|
|
5957
|
+
exportJsonKey: { backgroundWallpaper: { type: "image", image: { src: "$" } } },
|
|
5958
|
+
description: "Background wallpaper for the image, used to set a background for the image",
|
|
5959
|
+
chain: [
|
|
5960
|
+
{
|
|
5961
|
+
key: ConfigKey.group_resourceImageCommon,
|
|
5962
|
+
description: "Common resource image tags for images"
|
|
5963
|
+
}
|
|
5964
|
+
]
|
|
5965
|
+
}
|
|
5966
|
+
]
|
|
5967
|
+
},
|
|
5968
|
+
[ConfigKey.group_imageNoZoom]: {
|
|
5969
|
+
type: GroupConfigType.standard,
|
|
5970
|
+
description: "Image bit tags",
|
|
5971
|
+
tags: [
|
|
5972
|
+
{
|
|
5973
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
5974
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
5975
|
+
},
|
|
5976
|
+
{
|
|
5977
|
+
key: ConfigKey.group_resourceBitTags,
|
|
5978
|
+
description: "Resource bit tags for images, used to define additional properties for images"
|
|
5979
|
+
},
|
|
5980
|
+
{
|
|
5981
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
5982
|
+
description: "Resource image tags for images, used to attach images to the bit",
|
|
5983
|
+
minCount: 1
|
|
5984
|
+
}
|
|
5985
|
+
]
|
|
5986
|
+
},
|
|
4523
5987
|
//
|
|
4524
5988
|
// Resource groups
|
|
4525
5989
|
//
|
|
@@ -4639,6 +6103,58 @@ var GROUPS = {
|
|
|
4639
6103
|
}
|
|
4640
6104
|
]
|
|
4641
6105
|
},
|
|
6106
|
+
[ConfigKey.group_resourceImageCommonNoZoom]: {
|
|
6107
|
+
type: GroupConfigType.standard,
|
|
6108
|
+
description: "Common properties for image resources where @zoomDisabled defaults to true",
|
|
6109
|
+
tags: [
|
|
6110
|
+
{
|
|
6111
|
+
key: ConfigKey.group_resourceCommon,
|
|
6112
|
+
description: "Common resource properties"
|
|
6113
|
+
},
|
|
6114
|
+
{
|
|
6115
|
+
key: ConfigKey.property_src1x,
|
|
6116
|
+
description: "The source URL for the image at 1x resolution",
|
|
6117
|
+
format: TagFormat.plainText
|
|
6118
|
+
},
|
|
6119
|
+
{
|
|
6120
|
+
key: ConfigKey.property_src2x,
|
|
6121
|
+
description: "The source URL for the image at 2x resolution",
|
|
6122
|
+
format: TagFormat.plainText
|
|
6123
|
+
},
|
|
6124
|
+
{
|
|
6125
|
+
key: ConfigKey.property_src3x,
|
|
6126
|
+
description: "The source URL for the image at 3x resolution",
|
|
6127
|
+
format: TagFormat.plainText
|
|
6128
|
+
},
|
|
6129
|
+
{
|
|
6130
|
+
key: ConfigKey.property_src4x,
|
|
6131
|
+
description: "The source URL for the image at 4x resolution",
|
|
6132
|
+
format: TagFormat.plainText
|
|
6133
|
+
},
|
|
6134
|
+
{
|
|
6135
|
+
key: ConfigKey.property_width,
|
|
6136
|
+
description: "The width of the image",
|
|
6137
|
+
format: TagFormat.number
|
|
6138
|
+
},
|
|
6139
|
+
{
|
|
6140
|
+
key: ConfigKey.property_height,
|
|
6141
|
+
description: "The height of the image",
|
|
6142
|
+
format: TagFormat.number
|
|
6143
|
+
},
|
|
6144
|
+
{
|
|
6145
|
+
key: ConfigKey.property_alt,
|
|
6146
|
+
description: "The alternative text for the image",
|
|
6147
|
+
format: TagFormat.plainText
|
|
6148
|
+
},
|
|
6149
|
+
// @zoomDisabled with a true default
|
|
6150
|
+
{
|
|
6151
|
+
key: ConfigKey.property_zoomDisabled,
|
|
6152
|
+
description: "If true, zooming is disabled for the image (defaults to true)",
|
|
6153
|
+
format: TagFormat.boolean,
|
|
6154
|
+
defaultValue: "true"
|
|
6155
|
+
}
|
|
6156
|
+
]
|
|
6157
|
+
},
|
|
4642
6158
|
[ConfigKey.group_resourceAudioCommon]: {
|
|
4643
6159
|
type: GroupConfigType.standard,
|
|
4644
6160
|
description: "Common properties for audio resources",
|
|
@@ -4728,22 +6244,26 @@ var GROUPS = {
|
|
|
4728
6244
|
{
|
|
4729
6245
|
key: ConfigKey.property_src1x,
|
|
4730
6246
|
description: "The source URL for the video at 1x resolution",
|
|
4731
|
-
format: TagFormat.plainText
|
|
6247
|
+
format: TagFormat.plainText,
|
|
6248
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4732
6249
|
},
|
|
4733
6250
|
{
|
|
4734
6251
|
key: ConfigKey.property_src2x,
|
|
4735
6252
|
description: "The source URL for the video at 2x resolution",
|
|
4736
|
-
format: TagFormat.plainText
|
|
6253
|
+
format: TagFormat.plainText,
|
|
6254
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4737
6255
|
},
|
|
4738
6256
|
{
|
|
4739
6257
|
key: ConfigKey.property_src3x,
|
|
4740
6258
|
description: "The source URL for the video at 3x resolution",
|
|
4741
|
-
format: TagFormat.plainText
|
|
6259
|
+
format: TagFormat.plainText,
|
|
6260
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4742
6261
|
},
|
|
4743
6262
|
{
|
|
4744
6263
|
key: ConfigKey.property_src4x,
|
|
4745
6264
|
description: "The source URL for the video at 4x resolution",
|
|
4746
|
-
format: TagFormat.plainText
|
|
6265
|
+
format: TagFormat.plainText,
|
|
6266
|
+
exportJsonKey: { thumbnails: [{ src: "$" }] }
|
|
4747
6267
|
}
|
|
4748
6268
|
]
|
|
4749
6269
|
},
|
|
@@ -4756,6 +6276,7 @@ var GROUPS = {
|
|
|
4756
6276
|
tags: [
|
|
4757
6277
|
{
|
|
4758
6278
|
key: ConfigKey.resource_icon,
|
|
6279
|
+
exportJsonKey: { resource: { type: "icon", icon: { src: "$" } } },
|
|
4759
6280
|
description: "The icon resource",
|
|
4760
6281
|
chain: [
|
|
4761
6282
|
{
|
|
@@ -4783,12 +6304,30 @@ var GROUPS = {
|
|
|
4783
6304
|
}
|
|
4784
6305
|
]
|
|
4785
6306
|
},
|
|
6307
|
+
[ConfigKey.group_resourceImageNoZoom]: {
|
|
6308
|
+
type: GroupConfigType.resource,
|
|
6309
|
+
description: "Image resource where @zoomDisabled defaults to true",
|
|
6310
|
+
tags: [
|
|
6311
|
+
{
|
|
6312
|
+
key: ConfigKey.resource_image,
|
|
6313
|
+
exportJsonKey: { resource: { type: "image", image: { src: "$" } } },
|
|
6314
|
+
description: "The image resource (no-zoom default)",
|
|
6315
|
+
chain: [
|
|
6316
|
+
{
|
|
6317
|
+
key: ConfigKey.group_resourceImageCommonNoZoom,
|
|
6318
|
+
description: "Common image properties with @zoomDisabled defaulting to true"
|
|
6319
|
+
}
|
|
6320
|
+
]
|
|
6321
|
+
}
|
|
6322
|
+
]
|
|
6323
|
+
},
|
|
4786
6324
|
[ConfigKey.group_resourceImagePortrait]: {
|
|
4787
6325
|
type: GroupConfigType.resource,
|
|
4788
6326
|
description: "Portrait image resource",
|
|
4789
6327
|
tags: [
|
|
4790
6328
|
{
|
|
4791
6329
|
key: ConfigKey.resource_imagePortrait,
|
|
6330
|
+
exportJsonKey: { resource: { type: "image-portrait", imagePortrait: { src: "$" } } },
|
|
4792
6331
|
description: "The portrait image resource",
|
|
4793
6332
|
chain: [
|
|
4794
6333
|
{
|
|
@@ -4805,6 +6344,7 @@ var GROUPS = {
|
|
|
4805
6344
|
tags: [
|
|
4806
6345
|
{
|
|
4807
6346
|
key: ConfigKey.resource_imageLandscape,
|
|
6347
|
+
exportJsonKey: { resource: { type: "image-landscape", imageLandscape: { src: "$" } } },
|
|
4808
6348
|
description: "The landscape image resource",
|
|
4809
6349
|
chain: [
|
|
4810
6350
|
{
|
|
@@ -4821,6 +6361,7 @@ var GROUPS = {
|
|
|
4821
6361
|
tags: [
|
|
4822
6362
|
{
|
|
4823
6363
|
key: ConfigKey.resource_imageEmbed,
|
|
6364
|
+
exportJsonKey: { resource: { type: "image-embed", imageEmbed: { src: "$" } } },
|
|
4824
6365
|
description: "The embedded image resource",
|
|
4825
6366
|
chain: [
|
|
4826
6367
|
{
|
|
@@ -4994,6 +6535,7 @@ var GROUPS = {
|
|
|
4994
6535
|
tags: [
|
|
4995
6536
|
{
|
|
4996
6537
|
key: ConfigKey.resource_article,
|
|
6538
|
+
exportJsonKey: { resource: { type: "article", article: { body: "$" } } },
|
|
4997
6539
|
description: "The article resource",
|
|
4998
6540
|
chain: [
|
|
4999
6541
|
{
|
|
@@ -5010,6 +6552,7 @@ var GROUPS = {
|
|
|
5010
6552
|
tags: [
|
|
5011
6553
|
{
|
|
5012
6554
|
key: ConfigKey.resource_articleEmbed,
|
|
6555
|
+
exportJsonKey: { resource: { type: "article-embed", articleEmbed: { url: "$" } } },
|
|
5013
6556
|
description: "The embedded article resource",
|
|
5014
6557
|
chain: [
|
|
5015
6558
|
{
|
|
@@ -5026,6 +6569,7 @@ var GROUPS = {
|
|
|
5026
6569
|
tags: [
|
|
5027
6570
|
{
|
|
5028
6571
|
key: ConfigKey.resource_articleLink,
|
|
6572
|
+
exportJsonKey: { resource: { type: "article-link", articleLink: { url: "$" } } },
|
|
5029
6573
|
description: "The link to the article resource",
|
|
5030
6574
|
chain: [
|
|
5031
6575
|
{
|
|
@@ -5296,7 +6840,12 @@ var ConfigHydrator = class {
|
|
|
5296
6840
|
isDefault: v.isDefault,
|
|
5297
6841
|
sideJsonKey: v.sideJsonKey,
|
|
5298
6842
|
sideExportJsonKey: v.sideExportJsonKey,
|
|
5299
|
-
hasSideExportJsonKey: Object.prototype.hasOwnProperty.call(v, "sideExportJsonKey")
|
|
6843
|
+
hasSideExportJsonKey: Object.prototype.hasOwnProperty.call(v, "sideExportJsonKey"),
|
|
6844
|
+
// PLAN-085: cardinality fields pass through; defaults applied
|
|
6845
|
+
// downstream by the config consumer (Rust treats `0` / undefined
|
|
6846
|
+
// as unbounded).
|
|
6847
|
+
minCount: v.minCount,
|
|
6848
|
+
maxCount: v.maxCount
|
|
5300
6849
|
};
|
|
5301
6850
|
}
|
|
5302
6851
|
return out;
|
|
@@ -5511,7 +7060,8 @@ var BITS = {
|
|
|
5511
7060
|
{ isExample: true, example: "$" }
|
|
5512
7061
|
],
|
|
5513
7062
|
description: "The example text for the bit",
|
|
5514
|
-
format: TagFormat.plainText
|
|
7063
|
+
format: TagFormat.plainText,
|
|
7064
|
+
nullable: true
|
|
5515
7065
|
}
|
|
5516
7066
|
],
|
|
5517
7067
|
rootExampleType: ExampleType.string
|
|
@@ -5850,7 +7400,8 @@ var BITS = {
|
|
|
5850
7400
|
{ isExample: true, example: "$" }
|
|
5851
7401
|
],
|
|
5852
7402
|
description: "The example text for the bit",
|
|
5853
|
-
format: TagFormat.plainText
|
|
7403
|
+
format: TagFormat.plainText,
|
|
7404
|
+
nullable: true
|
|
5854
7405
|
}
|
|
5855
7406
|
],
|
|
5856
7407
|
rootExampleType: ExampleType.string
|
|
@@ -6013,7 +7564,8 @@ var BITS = {
|
|
|
6013
7564
|
{ isExample: true, example: "$" }
|
|
6014
7565
|
],
|
|
6015
7566
|
description: "The example text for the bit",
|
|
6016
|
-
format: TagFormat.plainText
|
|
7567
|
+
format: TagFormat.plainText,
|
|
7568
|
+
nullable: true
|
|
6017
7569
|
}
|
|
6018
7570
|
],
|
|
6019
7571
|
rootExampleType: ExampleType.string
|
|
@@ -6164,7 +7716,8 @@ var BITS = {
|
|
|
6164
7716
|
{ isExample: true, example: "$" }
|
|
6165
7717
|
],
|
|
6166
7718
|
description: "The example text for the bit",
|
|
6167
|
-
format: TagFormat.plainText
|
|
7719
|
+
format: TagFormat.plainText,
|
|
7720
|
+
nullable: true
|
|
6168
7721
|
}
|
|
6169
7722
|
],
|
|
6170
7723
|
rootExampleType: ExampleType.string
|
|
@@ -6741,6 +8294,12 @@ var BITS = {
|
|
|
6741
8294
|
description: "The progress of the chapter, used for tracking reading progress",
|
|
6742
8295
|
format: TagFormat.boolean,
|
|
6743
8296
|
defaultValue: "true"
|
|
8297
|
+
},
|
|
8298
|
+
{
|
|
8299
|
+
key: ConfigKey.property_isCollapsible,
|
|
8300
|
+
description: "If true, the chapter is collapsible",
|
|
8301
|
+
format: TagFormat.boolean,
|
|
8302
|
+
defaultValue: "false"
|
|
6744
8303
|
}
|
|
6745
8304
|
]
|
|
6746
8305
|
},
|
|
@@ -6759,8 +8318,31 @@ var BITS = {
|
|
|
6759
8318
|
description: "Tags for gaps in cloze and multiple choice text bits"
|
|
6760
8319
|
},
|
|
6761
8320
|
{
|
|
6762
|
-
key: ConfigKey.
|
|
8321
|
+
key: ConfigKey.group_trueFalseInlineSelect,
|
|
6763
8322
|
description: "Tags for true/false questions in cloze and multiple choice text bits"
|
|
8323
|
+
},
|
|
8324
|
+
{
|
|
8325
|
+
// Bit-level @isCaseSensitive — empty exportJsonKey (no bit-level emission);
|
|
8326
|
+
// defaultValue 'true' phantom-fires onto the ancestor stack so the gap chain's
|
|
8327
|
+
// `@absent: $ancestor` rule resolves to true. Mirrors BPG Builder.ts:1643-1652
|
|
8328
|
+
// `pushDownTree(... 'isCaseSensitive', data.isCaseSensitive ?? true)` for cloze bits.
|
|
8329
|
+
key: ConfigKey.property_isCaseSensitive,
|
|
8330
|
+
exportJsonKey: {},
|
|
8331
|
+
description: "If the cloze answers are case sensitive",
|
|
8332
|
+
format: TagFormat.boolean,
|
|
8333
|
+
defaultValue: "true"
|
|
8334
|
+
},
|
|
8335
|
+
{
|
|
8336
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
8337
|
+
key: ConfigKey.property_example,
|
|
8338
|
+
exportJsonKey: [
|
|
8339
|
+
{ "@keyonly": { isExample: true } },
|
|
8340
|
+
{ "@absent": { isExample: true } },
|
|
8341
|
+
{ isExample: true, example: "$" }
|
|
8342
|
+
],
|
|
8343
|
+
description: "The example(s) for the bit",
|
|
8344
|
+
format: TagFormat.bitmarkText,
|
|
8345
|
+
nullable: true
|
|
6764
8346
|
}
|
|
6765
8347
|
]
|
|
6766
8348
|
},
|
|
@@ -6799,18 +8381,56 @@ var BITS = {
|
|
|
6799
8381
|
{
|
|
6800
8382
|
key: ConfigKey.group_gap,
|
|
6801
8383
|
description: "Tags for gaps in cloze bits"
|
|
8384
|
+
},
|
|
8385
|
+
{
|
|
8386
|
+
// Override inherited @example: cloze is in OLD parser's
|
|
8387
|
+
// `isTopLevelExample` allow-list, so [@example] at bit-header
|
|
8388
|
+
// emits `isExample: true`.
|
|
8389
|
+
key: ConfigKey.property_example,
|
|
8390
|
+
exportJsonKey: [
|
|
8391
|
+
{ "@keyonly": { isExample: true } },
|
|
8392
|
+
{ "@absent": { isExample: true } },
|
|
8393
|
+
{ isExample: true, example: "$" }
|
|
8394
|
+
],
|
|
8395
|
+
description: "The example(s) for the bit",
|
|
8396
|
+
format: TagFormat.bitmarkText,
|
|
8397
|
+
nullable: true
|
|
6802
8398
|
}
|
|
6803
8399
|
]
|
|
6804
8400
|
},
|
|
6805
8401
|
[BitType2.clozeInstructionGrouped]: {
|
|
6806
8402
|
since: "1.3.0",
|
|
6807
8403
|
baseBitType: BitType2.cloze,
|
|
6808
|
-
description: "Cloze instruction grouped bit, used for cloze questions with grouped instructions"
|
|
8404
|
+
description: "Cloze instruction grouped bit, used for cloze questions with grouped instructions",
|
|
8405
|
+
tags: [
|
|
8406
|
+
{
|
|
8407
|
+
key: ConfigKey.property_quizCountItems,
|
|
8408
|
+
description: "The number of items in the cloze quiz (instruction-grouped default: true)",
|
|
8409
|
+
format: TagFormat.boolean,
|
|
8410
|
+
defaultValue: "true"
|
|
8411
|
+
}
|
|
8412
|
+
// Note: quizStrikethroughSolutions defaults to false for instruction-grouped per OLD
|
|
8413
|
+
// JsonGenerator.ts:1689-1690, which equals the Boolean natural default → no override needed.
|
|
8414
|
+
]
|
|
6809
8415
|
},
|
|
6810
8416
|
[BitType2.clozeSolutionGrouped]: {
|
|
6811
8417
|
since: "1.3.0",
|
|
6812
8418
|
baseBitType: BitType2.cloze,
|
|
6813
|
-
description: "Cloze solution grouped bit, used for cloze questions with grouped solutions"
|
|
8419
|
+
description: "Cloze solution grouped bit, used for cloze questions with grouped solutions",
|
|
8420
|
+
tags: [
|
|
8421
|
+
{
|
|
8422
|
+
key: ConfigKey.property_quizCountItems,
|
|
8423
|
+
description: "The number of items in the cloze quiz (solution-grouped default: true)",
|
|
8424
|
+
format: TagFormat.boolean,
|
|
8425
|
+
defaultValue: "true"
|
|
8426
|
+
},
|
|
8427
|
+
{
|
|
8428
|
+
key: ConfigKey.property_quizStrikethroughSolutions,
|
|
8429
|
+
description: "If the cloze solutions should be strikethrough (solution-grouped default: true)",
|
|
8430
|
+
format: TagFormat.boolean,
|
|
8431
|
+
defaultValue: "true"
|
|
8432
|
+
}
|
|
8433
|
+
]
|
|
6814
8434
|
},
|
|
6815
8435
|
[BitType2.clozeSeveral]: {
|
|
6816
8436
|
since: "3.5.0",
|
|
@@ -6846,6 +8466,17 @@ var BITS = {
|
|
|
6846
8466
|
{
|
|
6847
8467
|
key: ConfigKey.group_quizCommon,
|
|
6848
8468
|
description: "Common tags for quiz bits"
|
|
8469
|
+
},
|
|
8470
|
+
{
|
|
8471
|
+
// PLAN-084 (R12): bit-level @isCaseSensitive — empty exportJsonKey
|
|
8472
|
+
// (no bit-level emission); defaultValue 'true' phantom-fires onto
|
|
8473
|
+
// the ancestor stack so each listItem's gap chain `@absent: $ancestor`
|
|
8474
|
+
// rule resolves to true. Mirrors the cloze bit (bits.ts:1326-1336).
|
|
8475
|
+
key: ConfigKey.property_isCaseSensitive,
|
|
8476
|
+
exportJsonKey: {},
|
|
8477
|
+
description: "If the cloze answers are case sensitive",
|
|
8478
|
+
format: TagFormat.boolean,
|
|
8479
|
+
defaultValue: "true"
|
|
6849
8480
|
}
|
|
6850
8481
|
],
|
|
6851
8482
|
cardSet: CardSetConfigKey.clozeList
|
|
@@ -7012,6 +8643,7 @@ var BITS = {
|
|
|
7012
8643
|
tags: [
|
|
7013
8644
|
{
|
|
7014
8645
|
key: ConfigKey.group_person,
|
|
8646
|
+
exportJsonKey: { partner: { name: "$" } },
|
|
7015
8647
|
description: "Tags for the person in the conversation"
|
|
7016
8648
|
}
|
|
7017
8649
|
]
|
|
@@ -7442,7 +9074,12 @@ var BITS = {
|
|
|
7442
9074
|
maxCount: Count.infinity
|
|
7443
9075
|
},
|
|
7444
9076
|
{
|
|
7445
|
-
// Override inherited @example from group_standardTags:
|
|
9077
|
+
// Override inherited @example from group_standardTags: emits both
|
|
9078
|
+
// `isExample` (bool) AND `example` (paragraph array). Declared as
|
|
9079
|
+
// bitmarkText because BPG `JsonGenerator.toExample` renders the
|
|
9080
|
+
// root-example value through the bit's textFormat (not this tag's
|
|
9081
|
+
// declared format) — `TagFormat.plainText` here would be ignored
|
|
9082
|
+
// at runtime and is misleading.
|
|
7446
9083
|
key: ConfigKey.property_example,
|
|
7447
9084
|
exportJsonKey: [
|
|
7448
9085
|
{ "@keyonly": { isExample: true, example: "true" } },
|
|
@@ -7450,7 +9087,8 @@ var BITS = {
|
|
|
7450
9087
|
{ isExample: true, example: "$" }
|
|
7451
9088
|
],
|
|
7452
9089
|
description: "The example text for the essay bit",
|
|
7453
|
-
format: TagFormat.
|
|
9090
|
+
format: TagFormat.bitmarkText,
|
|
9091
|
+
nullable: true
|
|
7454
9092
|
}
|
|
7455
9093
|
],
|
|
7456
9094
|
rootExampleType: ExampleType.string
|
|
@@ -7484,7 +9122,8 @@ var BITS = {
|
|
|
7484
9122
|
{ isExample: true, example: "$" }
|
|
7485
9123
|
],
|
|
7486
9124
|
description: "The example text for the example bit",
|
|
7487
|
-
format: TagFormat.plainText
|
|
9125
|
+
format: TagFormat.plainText,
|
|
9126
|
+
nullable: true
|
|
7488
9127
|
}
|
|
7489
9128
|
],
|
|
7490
9129
|
rootExampleType: ExampleType.string
|
|
@@ -7570,7 +9209,19 @@ var BITS = {
|
|
|
7570
9209
|
[BitType2.articleAi]: {
|
|
7571
9210
|
since: "1.3.0",
|
|
7572
9211
|
baseBitType: BitType2.article,
|
|
7573
|
-
description: "Article AI bit, used to create AI-generated articles"
|
|
9212
|
+
description: "Article AI bit, used to create AI-generated articles",
|
|
9213
|
+
tags: [
|
|
9214
|
+
{
|
|
9215
|
+
// Shadows the inherited @aiGenerated from the standard group: this
|
|
9216
|
+
// bit type forces aiGenerated:true regardless of source value or
|
|
9217
|
+
// absence. Literal `true` in the export pattern ignores `$`.
|
|
9218
|
+
key: ConfigKey.property_aiGenerated,
|
|
9219
|
+
description: "AI-generated flag, forced true for article-ai bits",
|
|
9220
|
+
format: TagFormat.boolean,
|
|
9221
|
+
defaultValue: "true",
|
|
9222
|
+
exportJsonKey: { aiGenerated: true }
|
|
9223
|
+
}
|
|
9224
|
+
]
|
|
7574
9225
|
},
|
|
7575
9226
|
[BitType2.articleAttachment]: {
|
|
7576
9227
|
since: "1.3.0",
|
|
@@ -7895,7 +9546,19 @@ var BITS = {
|
|
|
7895
9546
|
[BitType2.noteAi]: {
|
|
7896
9547
|
since: "1.3.0",
|
|
7897
9548
|
baseBitType: BitType2.note,
|
|
7898
|
-
description: "Note AI bit, used to create AI-generated notes in articles or books"
|
|
9549
|
+
description: "Note AI bit, used to create AI-generated notes in articles or books",
|
|
9550
|
+
tags: [
|
|
9551
|
+
{
|
|
9552
|
+
// Shadows the inherited @aiGenerated from the standard group: this
|
|
9553
|
+
// bit type forces aiGenerated:true regardless of source value or
|
|
9554
|
+
// absence. Literal `true` in the export pattern ignores `$`.
|
|
9555
|
+
key: ConfigKey.property_aiGenerated,
|
|
9556
|
+
description: "AI-generated flag, forced true for article-ai bits",
|
|
9557
|
+
format: TagFormat.boolean,
|
|
9558
|
+
defaultValue: "true",
|
|
9559
|
+
exportJsonKey: { aiGenerated: true }
|
|
9560
|
+
}
|
|
9561
|
+
]
|
|
7899
9562
|
},
|
|
7900
9563
|
[BitType2.notebookArticle]: {
|
|
7901
9564
|
since: "1.3.0",
|
|
@@ -8020,7 +9683,19 @@ var BITS = {
|
|
|
8020
9683
|
[BitType2.summaryAi]: {
|
|
8021
9684
|
since: "1.3.0",
|
|
8022
9685
|
baseBitType: BitType2.summary,
|
|
8023
|
-
description: "AI-generated summary bit"
|
|
9686
|
+
description: "AI-generated summary bit",
|
|
9687
|
+
tags: [
|
|
9688
|
+
{
|
|
9689
|
+
// Shadows the inherited @aiGenerated from the standard group: this
|
|
9690
|
+
// bit type forces aiGenerated:true regardless of source value or
|
|
9691
|
+
// absence. Literal `true` in the export pattern ignores `$`.
|
|
9692
|
+
key: ConfigKey.property_aiGenerated,
|
|
9693
|
+
description: "AI-generated flag, forced true for article-ai bits",
|
|
9694
|
+
format: TagFormat.boolean,
|
|
9695
|
+
defaultValue: "true",
|
|
9696
|
+
exportJsonKey: { aiGenerated: true }
|
|
9697
|
+
}
|
|
9698
|
+
]
|
|
8024
9699
|
},
|
|
8025
9700
|
[BitType2.videoTranscript]: {
|
|
8026
9701
|
since: "1.3.0",
|
|
@@ -8294,7 +9969,7 @@ var BITS = {
|
|
|
8294
9969
|
description: "Product ID for the module product, used to link to a specific product",
|
|
8295
9970
|
format: TagFormat.plainText,
|
|
8296
9971
|
minCount: 1,
|
|
8297
|
-
maxCount:
|
|
9972
|
+
maxCount: 1
|
|
8298
9973
|
}
|
|
8299
9974
|
]
|
|
8300
9975
|
},
|
|
@@ -8347,10 +10022,13 @@ var BITS = {
|
|
|
8347
10022
|
description: "Resource bit tags for logo grave images, used to define additional properties"
|
|
8348
10023
|
},
|
|
8349
10024
|
{
|
|
8350
|
-
// Image resource
|
|
8351
|
-
|
|
10025
|
+
// Image resource — fully-expanded shape so each `&image` emission
|
|
10026
|
+
// produces a complete `{type, image: {src}}` object inside the
|
|
10027
|
+
// `images[]` array. Chain attrs like `[@zoomDisabled]` fold under
|
|
10028
|
+
// `images[].image` via the `[]` last-element-merge semantic.
|
|
10029
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
8352
10030
|
description: "Resource image tags for logo grave images, used to attach images",
|
|
8353
|
-
exportJsonKey: { images: "$" },
|
|
10031
|
+
exportJsonKey: { images: [{ type: "image", image: { src: "$" } }] },
|
|
8354
10032
|
minCount: 1,
|
|
8355
10033
|
maxCount: Count.infinity
|
|
8356
10034
|
}
|
|
@@ -8640,6 +10318,10 @@ var BITS = {
|
|
|
8640
10318
|
tags: [
|
|
8641
10319
|
{
|
|
8642
10320
|
key: ConfigKey.property_book,
|
|
10321
|
+
// Starter-array shape: each `[@book:value]` chain appends a fresh
|
|
10322
|
+
// `{ book, reference }` entry. The chained `►` (tag_reference) lands
|
|
10323
|
+
// inside the most-recently-appended entry as `reference: $`.
|
|
10324
|
+
exportJsonKey: { book: [{ book: "$" }] },
|
|
8643
10325
|
description: "Book reference for the page, used to link to a specific book",
|
|
8644
10326
|
maxCount: Count.infinity,
|
|
8645
10327
|
chain: [
|
|
@@ -8707,7 +10389,9 @@ var BITS = {
|
|
|
8707
10389
|
format: TagFormat.plainText
|
|
8708
10390
|
}
|
|
8709
10391
|
],
|
|
8710
|
-
|
|
10392
|
+
// page-footer emits cards under `sections` (vs `listItems` for the
|
|
10393
|
+
// sibling exampleList / assignmentList bits) — see JsonGenerator.ts.
|
|
10394
|
+
cardSet: CardSetConfigKey.pageFooterSections
|
|
8711
10395
|
},
|
|
8712
10396
|
[BitType2.legend]: {
|
|
8713
10397
|
since: "3.12.0",
|
|
@@ -8749,13 +10433,52 @@ var BITS = {
|
|
|
8749
10433
|
since: "1.34.0",
|
|
8750
10434
|
baseBitType: BitType2._standard,
|
|
8751
10435
|
description: "Definition list bit, used to create lists of definitions in articles or books",
|
|
10436
|
+
tags: [
|
|
10437
|
+
{
|
|
10438
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10439
|
+
key: ConfigKey.property_example,
|
|
10440
|
+
exportJsonKey: [
|
|
10441
|
+
{ "@keyonly": { isExample: true } },
|
|
10442
|
+
{ "@absent": { isExample: true } },
|
|
10443
|
+
{ isExample: true, example: "$" }
|
|
10444
|
+
],
|
|
10445
|
+
description: "The example(s) for the bit",
|
|
10446
|
+
format: TagFormat.bitmarkText,
|
|
10447
|
+
nullable: true
|
|
10448
|
+
}
|
|
10449
|
+
],
|
|
8752
10450
|
cardSet: CardSetConfigKey.definitionList
|
|
8753
10451
|
},
|
|
10452
|
+
[BitType2.definitionListCollapsible]: {
|
|
10453
|
+
since: "5.25.0",
|
|
10454
|
+
baseBitType: BitType2.definitionList,
|
|
10455
|
+
description: "Collapsible definition list bit, used to create collapsible lists of definitions in articles or books"
|
|
10456
|
+
},
|
|
10457
|
+
[BitType2.standardDefinitionListNormative]: {
|
|
10458
|
+
since: "5.24.0",
|
|
10459
|
+
baseBitType: BitType2.definitionList,
|
|
10460
|
+
description: "Standard normative definition list bit, used to create normative standard definition lists in articles or books"
|
|
10461
|
+
},
|
|
10462
|
+
[BitType2.standardDefinitionListNonNormative]: {
|
|
10463
|
+
since: "5.24.0",
|
|
10464
|
+
baseBitType: BitType2.definitionList,
|
|
10465
|
+
description: "Standard non-normative definition list bit, used to create non-normative standard definition lists in articles or books"
|
|
10466
|
+
},
|
|
10467
|
+
[BitType2.smartStandardDefinitionListNormative]: {
|
|
10468
|
+
since: "5.24.0",
|
|
10469
|
+
baseBitType: BitType2.standardDefinitionListNormative,
|
|
10470
|
+
description: "Smart standard normative definition list bit, used to create normative smart standard definition lists in articles or books"
|
|
10471
|
+
},
|
|
10472
|
+
[BitType2.smartStandardDefinitionListNonNormative]: {
|
|
10473
|
+
since: "5.24.0",
|
|
10474
|
+
baseBitType: BitType2.standardDefinitionListNonNormative,
|
|
10475
|
+
description: "Smart standard non-normative definition list bit, used to create non-normative smart standard definition lists in articles or books"
|
|
10476
|
+
},
|
|
8754
10477
|
[BitType2.metaSearchDefaultTerms]: {
|
|
8755
10478
|
since: "3.12.0",
|
|
8756
10479
|
baseBitType: BitType2._standard,
|
|
8757
10480
|
description: "Meta search default terms bit, used to define default search terms in articles",
|
|
8758
|
-
cardSet: CardSetConfigKey.
|
|
10481
|
+
cardSet: CardSetConfigKey.definitionListPlain
|
|
8759
10482
|
},
|
|
8760
10483
|
[BitType2.metaSearchDefaultTopics]: {
|
|
8761
10484
|
since: "3.12.0",
|
|
@@ -8771,6 +10494,18 @@ var BITS = {
|
|
|
8771
10494
|
{
|
|
8772
10495
|
key: ConfigKey.group_quizCommon,
|
|
8773
10496
|
description: "Common quiz tags for flashcards"
|
|
10497
|
+
},
|
|
10498
|
+
{
|
|
10499
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10500
|
+
key: ConfigKey.property_example,
|
|
10501
|
+
exportJsonKey: [
|
|
10502
|
+
{ "@keyonly": { isExample: true } },
|
|
10503
|
+
{ "@absent": { isExample: true } },
|
|
10504
|
+
{ isExample: true, example: "$" }
|
|
10505
|
+
],
|
|
10506
|
+
description: "The example(s) for the bit",
|
|
10507
|
+
format: TagFormat.bitmarkText,
|
|
10508
|
+
nullable: true
|
|
8774
10509
|
}
|
|
8775
10510
|
],
|
|
8776
10511
|
cardSet: CardSetConfigKey.flashcard
|
|
@@ -8778,12 +10513,20 @@ var BITS = {
|
|
|
8778
10513
|
[BitType2.flashcard1]: {
|
|
8779
10514
|
since: "1.3.0",
|
|
8780
10515
|
baseBitType: BitType2.flashcard,
|
|
8781
|
-
description: "Flashcard 1 bit"
|
|
10516
|
+
description: "Flashcard 1 bit",
|
|
10517
|
+
// PLAN-085: use the flashcard1 cardset (sections.default.maxCount=1)
|
|
10518
|
+
// instead of inheriting `flashcard`'s unbounded cardset, since this
|
|
10519
|
+
// bit type structurally allows only a single card.
|
|
10520
|
+
cardSet: CardSetConfigKey.flashcard1
|
|
8782
10521
|
},
|
|
8783
10522
|
[BitType2.qAndACard]: {
|
|
8784
10523
|
since: "3.25.0",
|
|
8785
10524
|
baseBitType: BitType2.flashcard1,
|
|
8786
|
-
description: "Q&A card bit, used to create question and answer cards in articles or books"
|
|
10525
|
+
description: "Q&A card bit, used to create question and answer cards in articles or books",
|
|
10526
|
+
// PLAN-085: q-and-a-card permits multiple cards (some fixtures carry
|
|
10527
|
+
// two). Override the inherited `flashcard1` (max=1) cardset back to
|
|
10528
|
+
// the unbounded `flashcard` cardset.
|
|
10529
|
+
cardSet: CardSetConfigKey.flashcard
|
|
8787
10530
|
},
|
|
8788
10531
|
[BitType2.focusImage]: {
|
|
8789
10532
|
since: "1.3.0",
|
|
@@ -8813,8 +10556,24 @@ var BITS = {
|
|
|
8813
10556
|
description: "Common quiz tags for highlighted text"
|
|
8814
10557
|
},
|
|
8815
10558
|
{
|
|
8816
|
-
|
|
8817
|
-
|
|
10559
|
+
// Dedicated highlight inline-select chain: tag_true / tag_false
|
|
10560
|
+
// emit `{type:"highlight", attrs:{texts:[{text,isCorrect?}]}}`
|
|
10561
|
+
// inline body nodes via @body-inline. Bit shares no tag IDs with
|
|
10562
|
+
// multiple-choice / multiple-choice-1 (which use group_trueFalse).
|
|
10563
|
+
key: ConfigKey.group_trueFalseInlineHighlight,
|
|
10564
|
+
description: "True/False quiz tags for highlighted text (inline body nodes)"
|
|
10565
|
+
},
|
|
10566
|
+
{
|
|
10567
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10568
|
+
key: ConfigKey.property_example,
|
|
10569
|
+
exportJsonKey: [
|
|
10570
|
+
{ "@keyonly": { isExample: true } },
|
|
10571
|
+
{ "@absent": { isExample: true } },
|
|
10572
|
+
{ isExample: true, example: "$" }
|
|
10573
|
+
],
|
|
10574
|
+
description: "The example(s) for the bit",
|
|
10575
|
+
format: TagFormat.bitmarkText,
|
|
10576
|
+
nullable: true
|
|
8818
10577
|
}
|
|
8819
10578
|
]
|
|
8820
10579
|
},
|
|
@@ -8824,15 +10583,8 @@ var BITS = {
|
|
|
8824
10583
|
description: "Image bit, used to create images in articles or books",
|
|
8825
10584
|
tags: [
|
|
8826
10585
|
{
|
|
8827
|
-
key: ConfigKey.
|
|
8828
|
-
|
|
8829
|
-
description: "Background wallpaper for the image, used to set a background for the image",
|
|
8830
|
-
chain: [
|
|
8831
|
-
{
|
|
8832
|
-
key: ConfigKey.group_resourceImageCommon,
|
|
8833
|
-
description: "Common resource image tags for images"
|
|
8834
|
-
}
|
|
8835
|
-
]
|
|
10586
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
10587
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
8836
10588
|
},
|
|
8837
10589
|
{
|
|
8838
10590
|
key: ConfigKey.group_resourceBitTags,
|
|
@@ -8935,8 +10687,15 @@ var BITS = {
|
|
|
8935
10687
|
},
|
|
8936
10688
|
[BitType2.imageSeparator]: {
|
|
8937
10689
|
since: "1.4.15",
|
|
8938
|
-
baseBitType: BitType2.
|
|
8939
|
-
description: "Image separator bit, used to create separators in articles or books"
|
|
10690
|
+
baseBitType: BitType2._standard,
|
|
10691
|
+
description: "Image separator bit, used to create separators in articles or books",
|
|
10692
|
+
tags: [
|
|
10693
|
+
{
|
|
10694
|
+
key: ConfigKey.group_imageNoZoom,
|
|
10695
|
+
description: "Image no zoom tags for images, used to define whether images should have zoom functionality"
|
|
10696
|
+
}
|
|
10697
|
+
],
|
|
10698
|
+
resourceAttachmentAllowed: false
|
|
8940
10699
|
},
|
|
8941
10700
|
[BitType2.imageSeparatorAlt]: {
|
|
8942
10701
|
since: "1.16.0",
|
|
@@ -8975,15 +10734,20 @@ var BITS = {
|
|
|
8975
10734
|
},
|
|
8976
10735
|
[BitType2.pageBanner]: {
|
|
8977
10736
|
since: "1.4.3",
|
|
8978
|
-
baseBitType: BitType2.
|
|
10737
|
+
baseBitType: BitType2._standard,
|
|
8979
10738
|
description: "Page banner bit, used to create banners for pages in articles or books",
|
|
8980
10739
|
tags: [
|
|
8981
10740
|
{
|
|
8982
10741
|
key: ConfigKey.property_slug,
|
|
8983
10742
|
description: "Slug for the page banner, used to identify the banner in the system",
|
|
8984
10743
|
format: TagFormat.plainText
|
|
10744
|
+
},
|
|
10745
|
+
{
|
|
10746
|
+
key: ConfigKey.group_imageNoZoom,
|
|
10747
|
+
description: "Image no zoom tags for images, used to define whether images should have zoom functionality"
|
|
8985
10748
|
}
|
|
8986
|
-
]
|
|
10749
|
+
],
|
|
10750
|
+
resourceAttachmentAllowed: false
|
|
8987
10751
|
},
|
|
8988
10752
|
[BitType2.pageHero]: {
|
|
8989
10753
|
since: "1.11.0",
|
|
@@ -8998,7 +10762,7 @@ var BITS = {
|
|
|
8998
10762
|
},
|
|
8999
10763
|
[BitType2.tableImage]: {
|
|
9000
10764
|
since: "1.5.15",
|
|
9001
|
-
baseBitType: BitType2.
|
|
10765
|
+
baseBitType: BitType2.tableExtended,
|
|
9002
10766
|
description: "Table image bit, used to create images in tables in articles or books",
|
|
9003
10767
|
tags: [
|
|
9004
10768
|
{
|
|
@@ -9007,15 +10771,8 @@ var BITS = {
|
|
|
9007
10771
|
format: TagFormat.bitmarkText
|
|
9008
10772
|
},
|
|
9009
10773
|
{
|
|
9010
|
-
key: ConfigKey.
|
|
9011
|
-
|
|
9012
|
-
description: "Background wallpaper for the image, used to set a background for the image",
|
|
9013
|
-
chain: [
|
|
9014
|
-
{
|
|
9015
|
-
key: ConfigKey.group_resourceImageCommon,
|
|
9016
|
-
description: "Common resource image tags for images"
|
|
9017
|
-
}
|
|
9018
|
-
]
|
|
10774
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
10775
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
9019
10776
|
},
|
|
9020
10777
|
{
|
|
9021
10778
|
key: ConfigKey.group_resourceBitTags,
|
|
@@ -9158,10 +10915,10 @@ var BITS = {
|
|
|
9158
10915
|
description: "Resource bit tags for logo grave images, used to define additional properties"
|
|
9159
10916
|
},
|
|
9160
10917
|
{
|
|
9161
|
-
// Image resource
|
|
9162
|
-
key: ConfigKey.
|
|
10918
|
+
// Image resource — fully-expanded shape (see BitType.extractorImage).
|
|
10919
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
9163
10920
|
description: "Resource image tags for logo grave images, used to attach images",
|
|
9164
|
-
exportJsonKey: { logos: "$" },
|
|
10921
|
+
exportJsonKey: { logos: [{ type: "image", image: { src: "$" } }] },
|
|
9165
10922
|
minCount: 1,
|
|
9166
10923
|
maxCount: Count.infinity
|
|
9167
10924
|
}
|
|
@@ -9171,7 +10928,17 @@ var BITS = {
|
|
|
9171
10928
|
[BitType2.prototypeImages]: {
|
|
9172
10929
|
since: "1.6.1",
|
|
9173
10930
|
baseBitType: BitType2.imagesLogoGrave,
|
|
9174
|
-
description: "Prototype images bit, used to create prototype images in articles or books"
|
|
10931
|
+
description: "Prototype images bit, used to create prototype images in articles or books",
|
|
10932
|
+
tags: [
|
|
10933
|
+
{
|
|
10934
|
+
// Override inherited `logos` wrapper with `images` for this bit type.
|
|
10935
|
+
key: ConfigKey.group_resourceImageNoZoom,
|
|
10936
|
+
description: "Resource image tags for prototype images",
|
|
10937
|
+
exportJsonKey: { images: [{ type: "image", image: { src: "$" } }] },
|
|
10938
|
+
minCount: 1,
|
|
10939
|
+
maxCount: Count.infinity
|
|
10940
|
+
}
|
|
10941
|
+
]
|
|
9175
10942
|
},
|
|
9176
10943
|
[BitType2.internalLink]: {
|
|
9177
10944
|
since: "1.3.0",
|
|
@@ -9201,6 +10968,18 @@ var BITS = {
|
|
|
9201
10968
|
exportJsonKey: {},
|
|
9202
10969
|
description: "Reasonable number of characters for the interview, used to limit input size",
|
|
9203
10970
|
format: TagFormat.number
|
|
10971
|
+
},
|
|
10972
|
+
{
|
|
10973
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
10974
|
+
key: ConfigKey.property_example,
|
|
10975
|
+
exportJsonKey: [
|
|
10976
|
+
{ "@keyonly": { isExample: true } },
|
|
10977
|
+
{ "@absent": { isExample: true } },
|
|
10978
|
+
{ isExample: true, example: "$" }
|
|
10979
|
+
],
|
|
10980
|
+
description: "The example(s) for the bit",
|
|
10981
|
+
format: TagFormat.bitmarkText,
|
|
10982
|
+
nullable: true
|
|
9204
10983
|
}
|
|
9205
10984
|
],
|
|
9206
10985
|
cardSet: CardSetConfigKey.questions
|
|
@@ -9559,6 +11338,18 @@ var BITS = {
|
|
|
9559
11338
|
{
|
|
9560
11339
|
key: ConfigKey.group_mark,
|
|
9561
11340
|
description: "Mark tags, used to define the content of marks"
|
|
11341
|
+
},
|
|
11342
|
+
{
|
|
11343
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11344
|
+
key: ConfigKey.property_example,
|
|
11345
|
+
exportJsonKey: [
|
|
11346
|
+
{ "@keyonly": { isExample: true } },
|
|
11347
|
+
{ "@absent": { isExample: true } },
|
|
11348
|
+
{ isExample: true, example: "$" }
|
|
11349
|
+
],
|
|
11350
|
+
description: "The example(s) for the bit",
|
|
11351
|
+
format: TagFormat.bitmarkText,
|
|
11352
|
+
nullable: true
|
|
9562
11353
|
}
|
|
9563
11354
|
]
|
|
9564
11355
|
},
|
|
@@ -9578,6 +11369,23 @@ var BITS = {
|
|
|
9578
11369
|
description: "Case sensitivity for matching pairs, used to define if matches are case-sensitive",
|
|
9579
11370
|
format: TagFormat.boolean,
|
|
9580
11371
|
defaultValue: "true"
|
|
11372
|
+
},
|
|
11373
|
+
{
|
|
11374
|
+
// Override inherited @example: in `isTopLevelExample` allow-list
|
|
11375
|
+
// (covers match, matchAll, matchReverse, matchAllReverse,
|
|
11376
|
+
// matchSolutionGrouped, matchMatrix, matchAudio, matchPicture).
|
|
11377
|
+
// Bit-level fires emit only `isExample`; the @example value (when
|
|
11378
|
+
// provided) is recorded in the ancestor stack and consumed by
|
|
11379
|
+
// per-pair/per-cell variant overrides — not surfaced at bit scope.
|
|
11380
|
+
key: ConfigKey.property_example,
|
|
11381
|
+
exportJsonKey: [
|
|
11382
|
+
{ "@keyonly": { isExample: true } },
|
|
11383
|
+
{ "@absent": { isExample: true } },
|
|
11384
|
+
{ isExample: true }
|
|
11385
|
+
],
|
|
11386
|
+
description: "The example(s) for the bit",
|
|
11387
|
+
format: TagFormat.bitmarkText,
|
|
11388
|
+
nullable: true
|
|
9581
11389
|
}
|
|
9582
11390
|
],
|
|
9583
11391
|
cardSet: CardSetConfigKey.matchPairs
|
|
@@ -9662,6 +11470,18 @@ var BITS = {
|
|
|
9662
11470
|
{
|
|
9663
11471
|
key: ConfigKey.group_trueFalse,
|
|
9664
11472
|
description: "True/False tags for multiple choice 1 questions"
|
|
11473
|
+
},
|
|
11474
|
+
{
|
|
11475
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11476
|
+
key: ConfigKey.property_example,
|
|
11477
|
+
exportJsonKey: [
|
|
11478
|
+
{ "@keyonly": { isExample: true } },
|
|
11479
|
+
{ "@absent": { isExample: true } },
|
|
11480
|
+
{ isExample: true, example: "$" }
|
|
11481
|
+
],
|
|
11482
|
+
description: "The example(s) for the bit",
|
|
11483
|
+
format: TagFormat.bitmarkText,
|
|
11484
|
+
nullable: true
|
|
9665
11485
|
}
|
|
9666
11486
|
]
|
|
9667
11487
|
},
|
|
@@ -9683,8 +11503,20 @@ var BITS = {
|
|
|
9683
11503
|
{
|
|
9684
11504
|
key: ConfigKey.group_trueFalse,
|
|
9685
11505
|
description: "True/False tags for multiple choice questions"
|
|
9686
|
-
}
|
|
11506
|
+
},
|
|
9687
11507
|
// This is actually for multiple-choice-1, but we support it here as well (as many bits are wrong)
|
|
11508
|
+
{
|
|
11509
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11510
|
+
key: ConfigKey.property_example,
|
|
11511
|
+
exportJsonKey: [
|
|
11512
|
+
{ "@keyonly": { isExample: true } },
|
|
11513
|
+
{ "@absent": { isExample: true } },
|
|
11514
|
+
{ isExample: true, example: "$" }
|
|
11515
|
+
],
|
|
11516
|
+
description: "The example(s) for the bit",
|
|
11517
|
+
format: TagFormat.bitmarkText,
|
|
11518
|
+
nullable: true
|
|
11519
|
+
}
|
|
9688
11520
|
],
|
|
9689
11521
|
cardSet: CardSetConfigKey.quiz
|
|
9690
11522
|
},
|
|
@@ -9704,8 +11536,20 @@ var BITS = {
|
|
|
9704
11536
|
description: "Common quiz tags for multiple choice text questions"
|
|
9705
11537
|
},
|
|
9706
11538
|
{
|
|
9707
|
-
key: ConfigKey.
|
|
11539
|
+
key: ConfigKey.group_trueFalseInlineSelect,
|
|
9708
11540
|
description: "True/False tags for multiple choice text questions"
|
|
11541
|
+
},
|
|
11542
|
+
{
|
|
11543
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11544
|
+
key: ConfigKey.property_example,
|
|
11545
|
+
exportJsonKey: [
|
|
11546
|
+
{ "@keyonly": { isExample: true } },
|
|
11547
|
+
{ "@absent": { isExample: true } },
|
|
11548
|
+
{ isExample: true, example: "$" }
|
|
11549
|
+
],
|
|
11550
|
+
description: "The example(s) for the bit",
|
|
11551
|
+
format: TagFormat.bitmarkText,
|
|
11552
|
+
nullable: true
|
|
9709
11553
|
}
|
|
9710
11554
|
]
|
|
9711
11555
|
},
|
|
@@ -9730,8 +11574,20 @@ var BITS = {
|
|
|
9730
11574
|
description: "Common quiz tags for multiple response 1 questions"
|
|
9731
11575
|
},
|
|
9732
11576
|
{
|
|
9733
|
-
key: ConfigKey.
|
|
11577
|
+
key: ConfigKey.group_trueFalseResponses,
|
|
9734
11578
|
description: "True/False tags for multiple response 1 questions"
|
|
11579
|
+
},
|
|
11580
|
+
{
|
|
11581
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11582
|
+
key: ConfigKey.property_example,
|
|
11583
|
+
exportJsonKey: [
|
|
11584
|
+
{ "@keyonly": { isExample: true } },
|
|
11585
|
+
{ "@absent": { isExample: true } },
|
|
11586
|
+
{ isExample: true, example: "$" }
|
|
11587
|
+
],
|
|
11588
|
+
description: "The example(s) for the bit",
|
|
11589
|
+
format: TagFormat.bitmarkText,
|
|
11590
|
+
nullable: true
|
|
9735
11591
|
}
|
|
9736
11592
|
]
|
|
9737
11593
|
},
|
|
@@ -9751,12 +11607,24 @@ var BITS = {
|
|
|
9751
11607
|
description: "Common quiz tags for multiple response questions"
|
|
9752
11608
|
},
|
|
9753
11609
|
{
|
|
9754
|
-
key: ConfigKey.
|
|
11610
|
+
key: ConfigKey.group_trueFalseResponses,
|
|
9755
11611
|
description: "True/False tags for multiple response questions"
|
|
9756
|
-
}
|
|
11612
|
+
},
|
|
9757
11613
|
// This is actually for multiple-response-1, but we support it here as well (as many bits are wrong)
|
|
11614
|
+
{
|
|
11615
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
11616
|
+
key: ConfigKey.property_example,
|
|
11617
|
+
exportJsonKey: [
|
|
11618
|
+
{ "@keyonly": { isExample: true } },
|
|
11619
|
+
{ "@absent": { isExample: true } },
|
|
11620
|
+
{ isExample: true, example: "$" }
|
|
11621
|
+
],
|
|
11622
|
+
description: "The example(s) for the bit",
|
|
11623
|
+
format: TagFormat.bitmarkText,
|
|
11624
|
+
nullable: true
|
|
11625
|
+
}
|
|
9758
11626
|
],
|
|
9759
|
-
cardSet: CardSetConfigKey.
|
|
11627
|
+
cardSet: CardSetConfigKey.quizResponses
|
|
9760
11628
|
},
|
|
9761
11629
|
[BitType2.coachSelfReflectionMultipleResponse]: {
|
|
9762
11630
|
since: "1.3.0",
|
|
@@ -10006,6 +11874,8 @@ var BITS = {
|
|
|
10006
11874
|
},
|
|
10007
11875
|
{
|
|
10008
11876
|
key: ConfigKey.resource_platformIcon,
|
|
11877
|
+
jsonKey: "platformIcon|resource(type=image, key=image)",
|
|
11878
|
+
exportJsonKey: { platformIcon: { type: "image", image: { src: "$" } } },
|
|
10009
11879
|
description: "The platform icon",
|
|
10010
11880
|
chain: [
|
|
10011
11881
|
{
|
|
@@ -10041,6 +11911,8 @@ var BITS = {
|
|
|
10041
11911
|
tags: [
|
|
10042
11912
|
{
|
|
10043
11913
|
key: ConfigKey.resource_platformLogo,
|
|
11914
|
+
jsonKey: "platformLogo|resource(type=image, key=image)",
|
|
11915
|
+
exportJsonKey: { platformLogo: { type: "image", image: { src: "$" } } },
|
|
10044
11916
|
description: "The platform logo",
|
|
10045
11917
|
chain: [
|
|
10046
11918
|
{
|
|
@@ -10252,7 +12124,8 @@ var BITS = {
|
|
|
10252
12124
|
{ isExample: true, example: "$" }
|
|
10253
12125
|
],
|
|
10254
12126
|
description: "The example text for the review note bit",
|
|
10255
|
-
format: TagFormat.plainText
|
|
12127
|
+
format: TagFormat.plainText,
|
|
12128
|
+
nullable: true
|
|
10256
12129
|
}
|
|
10257
12130
|
],
|
|
10258
12131
|
rootExampleType: ExampleType.string
|
|
@@ -10339,7 +12212,8 @@ var BITS = {
|
|
|
10339
12212
|
{ isExample: true, example: "$" }
|
|
10340
12213
|
],
|
|
10341
12214
|
description: "The example flag for the bit (boolean)",
|
|
10342
|
-
format: TagFormat.
|
|
12215
|
+
format: TagFormat.boolean,
|
|
12216
|
+
nullable: true
|
|
10343
12217
|
}
|
|
10344
12218
|
],
|
|
10345
12219
|
cardSet: CardSetConfigKey.elements,
|
|
@@ -10613,15 +12487,8 @@ var BITS = {
|
|
|
10613
12487
|
format: TagFormat.bitmarkText
|
|
10614
12488
|
},
|
|
10615
12489
|
{
|
|
10616
|
-
key: ConfigKey.
|
|
10617
|
-
|
|
10618
|
-
description: "Background wallpaper for the image, used to set a background for the image",
|
|
10619
|
-
chain: [
|
|
10620
|
-
{
|
|
10621
|
-
key: ConfigKey.group_resourceImageCommon,
|
|
10622
|
-
description: "Common resource image tags for images"
|
|
10623
|
-
}
|
|
10624
|
-
]
|
|
12490
|
+
key: ConfigKey.group_backgroundWallpaper,
|
|
12491
|
+
description: "Background wallpaper tags for images, used to define background properties for images"
|
|
10625
12492
|
},
|
|
10626
12493
|
{
|
|
10627
12494
|
key: ConfigKey.group_resourceBitTags,
|
|
@@ -10998,16 +12865,20 @@ var BITS = {
|
|
|
10998
12865
|
format: TagFormat.plainText
|
|
10999
12866
|
},
|
|
11000
12867
|
{
|
|
11001
|
-
|
|
12868
|
+
// PLAN-067 Edit #1: true-false-1's `+` / `-` emit a flat
|
|
12869
|
+
// `{ statement, isCorrect }` at bit root (single-statement bit),
|
|
12870
|
+
// not a `choices[]` array. Format is bitmarkText so the statement
|
|
12871
|
+
// body renders as a ProseMirror tree, matching reference fixtures.
|
|
12872
|
+
exportJsonKey: { statement: "$", isCorrect: true },
|
|
11002
12873
|
key: ConfigKey.tag_true,
|
|
11003
12874
|
description: "Tag for the true option in the true/false question",
|
|
11004
|
-
format: TagFormat.
|
|
12875
|
+
format: TagFormat.bitmarkText
|
|
11005
12876
|
},
|
|
11006
12877
|
{
|
|
11007
|
-
exportJsonKey: {
|
|
12878
|
+
exportJsonKey: { statement: "$", isCorrect: false },
|
|
11008
12879
|
key: ConfigKey.tag_false,
|
|
11009
12880
|
description: "Tag for the false option in the true/false question",
|
|
11010
|
-
format: TagFormat.
|
|
12881
|
+
format: TagFormat.bitmarkText
|
|
11011
12882
|
},
|
|
11012
12883
|
{
|
|
11013
12884
|
// Override inherited @example from group_standardTags: boolean root
|
|
@@ -11018,14 +12889,24 @@ var BITS = {
|
|
|
11018
12889
|
// sufficient for `[+...]` (correct) statements which dominate the
|
|
11019
12890
|
// fixtures; `[-...]` (incorrect) bits with bare `[@example]` would
|
|
11020
12891
|
// need either a runtime extension or an explicit `[@example:false]`.
|
|
12892
|
+
//
|
|
12893
|
+
// Format is `boolean` so `[@example:false]` coerces to JSON `false`
|
|
12894
|
+
// (a natural default that gets stripped in optimised mode, matching
|
|
12895
|
+
// BPG's `rootExampleType: boolean`). PlainText would emit the
|
|
12896
|
+
// STRING `"false"` which doesn't strip.
|
|
11021
12897
|
key: ConfigKey.property_example,
|
|
11022
12898
|
exportJsonKey: [
|
|
11023
12899
|
{ "@keyonly": { isExample: true, example: true } },
|
|
11024
12900
|
{ "@absent": { isExample: true, example: true } },
|
|
12901
|
+
// `[@example:false]`: emit `isExample: true` only — `example: false`
|
|
12902
|
+
// is the natural default for boolean, stripped in optimised mode.
|
|
12903
|
+
// Mirrors BPG `removeUnwantedProperties` `ignoreAllFalse: true`.
|
|
12904
|
+
{ "@value=false": { isExample: true } },
|
|
11025
12905
|
{ isExample: true, example: "$" }
|
|
11026
12906
|
],
|
|
11027
12907
|
description: "The example flag for the bit (boolean)",
|
|
11028
|
-
format: TagFormat.
|
|
12908
|
+
format: TagFormat.boolean,
|
|
12909
|
+
nullable: true
|
|
11029
12910
|
}
|
|
11030
12911
|
],
|
|
11031
12912
|
rootExampleType: ExampleType.boolean
|
|
@@ -11049,6 +12930,18 @@ var BITS = {
|
|
|
11049
12930
|
key: ConfigKey.property_labelFalse,
|
|
11050
12931
|
description: "Label for the false option in the true/false question",
|
|
11051
12932
|
format: TagFormat.plainText
|
|
12933
|
+
},
|
|
12934
|
+
{
|
|
12935
|
+
// Override inherited @example: in `isTopLevelExample` allow-list.
|
|
12936
|
+
key: ConfigKey.property_example,
|
|
12937
|
+
exportJsonKey: [
|
|
12938
|
+
{ "@keyonly": { isExample: true } },
|
|
12939
|
+
{ "@absent": { isExample: true } },
|
|
12940
|
+
{ isExample: true, example: "$" }
|
|
12941
|
+
],
|
|
12942
|
+
description: "The example(s) for the bit",
|
|
12943
|
+
format: TagFormat.bitmarkText,
|
|
12944
|
+
nullable: true
|
|
11052
12945
|
}
|
|
11053
12946
|
],
|
|
11054
12947
|
cardSet: CardSetConfigKey.statements
|
|
@@ -11238,6 +13131,11 @@ var BITS = {
|
|
|
11238
13131
|
baseBitType: BitType2.vendorStripePricingTable,
|
|
11239
13132
|
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",
|
|
11240
13133
|
tags: [
|
|
13134
|
+
{
|
|
13135
|
+
key: ConfigKey.property_stripePricingTableDescriptiveName,
|
|
13136
|
+
description: "Descriptive name for the Stripe pricing table",
|
|
13137
|
+
format: TagFormat.plainText
|
|
13138
|
+
},
|
|
11241
13139
|
{
|
|
11242
13140
|
key: ConfigKey.property_printOnRequestCustomerId,
|
|
11243
13141
|
description: "Print-on-request customer ID, used to identify the customer for the print-on-request flow",
|
|
@@ -11714,7 +13612,7 @@ var instance2 = new Config();
|
|
|
11714
13612
|
// src/generated/package_info.ts
|
|
11715
13613
|
var PACKAGE_INFO = {
|
|
11716
13614
|
"name": "@gmb/bitmark-parser-generator",
|
|
11717
|
-
"version": "5.
|
|
13615
|
+
"version": "5.25.0",
|
|
11718
13616
|
"author": "Get More Brain Ltd",
|
|
11719
13617
|
"license": "ISC",
|
|
11720
13618
|
"description": "A bitmark parser and generator using Peggy.js"
|
|
@@ -12360,6 +14258,8 @@ var NodeType = {
|
|
|
12360
14258
|
internalPrintPdf: "internalPrintPdf",
|
|
12361
14259
|
internalPrintPdfValue: "internalPrintPdfValue",
|
|
12362
14260
|
isCaseSensitive: "isCaseSensitive",
|
|
14261
|
+
isCollapsible: "isCollapsible",
|
|
14262
|
+
isCollapsibleValue: "isCollapsibleValue",
|
|
12363
14263
|
isCommented: "isCommented",
|
|
12364
14264
|
isCorrect: "isCorrect",
|
|
12365
14265
|
isEditable: "isEditable",
|
|
@@ -12679,6 +14579,8 @@ var NodeType = {
|
|
|
12679
14579
|
stillImageFilmLink: "stillImageFilmLink",
|
|
12680
14580
|
stripePricingTableId: "stripePricingTableId",
|
|
12681
14581
|
stripePricingTableIdValue: "stripePricingTableIdValue",
|
|
14582
|
+
stripePricingTableDescriptiveName: "stripePricingTableDescriptiveName",
|
|
14583
|
+
stripePricingTableDescriptiveNameValue: "stripePricingTableDescriptiveNameValue",
|
|
12682
14584
|
stripePublishableKey: "stripePublishableKey",
|
|
12683
14585
|
stripePublishableKeyValue: "stripePublishableKeyValue",
|
|
12684
14586
|
subject: "subject",
|
|
@@ -26104,6 +28006,12 @@ var Builder = class extends BaseBuilder {
|
|
|
26104
28006
|
data.stripePricingTableId,
|
|
26105
28007
|
options
|
|
26106
28008
|
),
|
|
28009
|
+
stripePricingTableDescriptiveName: this.toAstProperty(
|
|
28010
|
+
bitType,
|
|
28011
|
+
ConfigKey.property_stripePricingTableDescriptiveName,
|
|
28012
|
+
data.stripePricingTableDescriptiveName,
|
|
28013
|
+
options
|
|
28014
|
+
),
|
|
26107
28015
|
stripePublishableKey: this.toAstProperty(
|
|
26108
28016
|
bitType,
|
|
26109
28017
|
ConfigKey.property_stripePublishableKey,
|
|
@@ -26590,6 +28498,12 @@ var Builder = class extends BaseBuilder {
|
|
|
26590
28498
|
level: instance6.asNumber(data.level),
|
|
26591
28499
|
toc: this.toAstProperty(bitType, ConfigKey.property_toc, data.toc, options),
|
|
26592
28500
|
progress: this.toAstProperty(bitType, ConfigKey.property_progress, data.progress, options),
|
|
28501
|
+
isCollapsible: this.toAstProperty(
|
|
28502
|
+
bitType,
|
|
28503
|
+
ConfigKey.property_isCollapsible,
|
|
28504
|
+
data.isCollapsible,
|
|
28505
|
+
options
|
|
28506
|
+
),
|
|
26593
28507
|
anchor: data.anchor,
|
|
26594
28508
|
reference: data.reference,
|
|
26595
28509
|
referenceEnd: data.referenceEnd,
|
|
@@ -32136,6 +34050,7 @@ var JsonGenerator = class extends AstWalkerGenerator {
|
|
|
32136
34050
|
if (instance2.isOfBitType(bitType, BitType2.chapter)) {
|
|
32137
34051
|
if (bitJson.toc == null) bitJson.toc = true;
|
|
32138
34052
|
if (bitJson.progress == null) bitJson.progress = true;
|
|
34053
|
+
if (bitJson.isCollapsible == null) bitJson.isCollapsible = false;
|
|
32139
34054
|
if (bitJson.level == null) bitJson.level = 1;
|
|
32140
34055
|
if (bitJson.body == null) bitJson.body = this.bodyDefault;
|
|
32141
34056
|
}
|
|
@@ -34331,7 +36246,9 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
34331
36246
|
const cardSetType = bitConfig.cardSet?.configKey;
|
|
34332
36247
|
switch (cardSetType) {
|
|
34333
36248
|
case CardSetConfigKey.flashcard:
|
|
36249
|
+
case CardSetConfigKey.flashcard1:
|
|
34334
36250
|
case CardSetConfigKey.definitionList:
|
|
36251
|
+
case CardSetConfigKey.definitionListPlain:
|
|
34335
36252
|
result = parseFlashcardOrDefinitionList(context, bitType, processedCardSet);
|
|
34336
36253
|
break;
|
|
34337
36254
|
case CardSetConfigKey.elements:
|
|
@@ -34344,6 +36261,7 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
34344
36261
|
result = parseFeedback(context, bitType, processedCardSet);
|
|
34345
36262
|
break;
|
|
34346
36263
|
case CardSetConfigKey.quiz:
|
|
36264
|
+
case CardSetConfigKey.quizResponses:
|
|
34347
36265
|
result = parseQuiz(context, bitType, processedCardSet, choicesV1, responsesV1);
|
|
34348
36266
|
break;
|
|
34349
36267
|
case CardSetConfigKey.questions:
|
|
@@ -34370,6 +36288,7 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
34370
36288
|
break;
|
|
34371
36289
|
case CardSetConfigKey.clozeList:
|
|
34372
36290
|
case CardSetConfigKey.exampleBitList:
|
|
36291
|
+
case CardSetConfigKey.pageFooterSections:
|
|
34373
36292
|
case CardSetConfigKey.bookReferenceList:
|
|
34374
36293
|
result = parseCardBits(context, bitType, textFormat, processedCardSet);
|
|
34375
36294
|
break;
|
|
@@ -40396,7 +42315,11 @@ var InputFormat = {
|
|
|
40396
42315
|
/**
|
|
40397
42316
|
* Input is plain text
|
|
40398
42317
|
*/
|
|
40399
|
-
plainText: "plainText"
|
|
42318
|
+
plainText: "plainText",
|
|
42319
|
+
/**
|
|
42320
|
+
* Input is HTML (used by convertHtmlTable)
|
|
42321
|
+
*/
|
|
42322
|
+
html: "html"
|
|
40400
42323
|
};
|
|
40401
42324
|
var BitmarkParserGenerator = class {
|
|
40402
42325
|
constructor() {
|
|
@@ -40931,6 +42854,87 @@ var BitmarkParserGenerator = class {
|
|
|
40931
42854
|
const res = generator.generate(data);
|
|
40932
42855
|
return res;
|
|
40933
42856
|
}
|
|
42857
|
+
/**
|
|
42858
|
+
* Convert between HTML tables and bitmark tables.
|
|
42859
|
+
*
|
|
42860
|
+
* Direction is auto-detected (override with `options.inputFormat`):
|
|
42861
|
+
* - HTML input: every `<table>` is extracted and emitted as a `[.table-extended]` (or `[.table]`)
|
|
42862
|
+
* bit; output as bitmark (default), JSON, AST, or HTML (re-emit).
|
|
42863
|
+
* - bitmark / JSON / AST input: each `table` / `table-extended` bit is rendered as an HTML
|
|
42864
|
+
* `<table>` fragment.
|
|
42865
|
+
*
|
|
42866
|
+
* Cell content is reproduced verbatim except inline conversion to bitmark marks (bold, italic,
|
|
42867
|
+
* superscript, etc.), with lists and images mapped to their bitmark equivalents.
|
|
42868
|
+
*
|
|
42869
|
+
* @param input - HTML, bitmark, JSON or AST string; or a parsed JSON/AST value; or a file path.
|
|
42870
|
+
* @param options - the conversion options
|
|
42871
|
+
* @returns the converted output as a string (or object for JSON/AST), or void when writing a file
|
|
42872
|
+
* @throws Error if any error occurs
|
|
42873
|
+
*/
|
|
42874
|
+
convertHtmlTable(input, options) {
|
|
42875
|
+
const opts = Object.assign({}, options);
|
|
42876
|
+
if (env.isBrowser && opts.outputFile) {
|
|
42877
|
+
throw new Error("Cannot write to file in browser environment");
|
|
42878
|
+
}
|
|
42879
|
+
let inStr = input;
|
|
42880
|
+
const inputIsString = typeof input === "string";
|
|
42881
|
+
if (env.isNode && inputIsString && fs.existsSync(inStr)) {
|
|
42882
|
+
inStr = fs.readFileSync(inStr, { encoding: "utf8" });
|
|
42883
|
+
}
|
|
42884
|
+
const isHtmlString = (s) => {
|
|
42885
|
+
const t = s.replace(/^\s+/, "");
|
|
42886
|
+
return t.startsWith("<") && /<table/i.test(t);
|
|
42887
|
+
};
|
|
42888
|
+
let htmlInput;
|
|
42889
|
+
if (opts.inputFormat === InputFormat.html) {
|
|
42890
|
+
htmlInput = true;
|
|
42891
|
+
} else if (opts.inputFormat != null) {
|
|
42892
|
+
htmlInput = false;
|
|
42893
|
+
} else {
|
|
42894
|
+
htmlInput = inputIsString && isHtmlString(inStr);
|
|
42895
|
+
}
|
|
42896
|
+
if (htmlInput) {
|
|
42897
|
+
const parser2 = new HtmlTableParser();
|
|
42898
|
+
const bits = parser2.parse(inStr, {
|
|
42899
|
+
tableFormat: opts.tableFormat ?? "table-extended",
|
|
42900
|
+
keepUnknownTags: opts.keepUnknownTags,
|
|
42901
|
+
onWarning: (m) => console.warn(m)
|
|
42902
|
+
});
|
|
42903
|
+
const outputFormat2 = opts.outputFormat ?? Output.bitmark;
|
|
42904
|
+
if (outputFormat2 === "html") {
|
|
42905
|
+
const json2 = this.convert(bits, { outputFormat: Output.json });
|
|
42906
|
+
return this.outputHtml(new HtmlTableGenerator().generate(json2), opts);
|
|
42907
|
+
}
|
|
42908
|
+
return this.convert(bits, {
|
|
42909
|
+
outputFormat: Enum22(Output).fromValue(outputFormat2),
|
|
42910
|
+
outputFile: opts.outputFile,
|
|
42911
|
+
fileOptions: opts.fileOptions,
|
|
42912
|
+
jsonOptions: opts.jsonOptions,
|
|
42913
|
+
bitmarkOptions: opts.bitmarkOptions
|
|
42914
|
+
});
|
|
42915
|
+
}
|
|
42916
|
+
const outputFormat = opts.outputFormat ?? "html";
|
|
42917
|
+
if (outputFormat !== "html") {
|
|
42918
|
+
throw new Error(
|
|
42919
|
+
"convertHtmlTable: non-HTML input can only be converted to HTML. Use convert() for bitmark/JSON/AST conversions."
|
|
42920
|
+
);
|
|
42921
|
+
}
|
|
42922
|
+
const json = this.convert(inputIsString ? inStr : input, { outputFormat: Output.json });
|
|
42923
|
+
return this.outputHtml(new HtmlTableGenerator().generate(json), opts);
|
|
42924
|
+
}
|
|
42925
|
+
/**
|
|
42926
|
+
* Write an HTML string to the configured output file, or return it.
|
|
42927
|
+
*/
|
|
42928
|
+
outputHtml(html, opts) {
|
|
42929
|
+
if (opts.outputFile) {
|
|
42930
|
+
const output = opts.outputFile.toString();
|
|
42931
|
+
const flag = opts.fileOptions?.append ? "a" : "w";
|
|
42932
|
+
fs.ensureDirSync(path.dirname(output));
|
|
42933
|
+
fs.writeFileSync(output, html, { flag });
|
|
42934
|
+
return;
|
|
42935
|
+
}
|
|
42936
|
+
return html;
|
|
42937
|
+
}
|
|
40934
42938
|
/**
|
|
40935
42939
|
* Breakscape bitmark text.
|
|
40936
42940
|
*
|
|
@@ -41209,6 +43213,728 @@ var BoundingBoxIndex = class _BoundingBoxIndex {
|
|
|
41209
43213
|
}
|
|
41210
43214
|
};
|
|
41211
43215
|
|
|
43216
|
+
// src/generator/html/HtmlTableGenerator.ts
|
|
43217
|
+
var MARK_TO_TAG = {
|
|
43218
|
+
bold: "b",
|
|
43219
|
+
italic: "i",
|
|
43220
|
+
superscript: "sup",
|
|
43221
|
+
subscript: "sub",
|
|
43222
|
+
strike: "s",
|
|
43223
|
+
del: "del",
|
|
43224
|
+
ins: "ins",
|
|
43225
|
+
underline: "u",
|
|
43226
|
+
highlight: "mark",
|
|
43227
|
+
code: "code"
|
|
43228
|
+
};
|
|
43229
|
+
var HtmlTableGenerator2 = class {
|
|
43230
|
+
constructor() {
|
|
43231
|
+
__publicField(this, "indentUnit", " ");
|
|
43232
|
+
}
|
|
43233
|
+
/**
|
|
43234
|
+
* Generate HTML table fragments from a string or JSON value.
|
|
43235
|
+
* @returns the concatenated `<table>` fragments, blank-line separated (empty string if none).
|
|
43236
|
+
*/
|
|
43237
|
+
generate(input) {
|
|
43238
|
+
let data = input;
|
|
43239
|
+
if (typeof data === "string") {
|
|
43240
|
+
try {
|
|
43241
|
+
data = JSON.parse(data);
|
|
43242
|
+
} catch {
|
|
43243
|
+
return "";
|
|
43244
|
+
}
|
|
43245
|
+
}
|
|
43246
|
+
const bits = this.collectBits(data);
|
|
43247
|
+
const fragments = [];
|
|
43248
|
+
for (const bit of bits) {
|
|
43249
|
+
const html = this.renderTableBit(bit);
|
|
43250
|
+
if (html) fragments.push(html);
|
|
43251
|
+
}
|
|
43252
|
+
return fragments.join("\n\n");
|
|
43253
|
+
}
|
|
43254
|
+
// --- bit collection -------------------------------------------------------
|
|
43255
|
+
collectBits(data) {
|
|
43256
|
+
const out = [];
|
|
43257
|
+
const visit = (value) => {
|
|
43258
|
+
if (value == null || typeof value !== "object") return;
|
|
43259
|
+
if (Array.isArray(value)) {
|
|
43260
|
+
value.forEach(visit);
|
|
43261
|
+
return;
|
|
43262
|
+
}
|
|
43263
|
+
const obj = value;
|
|
43264
|
+
if ("bit" in obj && obj.bit && typeof obj.bit === "object") {
|
|
43265
|
+
out.push(obj.bit);
|
|
43266
|
+
} else if ("type" in obj) {
|
|
43267
|
+
out.push(obj);
|
|
43268
|
+
}
|
|
43269
|
+
};
|
|
43270
|
+
visit(data);
|
|
43271
|
+
return out;
|
|
43272
|
+
}
|
|
43273
|
+
// --- table rendering ------------------------------------------------------
|
|
43274
|
+
renderTableBit(bit) {
|
|
43275
|
+
const table = bit.table;
|
|
43276
|
+
if (!table) return "";
|
|
43277
|
+
if (bit.type !== "table" && bit.type !== "table-extended") return "";
|
|
43278
|
+
const extended = this.toExtended(table);
|
|
43279
|
+
const lines = [];
|
|
43280
|
+
lines.push("<table>");
|
|
43281
|
+
if (bit.caption != null) {
|
|
43282
|
+
const caption = this.cellContentToHtml(this.asTextAst(bit.caption));
|
|
43283
|
+
if (caption) lines.push(`${this.indentUnit}<caption>${caption}</caption>`);
|
|
43284
|
+
}
|
|
43285
|
+
this.renderSection(lines, "thead", extended.header, "header");
|
|
43286
|
+
this.renderSection(lines, "tbody", extended.body, "body");
|
|
43287
|
+
this.renderSection(lines, "tfoot", extended.footer, "footer");
|
|
43288
|
+
lines.push("</table>");
|
|
43289
|
+
return lines.join("\n");
|
|
43290
|
+
}
|
|
43291
|
+
toExtended(table) {
|
|
43292
|
+
const t = table;
|
|
43293
|
+
if (t.header || t.body || t.footer) return table;
|
|
43294
|
+
return convertBasicToExtendedTableFormat(table);
|
|
43295
|
+
}
|
|
43296
|
+
renderSection(lines, tag, section, key) {
|
|
43297
|
+
if (!section || !section.rows || section.rows.length === 0) return;
|
|
43298
|
+
lines.push(`${this.indentUnit}<${tag}>`);
|
|
43299
|
+
for (const row of section.rows) {
|
|
43300
|
+
lines.push(`${this.indentUnit.repeat(2)}<tr>`);
|
|
43301
|
+
for (const cell of row.cells ?? []) {
|
|
43302
|
+
lines.push(`${this.indentUnit.repeat(3)}${this.renderCell(cell, key)}`);
|
|
43303
|
+
}
|
|
43304
|
+
lines.push(`${this.indentUnit.repeat(2)}</tr>`);
|
|
43305
|
+
}
|
|
43306
|
+
lines.push(`${this.indentUnit}</${tag}>`);
|
|
43307
|
+
}
|
|
43308
|
+
renderCell(cell, _key) {
|
|
43309
|
+
const tag = cell.title === true ? "th" : "td";
|
|
43310
|
+
const attrs = [];
|
|
43311
|
+
if (cell.rowspan && cell.rowspan > 1) attrs.push(`rowspan="${cell.rowspan}"`);
|
|
43312
|
+
if (cell.colspan && cell.colspan > 1) attrs.push(`colspan="${cell.colspan}"`);
|
|
43313
|
+
if (cell.scope) attrs.push(`scope="${cell.scope}"`);
|
|
43314
|
+
if (cell.colwidth && cell.colwidth > 0) attrs.push(`width="${cell.colwidth}"`);
|
|
43315
|
+
const open = attrs.length > 0 ? `<${tag} ${attrs.join(" ")}>` : `<${tag}>`;
|
|
43316
|
+
return `${open}${this.cellContentToHtml(this.asTextAst(cell.content))}</${tag}>`;
|
|
43317
|
+
}
|
|
43318
|
+
// --- cell content (TextAst -> HTML) ---------------------------------------
|
|
43319
|
+
asTextAst(content) {
|
|
43320
|
+
if (content == null) return [];
|
|
43321
|
+
if (typeof content === "string") return [{ type: "text", text: content }];
|
|
43322
|
+
return content;
|
|
43323
|
+
}
|
|
43324
|
+
cellContentToHtml(blocks) {
|
|
43325
|
+
if (blocks.length === 0) return "";
|
|
43326
|
+
if (blocks.length === 1 && blocks[0].type === "paragraph") {
|
|
43327
|
+
return this.inlineToHtml(blocks[0].content ?? []);
|
|
43328
|
+
}
|
|
43329
|
+
return blocks.map((b) => this.blockToHtml(b)).join("");
|
|
43330
|
+
}
|
|
43331
|
+
blockToHtml(node) {
|
|
43332
|
+
switch (node.type) {
|
|
43333
|
+
case "paragraph":
|
|
43334
|
+
return `<p>${this.inlineToHtml(node.content ?? [])}</p>`;
|
|
43335
|
+
case "bulletList":
|
|
43336
|
+
case "noBulletList":
|
|
43337
|
+
case "orderedList":
|
|
43338
|
+
case "orderedListRoman":
|
|
43339
|
+
case "orderedListRomanLower":
|
|
43340
|
+
case "letteredList":
|
|
43341
|
+
case "letteredListLower":
|
|
43342
|
+
case "taskList":
|
|
43343
|
+
return this.listToHtml(node);
|
|
43344
|
+
case "image":
|
|
43345
|
+
case "imageInline":
|
|
43346
|
+
return this.imageToHtml(node);
|
|
43347
|
+
default:
|
|
43348
|
+
return this.inlineToHtml([node]);
|
|
43349
|
+
}
|
|
43350
|
+
}
|
|
43351
|
+
inlineToHtml(nodes) {
|
|
43352
|
+
return nodes.map((n) => this.inlineNodeToHtml(n)).join("");
|
|
43353
|
+
}
|
|
43354
|
+
inlineNodeToHtml(node) {
|
|
43355
|
+
if (node.type === "hardBreak") return "<br>";
|
|
43356
|
+
if (node.type === "image" || node.type === "imageInline") return this.imageToHtml(node);
|
|
43357
|
+
if (node.type === "text") {
|
|
43358
|
+
return this.wrapMarks(this.escapeText(node.text ?? ""), node.marks);
|
|
43359
|
+
}
|
|
43360
|
+
if (node.content) return this.inlineToHtml(node.content);
|
|
43361
|
+
return this.escapeText(node.text ?? "");
|
|
43362
|
+
}
|
|
43363
|
+
wrapMarks(text, marks) {
|
|
43364
|
+
if (!marks || marks.length === 0) return text;
|
|
43365
|
+
let open = "";
|
|
43366
|
+
let close = "";
|
|
43367
|
+
for (const mark of marks) {
|
|
43368
|
+
if (mark.type === "link") {
|
|
43369
|
+
const href = mark.attrs?.href ?? "";
|
|
43370
|
+
open += `<a href="${this.escapeAttr(href)}">`;
|
|
43371
|
+
close = `</a>${close}`;
|
|
43372
|
+
} else {
|
|
43373
|
+
const tag = MARK_TO_TAG[mark.type];
|
|
43374
|
+
if (tag) {
|
|
43375
|
+
open += `<${tag}>`;
|
|
43376
|
+
close = `</${tag}>${close}`;
|
|
43377
|
+
}
|
|
43378
|
+
}
|
|
43379
|
+
}
|
|
43380
|
+
return `${open}${text}${close}`;
|
|
43381
|
+
}
|
|
43382
|
+
// --- lists ----------------------------------------------------------------
|
|
43383
|
+
listToHtml(node) {
|
|
43384
|
+
const { tag, attrs } = this.listTag(node);
|
|
43385
|
+
const items = (node.content ?? []).map((item) => this.listItemToHtml(item, node.type === "taskList")).join("");
|
|
43386
|
+
return `<${tag}${attrs}>${items}</${tag}>`;
|
|
43387
|
+
}
|
|
43388
|
+
listTag(node) {
|
|
43389
|
+
const start = node.attrs?.start;
|
|
43390
|
+
const startAttr = typeof start === "number" && start !== 1 ? ` start="${start}"` : "";
|
|
43391
|
+
switch (node.type) {
|
|
43392
|
+
case "orderedList":
|
|
43393
|
+
return { tag: "ol", attrs: startAttr };
|
|
43394
|
+
case "orderedListRoman":
|
|
43395
|
+
return { tag: "ol", attrs: ` type="I"${startAttr}` };
|
|
43396
|
+
case "orderedListRomanLower":
|
|
43397
|
+
return { tag: "ol", attrs: ` type="i"${startAttr}` };
|
|
43398
|
+
case "letteredList":
|
|
43399
|
+
return { tag: "ol", attrs: ` type="A"${startAttr}` };
|
|
43400
|
+
case "letteredListLower":
|
|
43401
|
+
return { tag: "ol", attrs: ` type="a"${startAttr}` };
|
|
43402
|
+
case "noBulletList":
|
|
43403
|
+
return { tag: "ul", attrs: ' style="list-style:none"' };
|
|
43404
|
+
case "taskList":
|
|
43405
|
+
case "bulletList":
|
|
43406
|
+
default:
|
|
43407
|
+
return { tag: "ul", attrs: "" };
|
|
43408
|
+
}
|
|
43409
|
+
}
|
|
43410
|
+
listItemToHtml(item, task) {
|
|
43411
|
+
const inner = (item.content ?? []).map((b) => {
|
|
43412
|
+
if (b.type === "paragraph") return this.inlineToHtml(b.content ?? []);
|
|
43413
|
+
return this.blockToHtml(b);
|
|
43414
|
+
}).join("");
|
|
43415
|
+
if (task) {
|
|
43416
|
+
const checked = item.attrs?.checked ? " checked" : "";
|
|
43417
|
+
return `<li><input type="checkbox"${checked}>${inner}</li>`;
|
|
43418
|
+
}
|
|
43419
|
+
return `<li>${inner}</li>`;
|
|
43420
|
+
}
|
|
43421
|
+
// --- images ---------------------------------------------------------------
|
|
43422
|
+
imageToHtml(node) {
|
|
43423
|
+
const attrs = node.attrs ?? {};
|
|
43424
|
+
const parts = [];
|
|
43425
|
+
const src = attrs.src;
|
|
43426
|
+
parts.push(`src="${this.escapeAttr(typeof src === "string" ? src : "")}"`);
|
|
43427
|
+
if (typeof attrs.alt === "string") parts.push(`alt="${this.escapeAttr(attrs.alt)}"`);
|
|
43428
|
+
if (typeof attrs.title === "string") parts.push(`title="${this.escapeAttr(attrs.title)}"`);
|
|
43429
|
+
if (attrs.width != null) parts.push(`width="${attrs.width}"`);
|
|
43430
|
+
if (attrs.height != null) parts.push(`height="${attrs.height}"`);
|
|
43431
|
+
if (typeof attrs.class === "string" && attrs.class) {
|
|
43432
|
+
parts.push(`class="${this.escapeAttr(attrs.class)}"`);
|
|
43433
|
+
}
|
|
43434
|
+
return `<img ${parts.join(" ")}>`;
|
|
43435
|
+
}
|
|
43436
|
+
// --- escaping -------------------------------------------------------------
|
|
43437
|
+
escapeText(text) {
|
|
43438
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
43439
|
+
}
|
|
43440
|
+
escapeAttr(text) {
|
|
43441
|
+
return this.escapeText(text).replace(/"/g, """);
|
|
43442
|
+
}
|
|
43443
|
+
};
|
|
43444
|
+
|
|
43445
|
+
// src/parser/html/HtmlDom.ts
|
|
43446
|
+
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
43447
|
+
"area",
|
|
43448
|
+
"base",
|
|
43449
|
+
"br",
|
|
43450
|
+
"col",
|
|
43451
|
+
"embed",
|
|
43452
|
+
"hr",
|
|
43453
|
+
"img",
|
|
43454
|
+
"input",
|
|
43455
|
+
"link",
|
|
43456
|
+
"meta",
|
|
43457
|
+
"param",
|
|
43458
|
+
"source",
|
|
43459
|
+
"track",
|
|
43460
|
+
"wbr"
|
|
43461
|
+
]);
|
|
43462
|
+
var IMPLIED_CLOSE = {
|
|
43463
|
+
li: /* @__PURE__ */ new Set(["li"]),
|
|
43464
|
+
td: /* @__PURE__ */ new Set(["td", "th"]),
|
|
43465
|
+
th: /* @__PURE__ */ new Set(["td", "th"]),
|
|
43466
|
+
tr: /* @__PURE__ */ new Set(["td", "th", "tr"]),
|
|
43467
|
+
thead: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
|
|
43468
|
+
tbody: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
|
|
43469
|
+
tfoot: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
|
|
43470
|
+
p: /* @__PURE__ */ new Set(["p"]),
|
|
43471
|
+
option: /* @__PURE__ */ new Set(["option"])
|
|
43472
|
+
};
|
|
43473
|
+
var TAG_RE = /<(\/)?([a-zA-Z][a-zA-Z0-9-]*)((?:\s+(?:"[^"]*"|'[^']*'|[^<>"'])*)?)(\/)?>/g;
|
|
43474
|
+
var ATTR_RE = /([a-zA-Z_:][a-zA-Z0-9:._-]*)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s"'>]+))?/g;
|
|
43475
|
+
function parseAttrs(raw) {
|
|
43476
|
+
const attrs = {};
|
|
43477
|
+
if (!raw) return attrs;
|
|
43478
|
+
ATTR_RE.lastIndex = 0;
|
|
43479
|
+
let m;
|
|
43480
|
+
while ((m = ATTR_RE.exec(raw)) !== null) {
|
|
43481
|
+
const name = m[1].toLowerCase();
|
|
43482
|
+
let value = m[2] ?? "";
|
|
43483
|
+
if (value.length >= 2 && (value[0] === '"' || value[0] === "'")) {
|
|
43484
|
+
value = value.slice(1, -1);
|
|
43485
|
+
}
|
|
43486
|
+
attrs[name] = value;
|
|
43487
|
+
}
|
|
43488
|
+
return attrs;
|
|
43489
|
+
}
|
|
43490
|
+
function stripNonContent(html) {
|
|
43491
|
+
return html.replace(/<!--[\s\S]*?-->/g, "").replace(/<!\[CDATA\[[\s\S]*?\]\]>/g, "").replace(/<!doctype[^>]*>/gi, "").replace(/<script\b[\s\S]*?<\/script>/gi, "").replace(/<style\b[\s\S]*?<\/style>/gi, "");
|
|
43492
|
+
}
|
|
43493
|
+
function tokenize(html) {
|
|
43494
|
+
const tokens = [];
|
|
43495
|
+
const clean = stripNonContent(html);
|
|
43496
|
+
TAG_RE.lastIndex = 0;
|
|
43497
|
+
let lastIndex = 0;
|
|
43498
|
+
let m;
|
|
43499
|
+
while ((m = TAG_RE.exec(clean)) !== null) {
|
|
43500
|
+
if (m.index > lastIndex) {
|
|
43501
|
+
tokens.push({ kind: "text", text: clean.slice(lastIndex, m.index) });
|
|
43502
|
+
}
|
|
43503
|
+
lastIndex = TAG_RE.lastIndex;
|
|
43504
|
+
const isClose = m[1] === "/";
|
|
43505
|
+
const name = m[2].toLowerCase();
|
|
43506
|
+
if (isClose) {
|
|
43507
|
+
tokens.push({ kind: "close", name });
|
|
43508
|
+
} else {
|
|
43509
|
+
tokens.push({
|
|
43510
|
+
kind: "open",
|
|
43511
|
+
name,
|
|
43512
|
+
attrs: parseAttrs(m[3]),
|
|
43513
|
+
selfClose: m[4] === "/"
|
|
43514
|
+
});
|
|
43515
|
+
}
|
|
43516
|
+
}
|
|
43517
|
+
if (lastIndex < clean.length) {
|
|
43518
|
+
tokens.push({ kind: "text", text: clean.slice(lastIndex) });
|
|
43519
|
+
}
|
|
43520
|
+
return tokens;
|
|
43521
|
+
}
|
|
43522
|
+
function parseHtml(html) {
|
|
43523
|
+
const root = { type: "element", name: "#root", attrs: {}, children: [] };
|
|
43524
|
+
const stack = [root];
|
|
43525
|
+
const top = () => stack[stack.length - 1];
|
|
43526
|
+
for (const token of tokenize(html)) {
|
|
43527
|
+
if (token.kind === "text") {
|
|
43528
|
+
if (token.text) top().children.push({ type: "text", value: token.text });
|
|
43529
|
+
continue;
|
|
43530
|
+
}
|
|
43531
|
+
if (token.kind === "open") {
|
|
43532
|
+
const name = token.name;
|
|
43533
|
+
const closes = IMPLIED_CLOSE[name];
|
|
43534
|
+
if (closes) {
|
|
43535
|
+
while (stack.length > 1 && closes.has(top().name)) stack.pop();
|
|
43536
|
+
}
|
|
43537
|
+
const el = {
|
|
43538
|
+
type: "element",
|
|
43539
|
+
name,
|
|
43540
|
+
attrs: token.attrs ?? {},
|
|
43541
|
+
children: []
|
|
43542
|
+
};
|
|
43543
|
+
top().children.push(el);
|
|
43544
|
+
if (!token.selfClose && !VOID_ELEMENTS.has(name)) {
|
|
43545
|
+
stack.push(el);
|
|
43546
|
+
}
|
|
43547
|
+
continue;
|
|
43548
|
+
}
|
|
43549
|
+
for (let i = stack.length - 1; i > 0; i--) {
|
|
43550
|
+
if (stack[i].name === token.name) {
|
|
43551
|
+
stack.length = i;
|
|
43552
|
+
break;
|
|
43553
|
+
}
|
|
43554
|
+
}
|
|
43555
|
+
}
|
|
43556
|
+
return root.children;
|
|
43557
|
+
}
|
|
43558
|
+
function childElements(el, names) {
|
|
43559
|
+
return el.children.filter((c) => c.type === "element" && names.has(c.name));
|
|
43560
|
+
}
|
|
43561
|
+
|
|
43562
|
+
// src/parser/html/HtmlTableParser.ts
|
|
43563
|
+
var MARK_TAGS = {
|
|
43564
|
+
b: "bold",
|
|
43565
|
+
strong: "bold",
|
|
43566
|
+
i: "italic",
|
|
43567
|
+
em: "italic",
|
|
43568
|
+
sup: "superscript",
|
|
43569
|
+
sub: "subscript",
|
|
43570
|
+
s: "strike",
|
|
43571
|
+
strike: "strike",
|
|
43572
|
+
del: "del",
|
|
43573
|
+
ins: "ins",
|
|
43574
|
+
u: "underline",
|
|
43575
|
+
mark: "highlight",
|
|
43576
|
+
code: "code"
|
|
43577
|
+
};
|
|
43578
|
+
var SECTION_TAGS = /* @__PURE__ */ new Set(["thead", "tbody", "tfoot"]);
|
|
43579
|
+
var ROW_TAGS = /* @__PURE__ */ new Set(["tr"]);
|
|
43580
|
+
var CELL_TAGS = /* @__PURE__ */ new Set(["td", "th"]);
|
|
43581
|
+
var LI_TAGS = /* @__PURE__ */ new Set(["li"]);
|
|
43582
|
+
var VALID_SCOPES = /* @__PURE__ */ new Set(["row", "col", "rowgroup", "colgroup"]);
|
|
43583
|
+
var NAMED_ENTITIES = {
|
|
43584
|
+
amp: "&",
|
|
43585
|
+
lt: "<",
|
|
43586
|
+
gt: ">",
|
|
43587
|
+
quot: '"',
|
|
43588
|
+
apos: "'",
|
|
43589
|
+
nbsp: "\xA0"
|
|
43590
|
+
};
|
|
43591
|
+
function decodeEntities(text) {
|
|
43592
|
+
return text.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z][a-zA-Z0-9]*);/g, (whole, body) => {
|
|
43593
|
+
if (body[0] === "#") {
|
|
43594
|
+
const code = body[1] === "x" || body[1] === "X" ? Number.parseInt(body.slice(2), 16) : Number.parseInt(body.slice(1), 10);
|
|
43595
|
+
if (Number.isFinite(code) && code >= 0 && code <= 1114111) {
|
|
43596
|
+
try {
|
|
43597
|
+
return String.fromCodePoint(code);
|
|
43598
|
+
} catch {
|
|
43599
|
+
return whole;
|
|
43600
|
+
}
|
|
43601
|
+
}
|
|
43602
|
+
return whole;
|
|
43603
|
+
}
|
|
43604
|
+
return NAMED_ENTITIES[body] ?? whole;
|
|
43605
|
+
});
|
|
43606
|
+
}
|
|
43607
|
+
function intAttr(value) {
|
|
43608
|
+
if (value == null) return void 0;
|
|
43609
|
+
const n = Number.parseInt(value, 10);
|
|
43610
|
+
return Number.isInteger(n) ? n : void 0;
|
|
43611
|
+
}
|
|
43612
|
+
function isElement(node) {
|
|
43613
|
+
return node.type === "element";
|
|
43614
|
+
}
|
|
43615
|
+
var HtmlTableParser2 = class {
|
|
43616
|
+
constructor() {
|
|
43617
|
+
__publicField(this, "keepUnknownTags", false);
|
|
43618
|
+
}
|
|
43619
|
+
/**
|
|
43620
|
+
* Parse an HTML string and return one table bit per top-level `<table>`.
|
|
43621
|
+
*/
|
|
43622
|
+
parse(html, options) {
|
|
43623
|
+
this.keepUnknownTags = options?.keepUnknownTags ?? false;
|
|
43624
|
+
const tableFormat = options?.tableFormat ?? "table-extended";
|
|
43625
|
+
const onWarning = options?.onWarning;
|
|
43626
|
+
const tables = this.collectTopLevelTables(parseHtml(html));
|
|
43627
|
+
const bits = [];
|
|
43628
|
+
for (const table of tables) {
|
|
43629
|
+
const bit = this.tableToBit(table, tableFormat, onWarning);
|
|
43630
|
+
if (bit) bits.push(bit);
|
|
43631
|
+
}
|
|
43632
|
+
return bits;
|
|
43633
|
+
}
|
|
43634
|
+
// --- table extraction -----------------------------------------------------
|
|
43635
|
+
/** Collect every `<table>` element, NOT descending into nested tables. */
|
|
43636
|
+
collectTopLevelTables(nodes) {
|
|
43637
|
+
const tables = [];
|
|
43638
|
+
const visit = (node) => {
|
|
43639
|
+
if (!isElement(node)) return;
|
|
43640
|
+
if (node.name === "table") {
|
|
43641
|
+
tables.push(node);
|
|
43642
|
+
return;
|
|
43643
|
+
}
|
|
43644
|
+
node.children.forEach(visit);
|
|
43645
|
+
};
|
|
43646
|
+
nodes.forEach(visit);
|
|
43647
|
+
return tables;
|
|
43648
|
+
}
|
|
43649
|
+
tableToBit(table, tableFormat, onWarning) {
|
|
43650
|
+
const header = [];
|
|
43651
|
+
const body = [];
|
|
43652
|
+
const footer = [];
|
|
43653
|
+
let caption;
|
|
43654
|
+
for (const child of table.children) {
|
|
43655
|
+
if (!isElement(child)) continue;
|
|
43656
|
+
if (child.name === "caption") {
|
|
43657
|
+
const capContent = this.inlineNodes(child.children, []);
|
|
43658
|
+
const trimmed = this.trimInline(capContent);
|
|
43659
|
+
if (trimmed.length > 0) caption = trimmed;
|
|
43660
|
+
} else if (SECTION_TAGS.has(child.name)) {
|
|
43661
|
+
const target = child.name === "thead" ? header : child.name === "tfoot" ? footer : body;
|
|
43662
|
+
for (const tr of childElements(child, ROW_TAGS)) {
|
|
43663
|
+
target.push(this.rowToCells(tr));
|
|
43664
|
+
}
|
|
43665
|
+
} else if (ROW_TAGS.has(child.name)) {
|
|
43666
|
+
body.push(this.rowToCells(child));
|
|
43667
|
+
}
|
|
43668
|
+
}
|
|
43669
|
+
if (header.length === 0 && body.length === 0 && footer.length === 0) {
|
|
43670
|
+
return void 0;
|
|
43671
|
+
}
|
|
43672
|
+
const tableExtended = {};
|
|
43673
|
+
if (header.length > 0) tableExtended.header = { rows: header };
|
|
43674
|
+
if (body.length > 0) tableExtended.body = { rows: body };
|
|
43675
|
+
if (footer.length > 0) tableExtended.footer = { rows: footer };
|
|
43676
|
+
let tableData = tableExtended;
|
|
43677
|
+
if (tableFormat === "table") {
|
|
43678
|
+
if (this.isLossyAsBasic(tableExtended)) {
|
|
43679
|
+
onWarning?.(
|
|
43680
|
+
"Converting an HTML table to [.table] loses rowspan/colspan/scope and multi-section structure; use --tableFormat table-extended to preserve them."
|
|
43681
|
+
);
|
|
43682
|
+
}
|
|
43683
|
+
tableData = convertExtendedToBasicTableFormat(tableExtended);
|
|
43684
|
+
}
|
|
43685
|
+
const bit = {
|
|
43686
|
+
type: tableFormat,
|
|
43687
|
+
format: "bitmark++",
|
|
43688
|
+
table: tableData
|
|
43689
|
+
};
|
|
43690
|
+
if (caption) bit.caption = caption;
|
|
43691
|
+
return bit;
|
|
43692
|
+
}
|
|
43693
|
+
rowToCells(tr) {
|
|
43694
|
+
const cells = [];
|
|
43695
|
+
for (const cell of childElements(tr, CELL_TAGS)) {
|
|
43696
|
+
cells.push(this.cellToJson(cell));
|
|
43697
|
+
}
|
|
43698
|
+
return { cells };
|
|
43699
|
+
}
|
|
43700
|
+
cellToJson(cell) {
|
|
43701
|
+
const json = {
|
|
43702
|
+
content: this.blockNodes(cell.children)
|
|
43703
|
+
};
|
|
43704
|
+
if (cell.name === "th") json.title = true;
|
|
43705
|
+
const rowspan = intAttr(cell.attrs.rowspan);
|
|
43706
|
+
if (rowspan != null && rowspan >= 2) json.rowspan = rowspan;
|
|
43707
|
+
const colspan = intAttr(cell.attrs.colspan);
|
|
43708
|
+
if (colspan != null && colspan >= 2) json.colspan = colspan;
|
|
43709
|
+
const scope = cell.attrs.scope?.toLowerCase();
|
|
43710
|
+
if (scope && VALID_SCOPES.has(scope)) {
|
|
43711
|
+
json.scope = scope;
|
|
43712
|
+
}
|
|
43713
|
+
const width = this.widthFromCell(cell);
|
|
43714
|
+
if (width != null) json.colwidth = width;
|
|
43715
|
+
return json;
|
|
43716
|
+
}
|
|
43717
|
+
widthFromCell(cell) {
|
|
43718
|
+
const attrWidth = intAttr(cell.attrs.width);
|
|
43719
|
+
if (attrWidth != null && attrWidth > 0) return attrWidth;
|
|
43720
|
+
const style = cell.attrs.style;
|
|
43721
|
+
if (style) {
|
|
43722
|
+
const m = style.match(/width\s*:\s*(\d+)\s*px/i);
|
|
43723
|
+
if (m) {
|
|
43724
|
+
const n = Number.parseInt(m[1], 10);
|
|
43725
|
+
if (Number.isInteger(n) && n > 0) return n;
|
|
43726
|
+
}
|
|
43727
|
+
}
|
|
43728
|
+
return void 0;
|
|
43729
|
+
}
|
|
43730
|
+
isLossyAsBasic(table) {
|
|
43731
|
+
if (table.footer) return true;
|
|
43732
|
+
if (table.header && table.header.rows.length > 1) return true;
|
|
43733
|
+
const sections = [table.header, table.body, table.footer];
|
|
43734
|
+
for (const section of sections) {
|
|
43735
|
+
if (!section) continue;
|
|
43736
|
+
for (const row of section.rows) {
|
|
43737
|
+
for (const cell of row.cells) {
|
|
43738
|
+
if (cell.rowspan || cell.colspan || cell.scope) return true;
|
|
43739
|
+
}
|
|
43740
|
+
}
|
|
43741
|
+
}
|
|
43742
|
+
return false;
|
|
43743
|
+
}
|
|
43744
|
+
// --- content conversion (HTML -> TextAst) ---------------------------------
|
|
43745
|
+
/**
|
|
43746
|
+
* Convert a cell/li's child nodes into block-level TextAst nodes (paragraphs, lists, images).
|
|
43747
|
+
*/
|
|
43748
|
+
blockNodes(nodes) {
|
|
43749
|
+
const blocks = [];
|
|
43750
|
+
let inline = [];
|
|
43751
|
+
const flush = () => {
|
|
43752
|
+
const trimmed = this.trimInline(inline);
|
|
43753
|
+
inline = [];
|
|
43754
|
+
if (trimmed.length === 0) return;
|
|
43755
|
+
if (trimmed.length === 1 && trimmed[0].type === "imageInline") {
|
|
43756
|
+
blocks.push({ ...trimmed[0], type: "image" });
|
|
43757
|
+
} else {
|
|
43758
|
+
blocks.push({ type: "paragraph", content: trimmed, attrs: {} });
|
|
43759
|
+
}
|
|
43760
|
+
};
|
|
43761
|
+
for (const node of nodes) {
|
|
43762
|
+
if (!isElement(node)) {
|
|
43763
|
+
inline.push(...this.inlineText(node.value, []));
|
|
43764
|
+
continue;
|
|
43765
|
+
}
|
|
43766
|
+
const name = node.name;
|
|
43767
|
+
if (name === "p") {
|
|
43768
|
+
flush();
|
|
43769
|
+
const content = this.trimInline(this.inlineNodes(node.children, []));
|
|
43770
|
+
if (content.length > 0) {
|
|
43771
|
+
blocks.push({ type: "paragraph", content, attrs: {} });
|
|
43772
|
+
}
|
|
43773
|
+
} else if (this.isListTag(name)) {
|
|
43774
|
+
flush();
|
|
43775
|
+
const list = this.listNode(node);
|
|
43776
|
+
if (list) blocks.push(list);
|
|
43777
|
+
} else {
|
|
43778
|
+
inline.push(...this.inlineFromElement(node, []));
|
|
43779
|
+
}
|
|
43780
|
+
}
|
|
43781
|
+
flush();
|
|
43782
|
+
return blocks;
|
|
43783
|
+
}
|
|
43784
|
+
/** Convert child nodes to a flat list of inline TextNodes, applying the given marks. */
|
|
43785
|
+
inlineNodes(nodes, marks) {
|
|
43786
|
+
const out = [];
|
|
43787
|
+
for (const node of nodes) {
|
|
43788
|
+
if (!isElement(node)) {
|
|
43789
|
+
out.push(...this.inlineText(node.value, marks));
|
|
43790
|
+
} else {
|
|
43791
|
+
out.push(...this.inlineFromElement(node, marks));
|
|
43792
|
+
}
|
|
43793
|
+
}
|
|
43794
|
+
return out;
|
|
43795
|
+
}
|
|
43796
|
+
inlineFromElement(el, marks) {
|
|
43797
|
+
const name = el.name;
|
|
43798
|
+
if (name === "br") {
|
|
43799
|
+
return [{ type: "hardBreak" }];
|
|
43800
|
+
}
|
|
43801
|
+
if (name === "img") {
|
|
43802
|
+
return [this.imageNode(el, true)];
|
|
43803
|
+
}
|
|
43804
|
+
const markType = MARK_TAGS[name];
|
|
43805
|
+
if (markType) {
|
|
43806
|
+
return this.inlineNodes(el.children, [...marks, { type: markType }]);
|
|
43807
|
+
}
|
|
43808
|
+
if (name === "a") {
|
|
43809
|
+
const linkMark = {
|
|
43810
|
+
type: "link",
|
|
43811
|
+
attrs: {
|
|
43812
|
+
href: el.attrs.href ?? "",
|
|
43813
|
+
...el.attrs.target ? { target: el.attrs.target } : {}
|
|
43814
|
+
}
|
|
43815
|
+
};
|
|
43816
|
+
return this.inlineNodes(el.children, [...marks, linkMark]);
|
|
43817
|
+
}
|
|
43818
|
+
if (this.keepUnknownTags) {
|
|
43819
|
+
const open = this.serializeOpenTag(el);
|
|
43820
|
+
const close = `</${name}>`;
|
|
43821
|
+
return [
|
|
43822
|
+
...this.inlineText(open, marks),
|
|
43823
|
+
...this.inlineNodes(el.children, marks),
|
|
43824
|
+
...this.inlineText(close, marks)
|
|
43825
|
+
];
|
|
43826
|
+
}
|
|
43827
|
+
return this.inlineNodes(el.children, marks);
|
|
43828
|
+
}
|
|
43829
|
+
inlineText(raw, marks) {
|
|
43830
|
+
const text = decodeEntities(raw).replace(/\s+/g, " ");
|
|
43831
|
+
if (text === "") return [];
|
|
43832
|
+
const node = { text, type: "text" };
|
|
43833
|
+
if (marks.length > 0) node.marks = marks.map((m) => ({ ...m }));
|
|
43834
|
+
return [node];
|
|
43835
|
+
}
|
|
43836
|
+
serializeOpenTag(el) {
|
|
43837
|
+
const attrs = Object.entries(el.attrs).map(([k, v]) => v === "" ? ` ${k}` : ` ${k}="${v}"`).join("");
|
|
43838
|
+
return `<${el.name}${attrs}>`;
|
|
43839
|
+
}
|
|
43840
|
+
// --- lists ----------------------------------------------------------------
|
|
43841
|
+
isListTag(name) {
|
|
43842
|
+
return name === "ul" || name === "ol";
|
|
43843
|
+
}
|
|
43844
|
+
listNode(el) {
|
|
43845
|
+
const items = childElements(el, LI_TAGS);
|
|
43846
|
+
if (items.length === 0) return void 0;
|
|
43847
|
+
const isTask = el.name === "ul" && items.some((li) => {
|
|
43848
|
+
const firstEl = li.children.find(isElement);
|
|
43849
|
+
return firstEl?.name === "input" && firstEl.attrs.type?.toLowerCase() === "checkbox";
|
|
43850
|
+
});
|
|
43851
|
+
if (isTask) {
|
|
43852
|
+
return {
|
|
43853
|
+
type: "taskList",
|
|
43854
|
+
content: items.map((li) => this.taskItemNode(li))
|
|
43855
|
+
};
|
|
43856
|
+
}
|
|
43857
|
+
const type = this.listType(el);
|
|
43858
|
+
const node = {
|
|
43859
|
+
type,
|
|
43860
|
+
content: items.map((li) => this.listItemNode(li))
|
|
43861
|
+
};
|
|
43862
|
+
if (el.name === "ol") {
|
|
43863
|
+
const start = intAttr(el.attrs.start);
|
|
43864
|
+
if (start != null) {
|
|
43865
|
+
node.attrs = { start };
|
|
43866
|
+
}
|
|
43867
|
+
}
|
|
43868
|
+
return node;
|
|
43869
|
+
}
|
|
43870
|
+
listType(el) {
|
|
43871
|
+
if (el.name === "ol") {
|
|
43872
|
+
switch (el.attrs.type) {
|
|
43873
|
+
case "i":
|
|
43874
|
+
return "orderedListRomanLower";
|
|
43875
|
+
case "I":
|
|
43876
|
+
return "orderedListRoman";
|
|
43877
|
+
case "a":
|
|
43878
|
+
return "letteredListLower";
|
|
43879
|
+
case "A":
|
|
43880
|
+
return "letteredList";
|
|
43881
|
+
default:
|
|
43882
|
+
return "orderedList";
|
|
43883
|
+
}
|
|
43884
|
+
}
|
|
43885
|
+
const style = el.attrs.style ?? "";
|
|
43886
|
+
if (/list-style(-type)?\s*:\s*none/i.test(style)) return "noBulletList";
|
|
43887
|
+
return "bulletList";
|
|
43888
|
+
}
|
|
43889
|
+
listItemNode(li) {
|
|
43890
|
+
let content = this.blockNodes(li.children);
|
|
43891
|
+
if (content.length === 0) {
|
|
43892
|
+
content = [{ type: "paragraph", content: [], attrs: {} }];
|
|
43893
|
+
}
|
|
43894
|
+
return { type: "listItem", content };
|
|
43895
|
+
}
|
|
43896
|
+
taskItemNode(li) {
|
|
43897
|
+
const checkbox = li.children.find(
|
|
43898
|
+
(c) => isElement(c) && c.name === "input" && c.attrs.type?.toLowerCase() === "checkbox"
|
|
43899
|
+
);
|
|
43900
|
+
const checked = checkbox ? "checked" in checkbox.attrs : false;
|
|
43901
|
+
const rest = li.children.filter((c) => c !== checkbox);
|
|
43902
|
+
let content = this.blockNodes(rest);
|
|
43903
|
+
if (content.length === 0) {
|
|
43904
|
+
content = [{ type: "paragraph", content: [], attrs: {} }];
|
|
43905
|
+
}
|
|
43906
|
+
return { type: "taskItem", attrs: { checked }, content };
|
|
43907
|
+
}
|
|
43908
|
+
// --- images ---------------------------------------------------------------
|
|
43909
|
+
imageNode(el, inline) {
|
|
43910
|
+
const attrs = { src: el.attrs.src ?? "" };
|
|
43911
|
+
attrs.alt = el.attrs.alt ?? null;
|
|
43912
|
+
attrs.title = el.attrs.title ?? null;
|
|
43913
|
+
const width = intAttr(el.attrs.width);
|
|
43914
|
+
if (width != null) attrs.width = width;
|
|
43915
|
+
const height = intAttr(el.attrs.height);
|
|
43916
|
+
if (height != null) attrs.height = height;
|
|
43917
|
+
if (el.attrs.class) attrs.class = el.attrs.class;
|
|
43918
|
+
return { type: inline ? "imageInline" : "image", attrs };
|
|
43919
|
+
}
|
|
43920
|
+
// --- whitespace -----------------------------------------------------------
|
|
43921
|
+
/** Trim leading/trailing whitespace from inline content (edges only). */
|
|
43922
|
+
trimInline(nodes) {
|
|
43923
|
+
const out = nodes.slice();
|
|
43924
|
+
const isWs = (n) => n.type === "text" && /^\s*$/.test(n.text ?? "");
|
|
43925
|
+
while (out.length > 0 && isWs(out[0])) out.shift();
|
|
43926
|
+
if (out.length > 0 && out[0].type === "text") {
|
|
43927
|
+
out[0] = { ...out[0], text: (out[0].text ?? "").replace(/^\s+/, "") };
|
|
43928
|
+
}
|
|
43929
|
+
while (out.length > 0 && isWs(out[out.length - 1])) out.pop();
|
|
43930
|
+
if (out.length > 0 && out[out.length - 1].type === "text") {
|
|
43931
|
+
const last = out.length - 1;
|
|
43932
|
+
out[last] = { ...out[last], text: (out[last].text ?? "").replace(/\s+$/, "") };
|
|
43933
|
+
}
|
|
43934
|
+
return out.filter((n) => !(n.type === "text" && n.text === ""));
|
|
43935
|
+
}
|
|
43936
|
+
};
|
|
43937
|
+
|
|
41212
43938
|
// src/index.ts
|
|
41213
43939
|
init();
|
|
41214
43940
|
export {
|
|
@@ -41224,6 +43950,8 @@ export {
|
|
|
41224
43950
|
BoundingBoxIndex,
|
|
41225
43951
|
Builder,
|
|
41226
43952
|
CardSetVersion,
|
|
43953
|
+
HtmlTableGenerator2 as HtmlTableGenerator,
|
|
43954
|
+
HtmlTableParser2 as HtmlTableParser,
|
|
41227
43955
|
InfoFormat,
|
|
41228
43956
|
InfoType,
|
|
41229
43957
|
Input,
|