@gmb/bitmark-parser-generator 5.24.0 → 5.26.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 +1040 -17
- package/dist/browser/cjs/index.cjs.map +1 -1
- package/dist/browser/cjs/index.d.cts +175 -1
- package/dist/browser/esm/index.d.ts +175 -1
- package/dist/browser/esm/index.js +1038 -17
- package/dist/browser/esm/index.js.map +1 -1
- package/dist/cli/main.js +1155 -75
- package/dist/cli/main.js.map +1 -1
- package/dist/index.cjs +1040 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +175 -1
- package/dist/index.d.ts +175 -1
- package/dist/index.js +1038 -17
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/cli/main.js
CHANGED
|
@@ -2,7 +2,7 @@ import process2 from 'process';
|
|
|
2
2
|
import { Command, Option, Help, Argument, InvalidArgumentError } from 'commander';
|
|
3
3
|
import { Enum } from '@ncoderz/superenum';
|
|
4
4
|
import path3 from 'path';
|
|
5
|
-
import
|
|
5
|
+
import fs4 from 'fs-extra';
|
|
6
6
|
import 'fs';
|
|
7
7
|
import os from 'os';
|
|
8
8
|
|
|
@@ -230,6 +230,7 @@ var BitType = {
|
|
|
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 BitType = {
|
|
|
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 BitType = {
|
|
|
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",
|
|
@@ -711,6 +716,7 @@ var CardSetConfigKey = {
|
|
|
711
716
|
flashcard: "flashcard",
|
|
712
717
|
flashcard1: "flashcard1",
|
|
713
718
|
definitionList: "definitionList",
|
|
719
|
+
definitionListPlain: "definitionListPlain",
|
|
714
720
|
elements: "elements",
|
|
715
721
|
statements: "statements",
|
|
716
722
|
quiz: "quiz",
|
|
@@ -1309,6 +1315,7 @@ var propertyKeys = {
|
|
|
1309
1315
|
property_enforceUpdateOverUserInput: "@enforceUpdateOverUserInput",
|
|
1310
1316
|
property_extractorExtractionTimestamp: "@extractorExtractionTimestamp",
|
|
1311
1317
|
property_isCaseSensitive: "@isCaseSensitive",
|
|
1318
|
+
property_isCollapsible: "@isCollapsible",
|
|
1312
1319
|
property_isInfoOnly: "@isInfoOnly",
|
|
1313
1320
|
property_isPublic: "@isPublic",
|
|
1314
1321
|
property_isTemplate: "@isTemplate",
|
|
@@ -2504,6 +2511,126 @@ var CARDSETS = {
|
|
|
2504
2511
|
]
|
|
2505
2512
|
},
|
|
2506
2513
|
//
|
|
2514
|
+
// definition-list-plain
|
|
2515
|
+
//
|
|
2516
|
+
// Same shape as `definitionList`, but every variant body is rendered as
|
|
2517
|
+
// plain text (string), not bitmark+ AST. Used by
|
|
2518
|
+
// `meta-search-default-terms` / `meta-search-default-topics`, which need
|
|
2519
|
+
// term/definition text emitted verbatim instead of as a ProseMirror tree.
|
|
2520
|
+
//
|
|
2521
|
+
[CardSetConfigKey.definitionListPlain]: {
|
|
2522
|
+
jsonKey: "definitions",
|
|
2523
|
+
exportJsonKey: { definitions: "$" },
|
|
2524
|
+
sides: [
|
|
2525
|
+
{
|
|
2526
|
+
name: "term",
|
|
2527
|
+
variants: [
|
|
2528
|
+
{
|
|
2529
|
+
jsonKey: "term.text",
|
|
2530
|
+
exportJsonKey: [{ "@absent": { term: {} } }, { term: { text: "$" } }],
|
|
2531
|
+
format: TextFormat.plainText,
|
|
2532
|
+
tags: [
|
|
2533
|
+
{
|
|
2534
|
+
key: ConfigKey.group_standardTags,
|
|
2535
|
+
description: "Standard tags for the definition."
|
|
2536
|
+
},
|
|
2537
|
+
{
|
|
2538
|
+
key: ConfigKey.tag_title,
|
|
2539
|
+
description: "Title of the definition.",
|
|
2540
|
+
format: TagFormat.plainText,
|
|
2541
|
+
jsonKey: "^heading.forKeys",
|
|
2542
|
+
exportJsonKey: { "@bit": { heading: { forKeys: "$" } } }
|
|
2543
|
+
},
|
|
2544
|
+
{
|
|
2545
|
+
key: ConfigKey.group_resourceIcon,
|
|
2546
|
+
description: "Icon resource for the definition.",
|
|
2547
|
+
format: TagFormat.plainText,
|
|
2548
|
+
jsonKey: "term.icon|resource(type=image, key=image)",
|
|
2549
|
+
exportJsonKey: { term: { icon: { type: "image", image: { src: "$" } } } }
|
|
2550
|
+
},
|
|
2551
|
+
{
|
|
2552
|
+
key: ConfigKey.property_example,
|
|
2553
|
+
exportJsonKey: [
|
|
2554
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2555
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2556
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2557
|
+
],
|
|
2558
|
+
description: "Example marker for the definition term.",
|
|
2559
|
+
format: TagFormat.bitmarkText,
|
|
2560
|
+
nullable: true
|
|
2561
|
+
}
|
|
2562
|
+
]
|
|
2563
|
+
}
|
|
2564
|
+
]
|
|
2565
|
+
},
|
|
2566
|
+
{
|
|
2567
|
+
name: "definition",
|
|
2568
|
+
variants: [
|
|
2569
|
+
{
|
|
2570
|
+
jsonKey: "definition.text",
|
|
2571
|
+
exportJsonKey: [{ "@absent": { definition: {} } }, { definition: { text: "$" } }],
|
|
2572
|
+
format: TextFormat.plainText,
|
|
2573
|
+
tags: [
|
|
2574
|
+
{
|
|
2575
|
+
key: ConfigKey.group_standardTags,
|
|
2576
|
+
description: "Standard tags for the definition."
|
|
2577
|
+
},
|
|
2578
|
+
{
|
|
2579
|
+
key: ConfigKey.tag_title,
|
|
2580
|
+
description: "Title of the definition.",
|
|
2581
|
+
format: TagFormat.plainText,
|
|
2582
|
+
jsonKey: "^heading.forValues",
|
|
2583
|
+
exportJsonKey: { "@bit": { heading: { forValues: "$" } } }
|
|
2584
|
+
},
|
|
2585
|
+
{
|
|
2586
|
+
key: ConfigKey.group_resourceIcon,
|
|
2587
|
+
description: "Icon resource for the definition.",
|
|
2588
|
+
jsonKey: "definition.icon|resource(type=image, key=image)",
|
|
2589
|
+
exportJsonKey: { definition: { icon: { type: "image", image: { src: "$" } } } }
|
|
2590
|
+
},
|
|
2591
|
+
{
|
|
2592
|
+
key: ConfigKey.property_example,
|
|
2593
|
+
exportJsonKey: [
|
|
2594
|
+
{ "@keyonly": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2595
|
+
{ "@absent": { isExample: true, example: true, "@bit": { isExample: true } } },
|
|
2596
|
+
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
2597
|
+
],
|
|
2598
|
+
description: "Example marker for the definition.",
|
|
2599
|
+
format: TagFormat.bitmarkText,
|
|
2600
|
+
nullable: true
|
|
2601
|
+
}
|
|
2602
|
+
]
|
|
2603
|
+
},
|
|
2604
|
+
{
|
|
2605
|
+
jsonKey: "alternativeDefinitions[].text",
|
|
2606
|
+
exportJsonKey: { alternativeDefinitions: [{ text: "$" }] },
|
|
2607
|
+
format: TextFormat.plainText,
|
|
2608
|
+
tags: [
|
|
2609
|
+
{
|
|
2610
|
+
key: ConfigKey.group_standardTags,
|
|
2611
|
+
description: "Standard tags for the definition."
|
|
2612
|
+
},
|
|
2613
|
+
{
|
|
2614
|
+
exportJsonKey: { title: "$" },
|
|
2615
|
+
key: ConfigKey.tag_title,
|
|
2616
|
+
description: "Title of the definition."
|
|
2617
|
+
},
|
|
2618
|
+
{
|
|
2619
|
+
key: ConfigKey.group_resourceIcon,
|
|
2620
|
+
description: "Icon resource for the definition.",
|
|
2621
|
+
jsonKey: "alternativeDefinitions[].icon|resource(type=image, key=image)",
|
|
2622
|
+
exportJsonKey: {
|
|
2623
|
+
alternativeDefinitions: [{ icon: { type: "image", image: { src: "$" } } }]
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
],
|
|
2627
|
+
repeatCount: Count.infinity
|
|
2628
|
+
}
|
|
2629
|
+
]
|
|
2630
|
+
}
|
|
2631
|
+
]
|
|
2632
|
+
},
|
|
2633
|
+
//
|
|
2507
2634
|
// match-pairs
|
|
2508
2635
|
//
|
|
2509
2636
|
[CardSetConfigKey.matchPairs]: {
|
|
@@ -3441,12 +3568,29 @@ var CARDSETS = {
|
|
|
3441
3568
|
// ALIGN-EXAMPLE-CASCADE §3.10: `questions` is NOT in BPG's
|
|
3442
3569
|
// `pushExampleDownTree` dispatch — bit-header `[@example]`
|
|
3443
3570
|
// does not propagate `example`/`isExample` onto question
|
|
3444
|
-
// entries. Only entry-local `[@example]` fires
|
|
3445
|
-
//
|
|
3446
|
-
//
|
|
3571
|
+
// entries. Only entry-local `[@example]` fires.
|
|
3572
|
+
//
|
|
3573
|
+
// BPG's `BaseBuilder.toExample` for interview questions
|
|
3574
|
+
// (Builder.ts:2575,2588) uses `data.__sampleSolutionAst`
|
|
3575
|
+
// as `defaultExample` — bare `[@example]` (which sets
|
|
3576
|
+
// `__isDefaultExample=true, example=undefined`) emits the
|
|
3577
|
+
// parsed sample-solution AST in the `example` slot. The
|
|
3578
|
+
// `@keyonly` rule mirrors that runtime behaviour via
|
|
3579
|
+
// `$parent.sampleSolution` — the chain-walker's post-walk
|
|
3580
|
+
// retry resolves this once the sibling `[@sampleSolution]`
|
|
3581
|
+
// chain has merged into the shared scope (interview's
|
|
3582
|
+
// `[@example]` typically precedes `[@sampleSolution]` in
|
|
3583
|
+
// source). Format coercion turns the resolved string
|
|
3584
|
+
// value into a PM tree.
|
|
3447
3585
|
key: ConfigKey.property_example,
|
|
3448
3586
|
exportJsonKey: [
|
|
3449
|
-
{
|
|
3587
|
+
{
|
|
3588
|
+
"@keyonly": {
|
|
3589
|
+
isExample: true,
|
|
3590
|
+
example: "$parent.sampleSolution",
|
|
3591
|
+
"@bit": { isExample: true }
|
|
3592
|
+
}
|
|
3593
|
+
},
|
|
3450
3594
|
{ isExample: true, example: "$", "@bit": { isExample: true } }
|
|
3451
3595
|
],
|
|
3452
3596
|
description: "Example marker for the question (entry-local only; no bit-header cascade).",
|
|
@@ -5269,7 +5413,11 @@ var GROUPS = {
|
|
|
5269
5413
|
{
|
|
5270
5414
|
key: ConfigKey.property_mark,
|
|
5271
5415
|
jsonKey: "marks.mark",
|
|
5272
|
-
|
|
5416
|
+
// `emphasis: 'underline'` is the per-entry default for mark
|
|
5417
|
+
// configs — mirrors the hardcoded default in BPG
|
|
5418
|
+
// `MarkConfigChainContentProcessor.ts:55-58`. Chained
|
|
5419
|
+
// `[@emphasis:…]` overrides via deep-merge into `marks[-1]`.
|
|
5420
|
+
exportJsonKey: { marks: [{ mark: "$", emphasis: "underline" }] },
|
|
5273
5421
|
description: "The mark configuration",
|
|
5274
5422
|
format: TagFormat.plainText,
|
|
5275
5423
|
maxCount: Count.infinity,
|
|
@@ -5311,13 +5459,22 @@ var GROUPS = {
|
|
|
5311
5459
|
{
|
|
5312
5460
|
key: ConfigKey.property_example,
|
|
5313
5461
|
jsonKey: "example",
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5462
|
+
// Per-mark `@example` is a boolean toggle. BPG's runtime
|
|
5463
|
+
// `ExampleTagContentProcessor.handleDefaultOnlyExample`
|
|
5464
|
+
// (lines 147-161) normalises ANY `[@example]` or
|
|
5465
|
+
// `[@example:V]` on a mark body-bit to
|
|
5466
|
+
// `__isDefaultExample=true, example=undefined`; the
|
|
5467
|
+
// downstream `toExample(_, _, defaultExample=true)` in
|
|
5468
|
+
// `BaseBuilder.ts:80-87` then emits `example: true`
|
|
5469
|
+
// regardless of source. Declare a single unconditional
|
|
5470
|
+
// boolean-shape rule so the exported schema matches that
|
|
5471
|
+
// runtime semantic instead of the misleading `example: $`
|
|
5472
|
+
// shape (which would only fire if `handleDefaultOnlyExample`
|
|
5473
|
+
// were removed). `@bit: {isExample: true}` cascades the
|
|
5474
|
+
// marker — but NOT the `example` value — to bit root.
|
|
5475
|
+
exportJsonKey: { isExample: true, example: true, "@bit": { isExample: true } },
|
|
5319
5476
|
description: "An example for the marked content",
|
|
5320
|
-
format: TagFormat.
|
|
5477
|
+
format: TagFormat.boolean,
|
|
5321
5478
|
nullable: true
|
|
5322
5479
|
}
|
|
5323
5480
|
]
|
|
@@ -8093,6 +8250,12 @@ var BITS = {
|
|
|
8093
8250
|
description: "The progress of the chapter, used for tracking reading progress",
|
|
8094
8251
|
format: TagFormat.boolean,
|
|
8095
8252
|
defaultValue: "true"
|
|
8253
|
+
},
|
|
8254
|
+
{
|
|
8255
|
+
key: ConfigKey.property_isCollapsible,
|
|
8256
|
+
description: "If true, the chapter is collapsible",
|
|
8257
|
+
format: TagFormat.boolean,
|
|
8258
|
+
defaultValue: "false"
|
|
8096
8259
|
}
|
|
8097
8260
|
]
|
|
8098
8261
|
},
|
|
@@ -8867,7 +9030,12 @@ var BITS = {
|
|
|
8867
9030
|
maxCount: Count.infinity
|
|
8868
9031
|
},
|
|
8869
9032
|
{
|
|
8870
|
-
// Override inherited @example from group_standardTags:
|
|
9033
|
+
// Override inherited @example from group_standardTags: emits both
|
|
9034
|
+
// `isExample` (bool) AND `example` (paragraph array). Declared as
|
|
9035
|
+
// bitmarkText because BPG `JsonGenerator.toExample` renders the
|
|
9036
|
+
// root-example value through the bit's textFormat (not this tag's
|
|
9037
|
+
// declared format) — `TagFormat.plainText` here would be ignored
|
|
9038
|
+
// at runtime and is misleading.
|
|
8871
9039
|
key: ConfigKey.property_example,
|
|
8872
9040
|
exportJsonKey: [
|
|
8873
9041
|
{ "@keyonly": { isExample: true, example: "true" } },
|
|
@@ -8875,7 +9043,7 @@ var BITS = {
|
|
|
8875
9043
|
{ isExample: true, example: "$" }
|
|
8876
9044
|
],
|
|
8877
9045
|
description: "The example text for the essay bit",
|
|
8878
|
-
format: TagFormat.
|
|
9046
|
+
format: TagFormat.bitmarkText,
|
|
8879
9047
|
nullable: true
|
|
8880
9048
|
}
|
|
8881
9049
|
],
|
|
@@ -9921,6 +10089,11 @@ var BITS = {
|
|
|
9921
10089
|
baseBitType: BitType._standard,
|
|
9922
10090
|
description: "Extractor rule bit, used to define extraction rules with reference images and instructions",
|
|
9923
10091
|
tags: [
|
|
10092
|
+
{
|
|
10093
|
+
exportJsonKey: { title: "$" },
|
|
10094
|
+
key: ConfigKey.tag_title,
|
|
10095
|
+
description: "The name of the extraction rule"
|
|
10096
|
+
},
|
|
9924
10097
|
{
|
|
9925
10098
|
key: ConfigKey.group_resourceBitTags,
|
|
9926
10099
|
description: "Resource bit tags for extraction rule images"
|
|
@@ -10237,11 +10410,36 @@ var BITS = {
|
|
|
10237
10410
|
],
|
|
10238
10411
|
cardSet: CardSetConfigKey.definitionList
|
|
10239
10412
|
},
|
|
10413
|
+
[BitType.definitionListCollapsible]: {
|
|
10414
|
+
since: "5.25.0",
|
|
10415
|
+
baseBitType: BitType.definitionList,
|
|
10416
|
+
description: "Collapsible definition list bit, used to create collapsible lists of definitions in articles or books"
|
|
10417
|
+
},
|
|
10418
|
+
[BitType.standardDefinitionListNormative]: {
|
|
10419
|
+
since: "5.24.0",
|
|
10420
|
+
baseBitType: BitType.definitionList,
|
|
10421
|
+
description: "Standard normative definition list bit, used to create normative standard definition lists in articles or books"
|
|
10422
|
+
},
|
|
10423
|
+
[BitType.standardDefinitionListNonNormative]: {
|
|
10424
|
+
since: "5.24.0",
|
|
10425
|
+
baseBitType: BitType.definitionList,
|
|
10426
|
+
description: "Standard non-normative definition list bit, used to create non-normative standard definition lists in articles or books"
|
|
10427
|
+
},
|
|
10428
|
+
[BitType.smartStandardDefinitionListNormative]: {
|
|
10429
|
+
since: "5.24.0",
|
|
10430
|
+
baseBitType: BitType.standardDefinitionListNormative,
|
|
10431
|
+
description: "Smart standard normative definition list bit, used to create normative smart standard definition lists in articles or books"
|
|
10432
|
+
},
|
|
10433
|
+
[BitType.smartStandardDefinitionListNonNormative]: {
|
|
10434
|
+
since: "5.24.0",
|
|
10435
|
+
baseBitType: BitType.standardDefinitionListNonNormative,
|
|
10436
|
+
description: "Smart standard non-normative definition list bit, used to create non-normative smart standard definition lists in articles or books"
|
|
10437
|
+
},
|
|
10240
10438
|
[BitType.metaSearchDefaultTerms]: {
|
|
10241
10439
|
since: "3.12.0",
|
|
10242
10440
|
baseBitType: BitType._standard,
|
|
10243
10441
|
description: "Meta search default terms bit, used to define default search terms in articles",
|
|
10244
|
-
cardSet: CardSetConfigKey.
|
|
10442
|
+
cardSet: CardSetConfigKey.definitionListPlain
|
|
10245
10443
|
},
|
|
10246
10444
|
[BitType.metaSearchDefaultTopics]: {
|
|
10247
10445
|
since: "3.12.0",
|
|
@@ -10285,7 +10483,11 @@ var BITS = {
|
|
|
10285
10483
|
[BitType.qAndACard]: {
|
|
10286
10484
|
since: "3.25.0",
|
|
10287
10485
|
baseBitType: BitType.flashcard1,
|
|
10288
|
-
description: "Q&A card bit, used to create question and answer cards in articles or books"
|
|
10486
|
+
description: "Q&A card bit, used to create question and answer cards in articles or books",
|
|
10487
|
+
// PLAN-085: q-and-a-card permits multiple cards (some fixtures carry
|
|
10488
|
+
// two). Override the inherited `flashcard1` (max=1) cardset back to
|
|
10489
|
+
// the unbounded `flashcard` cardset.
|
|
10490
|
+
cardSet: CardSetConfigKey.flashcard
|
|
10289
10491
|
},
|
|
10290
10492
|
[BitType.focusImage]: {
|
|
10291
10493
|
since: "1.3.0",
|
|
@@ -13371,7 +13573,7 @@ var instance2 = new Config();
|
|
|
13371
13573
|
// src/generated/package_info.ts
|
|
13372
13574
|
var PACKAGE_INFO = {
|
|
13373
13575
|
"name": "@gmb/bitmark-parser-generator",
|
|
13374
|
-
"version": "5.
|
|
13576
|
+
"version": "5.26.0",
|
|
13375
13577
|
"license": "ISC"};
|
|
13376
13578
|
var Environment = {
|
|
13377
13579
|
unknown: "",
|
|
@@ -13985,6 +14187,8 @@ var NodeType = {
|
|
|
13985
14187
|
internalPrintPdf: "internalPrintPdf",
|
|
13986
14188
|
internalPrintPdfValue: "internalPrintPdfValue",
|
|
13987
14189
|
isCaseSensitive: "isCaseSensitive",
|
|
14190
|
+
isCollapsible: "isCollapsible",
|
|
14191
|
+
isCollapsibleValue: "isCollapsibleValue",
|
|
13988
14192
|
isCommented: "isCommented",
|
|
13989
14193
|
isCorrect: "isCorrect",
|
|
13990
14194
|
isEditable: "isEditable",
|
|
@@ -28039,6 +28243,12 @@ var Builder = class extends BaseBuilder {
|
|
|
28039
28243
|
level: instance6.asNumber(data.level),
|
|
28040
28244
|
toc: this.toAstProperty(bitType, ConfigKey.property_toc, data.toc, options),
|
|
28041
28245
|
progress: this.toAstProperty(bitType, ConfigKey.property_progress, data.progress, options),
|
|
28246
|
+
isCollapsible: this.toAstProperty(
|
|
28247
|
+
bitType,
|
|
28248
|
+
ConfigKey.property_isCollapsible,
|
|
28249
|
+
data.isCollapsible,
|
|
28250
|
+
options
|
|
28251
|
+
),
|
|
28042
28252
|
anchor: data.anchor,
|
|
28043
28253
|
reference: data.reference,
|
|
28044
28254
|
referenceEnd: data.referenceEnd,
|
|
@@ -33560,6 +33770,7 @@ var JsonGenerator = class extends AstWalkerGenerator {
|
|
|
33560
33770
|
if (instance2.isOfBitType(bitType, BitType.chapter)) {
|
|
33561
33771
|
if (bitJson.toc == null) bitJson.toc = true;
|
|
33562
33772
|
if (bitJson.progress == null) bitJson.progress = true;
|
|
33773
|
+
if (bitJson.isCollapsible == null) bitJson.isCollapsible = false;
|
|
33563
33774
|
if (bitJson.level == null) bitJson.level = 1;
|
|
33564
33775
|
if (bitJson.body == null) bitJson.body = this.bodyDefault;
|
|
33565
33776
|
}
|
|
@@ -35707,6 +35918,7 @@ function buildCards(context, bitType, textFormat, parsedCardSet, statementV1, st
|
|
|
35707
35918
|
case CardSetConfigKey.flashcard:
|
|
35708
35919
|
case CardSetConfigKey.flashcard1:
|
|
35709
35920
|
case CardSetConfigKey.definitionList:
|
|
35921
|
+
case CardSetConfigKey.definitionListPlain:
|
|
35710
35922
|
result = parseFlashcardOrDefinitionList(context, bitType, processedCardSet);
|
|
35711
35923
|
break;
|
|
35712
35924
|
case CardSetConfigKey.elements:
|
|
@@ -41780,8 +41992,8 @@ var FileWriter = class extends StreamWriter {
|
|
|
41780
41992
|
async open() {
|
|
41781
41993
|
return new Promise((resolve, reject) => {
|
|
41782
41994
|
const flags = this._append ? "a" : "w";
|
|
41783
|
-
|
|
41784
|
-
const stream =
|
|
41995
|
+
fs4.ensureDirSync(path3.dirname(this._path.toString()));
|
|
41996
|
+
const stream = fs4.createWriteStream(this._path, {
|
|
41785
41997
|
flags,
|
|
41786
41998
|
encoding: "utf8"
|
|
41787
41999
|
});
|
|
@@ -41855,8 +42067,8 @@ var SyncFileWriter = class {
|
|
|
41855
42067
|
}
|
|
41856
42068
|
openSync() {
|
|
41857
42069
|
const flag = this._append ? "a" : "w";
|
|
41858
|
-
|
|
41859
|
-
|
|
42070
|
+
fs4.ensureDirSync(path3.dirname(this._path.toString()));
|
|
42071
|
+
fs4.writeFileSync(this._path, "", {
|
|
41860
42072
|
flag,
|
|
41861
42073
|
encoding: this._encoding
|
|
41862
42074
|
});
|
|
@@ -41873,7 +42085,7 @@ var SyncFileWriter = class {
|
|
|
41873
42085
|
} else {
|
|
41874
42086
|
line = this.endOfLineString;
|
|
41875
42087
|
}
|
|
41876
|
-
|
|
42088
|
+
fs4.appendFileSync(this._path, line, {
|
|
41877
42089
|
encoding: this._encoding
|
|
41878
42090
|
});
|
|
41879
42091
|
this.lastWrite = line;
|
|
@@ -41891,7 +42103,7 @@ var SyncFileWriter = class {
|
|
|
41891
42103
|
}
|
|
41892
42104
|
str += this.endOfLineString;
|
|
41893
42105
|
}
|
|
41894
|
-
|
|
42106
|
+
fs4.appendFileSync(this._path, str, {
|
|
41895
42107
|
encoding: this._encoding
|
|
41896
42108
|
});
|
|
41897
42109
|
this.lastWrite = str;
|
|
@@ -41901,7 +42113,7 @@ var SyncFileWriter = class {
|
|
|
41901
42113
|
if (!this._open) return this;
|
|
41902
42114
|
if (value == null) return this;
|
|
41903
42115
|
if (value) this.lastWrite = value;
|
|
41904
|
-
|
|
42116
|
+
fs4.appendFileSync(this._path, value, {
|
|
41905
42117
|
encoding: this._encoding
|
|
41906
42118
|
});
|
|
41907
42119
|
return this;
|
|
@@ -41950,6 +42162,233 @@ var BitmarkFileGenerator = class {
|
|
|
41950
42162
|
this.generator.generateSync(_ast);
|
|
41951
42163
|
}
|
|
41952
42164
|
};
|
|
42165
|
+
|
|
42166
|
+
// src/generator/html/HtmlTableGenerator.ts
|
|
42167
|
+
var MARK_TO_TAG = {
|
|
42168
|
+
bold: "b",
|
|
42169
|
+
italic: "i",
|
|
42170
|
+
superscript: "sup",
|
|
42171
|
+
subscript: "sub",
|
|
42172
|
+
strike: "s",
|
|
42173
|
+
del: "del",
|
|
42174
|
+
ins: "ins",
|
|
42175
|
+
underline: "u",
|
|
42176
|
+
highlight: "mark",
|
|
42177
|
+
code: "code"
|
|
42178
|
+
};
|
|
42179
|
+
var HtmlTableGenerator = class {
|
|
42180
|
+
indentUnit = " ";
|
|
42181
|
+
/**
|
|
42182
|
+
* Generate HTML table fragments from a string or JSON value.
|
|
42183
|
+
* @returns the concatenated `<table>` fragments, blank-line separated (empty string if none).
|
|
42184
|
+
*/
|
|
42185
|
+
generate(input) {
|
|
42186
|
+
let data = input;
|
|
42187
|
+
if (typeof data === "string") {
|
|
42188
|
+
try {
|
|
42189
|
+
data = JSON.parse(data);
|
|
42190
|
+
} catch {
|
|
42191
|
+
return "";
|
|
42192
|
+
}
|
|
42193
|
+
}
|
|
42194
|
+
const bits = this.collectBits(data);
|
|
42195
|
+
const fragments = [];
|
|
42196
|
+
for (const bit of bits) {
|
|
42197
|
+
const html = this.renderTableBit(bit);
|
|
42198
|
+
if (html) fragments.push(html);
|
|
42199
|
+
}
|
|
42200
|
+
return fragments.join("\n\n");
|
|
42201
|
+
}
|
|
42202
|
+
// --- bit collection -------------------------------------------------------
|
|
42203
|
+
collectBits(data) {
|
|
42204
|
+
const out = [];
|
|
42205
|
+
const visit = (value) => {
|
|
42206
|
+
if (value == null || typeof value !== "object") return;
|
|
42207
|
+
if (Array.isArray(value)) {
|
|
42208
|
+
value.forEach(visit);
|
|
42209
|
+
return;
|
|
42210
|
+
}
|
|
42211
|
+
const obj = value;
|
|
42212
|
+
if ("bit" in obj && obj.bit && typeof obj.bit === "object") {
|
|
42213
|
+
out.push(obj.bit);
|
|
42214
|
+
} else if ("type" in obj) {
|
|
42215
|
+
out.push(obj);
|
|
42216
|
+
}
|
|
42217
|
+
};
|
|
42218
|
+
visit(data);
|
|
42219
|
+
return out;
|
|
42220
|
+
}
|
|
42221
|
+
// --- table rendering ------------------------------------------------------
|
|
42222
|
+
renderTableBit(bit) {
|
|
42223
|
+
const table = bit.table;
|
|
42224
|
+
if (!table) return "";
|
|
42225
|
+
if (bit.type !== "table" && bit.type !== "table-extended") return "";
|
|
42226
|
+
const extended = this.toExtended(table);
|
|
42227
|
+
const lines = [];
|
|
42228
|
+
lines.push("<table>");
|
|
42229
|
+
if (bit.caption != null) {
|
|
42230
|
+
const caption = this.cellContentToHtml(this.asTextAst(bit.caption));
|
|
42231
|
+
if (caption) lines.push(`${this.indentUnit}<caption>${caption}</caption>`);
|
|
42232
|
+
}
|
|
42233
|
+
this.renderSection(lines, "thead", extended.header, "header");
|
|
42234
|
+
this.renderSection(lines, "tbody", extended.body, "body");
|
|
42235
|
+
this.renderSection(lines, "tfoot", extended.footer, "footer");
|
|
42236
|
+
lines.push("</table>");
|
|
42237
|
+
return lines.join("\n");
|
|
42238
|
+
}
|
|
42239
|
+
toExtended(table) {
|
|
42240
|
+
const t = table;
|
|
42241
|
+
if (t.header || t.body || t.footer) return table;
|
|
42242
|
+
return convertBasicToExtendedTableFormat(table);
|
|
42243
|
+
}
|
|
42244
|
+
renderSection(lines, tag, section, key) {
|
|
42245
|
+
if (!section || !section.rows || section.rows.length === 0) return;
|
|
42246
|
+
lines.push(`${this.indentUnit}<${tag}>`);
|
|
42247
|
+
for (const row of section.rows) {
|
|
42248
|
+
lines.push(`${this.indentUnit.repeat(2)}<tr>`);
|
|
42249
|
+
for (const cell of row.cells ?? []) {
|
|
42250
|
+
lines.push(`${this.indentUnit.repeat(3)}${this.renderCell(cell, key)}`);
|
|
42251
|
+
}
|
|
42252
|
+
lines.push(`${this.indentUnit.repeat(2)}</tr>`);
|
|
42253
|
+
}
|
|
42254
|
+
lines.push(`${this.indentUnit}</${tag}>`);
|
|
42255
|
+
}
|
|
42256
|
+
renderCell(cell, _key) {
|
|
42257
|
+
const tag = cell.title === true ? "th" : "td";
|
|
42258
|
+
const attrs = [];
|
|
42259
|
+
if (cell.rowspan && cell.rowspan > 1) attrs.push(`rowspan="${cell.rowspan}"`);
|
|
42260
|
+
if (cell.colspan && cell.colspan > 1) attrs.push(`colspan="${cell.colspan}"`);
|
|
42261
|
+
if (cell.scope) attrs.push(`scope="${cell.scope}"`);
|
|
42262
|
+
if (cell.colwidth && cell.colwidth > 0) attrs.push(`width="${cell.colwidth}"`);
|
|
42263
|
+
const open = attrs.length > 0 ? `<${tag} ${attrs.join(" ")}>` : `<${tag}>`;
|
|
42264
|
+
return `${open}${this.cellContentToHtml(this.asTextAst(cell.content))}</${tag}>`;
|
|
42265
|
+
}
|
|
42266
|
+
// --- cell content (TextAst -> HTML) ---------------------------------------
|
|
42267
|
+
asTextAst(content) {
|
|
42268
|
+
if (content == null) return [];
|
|
42269
|
+
if (typeof content === "string") return [{ type: "text", text: content }];
|
|
42270
|
+
return content;
|
|
42271
|
+
}
|
|
42272
|
+
cellContentToHtml(blocks) {
|
|
42273
|
+
if (blocks.length === 0) return "";
|
|
42274
|
+
if (blocks.length === 1 && blocks[0].type === "paragraph") {
|
|
42275
|
+
return this.inlineToHtml(blocks[0].content ?? []);
|
|
42276
|
+
}
|
|
42277
|
+
return blocks.map((b) => this.blockToHtml(b)).join("");
|
|
42278
|
+
}
|
|
42279
|
+
blockToHtml(node) {
|
|
42280
|
+
switch (node.type) {
|
|
42281
|
+
case "paragraph":
|
|
42282
|
+
return `<p>${this.inlineToHtml(node.content ?? [])}</p>`;
|
|
42283
|
+
case "bulletList":
|
|
42284
|
+
case "noBulletList":
|
|
42285
|
+
case "orderedList":
|
|
42286
|
+
case "orderedListRoman":
|
|
42287
|
+
case "orderedListRomanLower":
|
|
42288
|
+
case "letteredList":
|
|
42289
|
+
case "letteredListLower":
|
|
42290
|
+
case "taskList":
|
|
42291
|
+
return this.listToHtml(node);
|
|
42292
|
+
case "image":
|
|
42293
|
+
case "imageInline":
|
|
42294
|
+
return this.imageToHtml(node);
|
|
42295
|
+
default:
|
|
42296
|
+
return this.inlineToHtml([node]);
|
|
42297
|
+
}
|
|
42298
|
+
}
|
|
42299
|
+
inlineToHtml(nodes) {
|
|
42300
|
+
return nodes.map((n) => this.inlineNodeToHtml(n)).join("");
|
|
42301
|
+
}
|
|
42302
|
+
inlineNodeToHtml(node) {
|
|
42303
|
+
if (node.type === "hardBreak") return "<br>";
|
|
42304
|
+
if (node.type === "image" || node.type === "imageInline") return this.imageToHtml(node);
|
|
42305
|
+
if (node.type === "text") {
|
|
42306
|
+
return this.wrapMarks(this.escapeText(node.text ?? ""), node.marks);
|
|
42307
|
+
}
|
|
42308
|
+
if (node.content) return this.inlineToHtml(node.content);
|
|
42309
|
+
return this.escapeText(node.text ?? "");
|
|
42310
|
+
}
|
|
42311
|
+
wrapMarks(text, marks) {
|
|
42312
|
+
if (!marks || marks.length === 0) return text;
|
|
42313
|
+
let open = "";
|
|
42314
|
+
let close = "";
|
|
42315
|
+
for (const mark of marks) {
|
|
42316
|
+
if (mark.type === "link") {
|
|
42317
|
+
const href = mark.attrs?.href ?? "";
|
|
42318
|
+
open += `<a href="${this.escapeAttr(href)}">`;
|
|
42319
|
+
close = `</a>${close}`;
|
|
42320
|
+
} else {
|
|
42321
|
+
const tag = MARK_TO_TAG[mark.type];
|
|
42322
|
+
if (tag) {
|
|
42323
|
+
open += `<${tag}>`;
|
|
42324
|
+
close = `</${tag}>${close}`;
|
|
42325
|
+
}
|
|
42326
|
+
}
|
|
42327
|
+
}
|
|
42328
|
+
return `${open}${text}${close}`;
|
|
42329
|
+
}
|
|
42330
|
+
// --- lists ----------------------------------------------------------------
|
|
42331
|
+
listToHtml(node) {
|
|
42332
|
+
const { tag, attrs } = this.listTag(node);
|
|
42333
|
+
const items = (node.content ?? []).map((item) => this.listItemToHtml(item, node.type === "taskList")).join("");
|
|
42334
|
+
return `<${tag}${attrs}>${items}</${tag}>`;
|
|
42335
|
+
}
|
|
42336
|
+
listTag(node) {
|
|
42337
|
+
const start = node.attrs?.start;
|
|
42338
|
+
const startAttr = typeof start === "number" && start !== 1 ? ` start="${start}"` : "";
|
|
42339
|
+
switch (node.type) {
|
|
42340
|
+
case "orderedList":
|
|
42341
|
+
return { tag: "ol", attrs: startAttr };
|
|
42342
|
+
case "orderedListRoman":
|
|
42343
|
+
return { tag: "ol", attrs: ` type="I"${startAttr}` };
|
|
42344
|
+
case "orderedListRomanLower":
|
|
42345
|
+
return { tag: "ol", attrs: ` type="i"${startAttr}` };
|
|
42346
|
+
case "letteredList":
|
|
42347
|
+
return { tag: "ol", attrs: ` type="A"${startAttr}` };
|
|
42348
|
+
case "letteredListLower":
|
|
42349
|
+
return { tag: "ol", attrs: ` type="a"${startAttr}` };
|
|
42350
|
+
case "noBulletList":
|
|
42351
|
+
return { tag: "ul", attrs: ' style="list-style:none"' };
|
|
42352
|
+
case "taskList":
|
|
42353
|
+
case "bulletList":
|
|
42354
|
+
default:
|
|
42355
|
+
return { tag: "ul", attrs: "" };
|
|
42356
|
+
}
|
|
42357
|
+
}
|
|
42358
|
+
listItemToHtml(item, task) {
|
|
42359
|
+
const inner = (item.content ?? []).map((b) => {
|
|
42360
|
+
if (b.type === "paragraph") return this.inlineToHtml(b.content ?? []);
|
|
42361
|
+
return this.blockToHtml(b);
|
|
42362
|
+
}).join("");
|
|
42363
|
+
if (task) {
|
|
42364
|
+
const checked = item.attrs?.checked ? " checked" : "";
|
|
42365
|
+
return `<li><input type="checkbox"${checked}>${inner}</li>`;
|
|
42366
|
+
}
|
|
42367
|
+
return `<li>${inner}</li>`;
|
|
42368
|
+
}
|
|
42369
|
+
// --- images ---------------------------------------------------------------
|
|
42370
|
+
imageToHtml(node) {
|
|
42371
|
+
const attrs = node.attrs ?? {};
|
|
42372
|
+
const parts = [];
|
|
42373
|
+
const src = attrs.src;
|
|
42374
|
+
parts.push(`src="${this.escapeAttr(typeof src === "string" ? src : "")}"`);
|
|
42375
|
+
if (typeof attrs.alt === "string") parts.push(`alt="${this.escapeAttr(attrs.alt)}"`);
|
|
42376
|
+
if (typeof attrs.title === "string") parts.push(`title="${this.escapeAttr(attrs.title)}"`);
|
|
42377
|
+
if (attrs.width != null) parts.push(`width="${attrs.width}"`);
|
|
42378
|
+
if (attrs.height != null) parts.push(`height="${attrs.height}"`);
|
|
42379
|
+
if (typeof attrs.class === "string" && attrs.class) {
|
|
42380
|
+
parts.push(`class="${this.escapeAttr(attrs.class)}"`);
|
|
42381
|
+
}
|
|
42382
|
+
return `<img ${parts.join(" ")}>`;
|
|
42383
|
+
}
|
|
42384
|
+
// --- escaping -------------------------------------------------------------
|
|
42385
|
+
escapeText(text) {
|
|
42386
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
42387
|
+
}
|
|
42388
|
+
escapeAttr(text) {
|
|
42389
|
+
return this.escapeText(text).replace(/"/g, """);
|
|
42390
|
+
}
|
|
42391
|
+
};
|
|
41953
42392
|
var JsonFileGenerator = class {
|
|
41954
42393
|
generator;
|
|
41955
42394
|
async;
|
|
@@ -42286,20 +42725,20 @@ var ConfigBuilder = class {
|
|
|
42286
42725
|
const outputFolderBits = path3.join(outputFolder, "bits");
|
|
42287
42726
|
const outputFolderGroups = path3.join(outputFolder, "partials");
|
|
42288
42727
|
const outputFolderCards = path3.join(outputFolder, "cards");
|
|
42289
|
-
|
|
42290
|
-
|
|
42291
|
-
|
|
42292
|
-
const bitsFiles =
|
|
42728
|
+
fs4.ensureDirSync(outputFolderBits);
|
|
42729
|
+
fs4.ensureDirSync(outputFolderGroups);
|
|
42730
|
+
fs4.ensureDirSync(outputFolderCards);
|
|
42731
|
+
const bitsFiles = fs4.readdirSync(outputFolderBits).filter((f) => f.endsWith(".jsonc"));
|
|
42293
42732
|
for (const file of bitsFiles) {
|
|
42294
|
-
|
|
42733
|
+
fs4.removeSync(path3.join(outputFolderBits, file));
|
|
42295
42734
|
}
|
|
42296
|
-
const partialsFiles =
|
|
42735
|
+
const partialsFiles = fs4.readdirSync(outputFolderGroups).filter((f) => f.endsWith(".jsonc"));
|
|
42297
42736
|
for (const file of partialsFiles) {
|
|
42298
|
-
|
|
42737
|
+
fs4.removeSync(path3.join(outputFolderGroups, file));
|
|
42299
42738
|
}
|
|
42300
|
-
const cardsFiles =
|
|
42739
|
+
const cardsFiles = fs4.readdirSync(outputFolderCards).filter((f) => f.endsWith(".jsonc"));
|
|
42301
42740
|
for (const file of cardsFiles) {
|
|
42302
|
-
|
|
42741
|
+
fs4.removeSync(path3.join(outputFolderCards, file));
|
|
42303
42742
|
}
|
|
42304
42743
|
const fileWrites = [];
|
|
42305
42744
|
const tagEntriesTypeOrder = [
|
|
@@ -42644,7 +43083,7 @@ var ConfigBuilder = class {
|
|
|
42644
43083
|
};
|
|
42645
43084
|
const output = path3.join(outputFolderBits, `${b.bitType}.jsonc`);
|
|
42646
43085
|
const str = JSON.stringify(bitJson, null, 2);
|
|
42647
|
-
fileWrites.push(
|
|
43086
|
+
fileWrites.push(fs4.writeFile(output, str));
|
|
42648
43087
|
}
|
|
42649
43088
|
const writeGroupConfigs = (groupConfigs2) => {
|
|
42650
43089
|
for (const g of groupConfigs2) {
|
|
@@ -42703,7 +43142,7 @@ var ConfigBuilder = class {
|
|
|
42703
43142
|
};
|
|
42704
43143
|
const output = path3.join(outputFolderGroups, `${groupKey}.jsonc`);
|
|
42705
43144
|
const str = JSON.stringify(bitJson, null, 2);
|
|
42706
|
-
|
|
43145
|
+
fs4.writeFileSync(output, str);
|
|
42707
43146
|
}
|
|
42708
43147
|
};
|
|
42709
43148
|
writeGroupConfigs(groupConfigs);
|
|
@@ -42713,7 +43152,7 @@ var ConfigBuilder = class {
|
|
|
42713
43152
|
if (!cardJson) continue;
|
|
42714
43153
|
const output = path3.join(outputFolderCards, `${cardJson.name}.jsonc`);
|
|
42715
43154
|
const str = JSON.stringify(cardJson, null, 2);
|
|
42716
|
-
fileWrites.push(
|
|
43155
|
+
fileWrites.push(fs4.writeFile(output, str));
|
|
42717
43156
|
}
|
|
42718
43157
|
};
|
|
42719
43158
|
const writeBitsAsGroupConfigs = (bitsAsGroupConfigs) => {
|
|
@@ -42762,7 +43201,7 @@ var ConfigBuilder = class {
|
|
|
42762
43201
|
};
|
|
42763
43202
|
const output = path3.join(outputFolderGroups, `${groupKey}.jsonc`);
|
|
42764
43203
|
const str = JSON.stringify(bitJson, null, 2);
|
|
42765
|
-
|
|
43204
|
+
fs4.writeFileSync(output, str);
|
|
42766
43205
|
}
|
|
42767
43206
|
};
|
|
42768
43207
|
writeBitsAsGroupConfigs(bitGroupConfigs);
|
|
@@ -42801,15 +43240,15 @@ var ConfigBuilder = class {
|
|
|
42801
43240
|
const outputFolderGroups = path3.join(outputFolder, "partials");
|
|
42802
43241
|
const outputFolderCards = path3.join(outputFolder, "cards");
|
|
42803
43242
|
const availableGroups = /* @__PURE__ */ new Set();
|
|
42804
|
-
if (
|
|
42805
|
-
const groupFiles =
|
|
43243
|
+
if (fs4.existsSync(outputFolderGroups)) {
|
|
43244
|
+
const groupFiles = fs4.readdirSync(outputFolderGroups).filter((f) => f.endsWith(".jsonc"));
|
|
42806
43245
|
for (const file of groupFiles) {
|
|
42807
43246
|
const groupName = file.replace(".jsonc", "");
|
|
42808
43247
|
availableGroups.add(groupName);
|
|
42809
43248
|
}
|
|
42810
43249
|
}
|
|
42811
43250
|
const availableCards = /* @__PURE__ */ new Set();
|
|
42812
|
-
const cardFiles =
|
|
43251
|
+
const cardFiles = fs4.existsSync(outputFolderCards) ? fs4.readdirSync(outputFolderCards).filter((f) => f.endsWith(".jsonc")) : [];
|
|
42813
43252
|
for (const file of cardFiles) {
|
|
42814
43253
|
const cardName = file.replace(".jsonc", "");
|
|
42815
43254
|
availableCards.add(cardName);
|
|
@@ -42828,12 +43267,12 @@ var ConfigBuilder = class {
|
|
|
42828
43267
|
}
|
|
42829
43268
|
}
|
|
42830
43269
|
};
|
|
42831
|
-
if (
|
|
42832
|
-
const bitFiles =
|
|
43270
|
+
if (fs4.existsSync(outputFolderBits)) {
|
|
43271
|
+
const bitFiles = fs4.readdirSync(outputFolderBits).filter((f) => f.endsWith(".jsonc"));
|
|
42833
43272
|
for (const file of bitFiles) {
|
|
42834
43273
|
const filePath = path3.join(outputFolderBits, file);
|
|
42835
43274
|
try {
|
|
42836
|
-
const content =
|
|
43275
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
42837
43276
|
const config = JSON.parse(content);
|
|
42838
43277
|
if (config.tags && Array.isArray(config.tags)) {
|
|
42839
43278
|
checkTags(config.tags, `bits/${file}`, 15);
|
|
@@ -42864,12 +43303,12 @@ var ConfigBuilder = class {
|
|
|
42864
43303
|
}
|
|
42865
43304
|
}
|
|
42866
43305
|
}
|
|
42867
|
-
if (
|
|
42868
|
-
const groupFiles =
|
|
43306
|
+
if (fs4.existsSync(outputFolderGroups)) {
|
|
43307
|
+
const groupFiles = fs4.readdirSync(outputFolderGroups).filter((f) => f.endsWith(".jsonc"));
|
|
42869
43308
|
for (const file of groupFiles) {
|
|
42870
43309
|
const filePath = path3.join(outputFolderGroups, file);
|
|
42871
43310
|
try {
|
|
42872
|
-
const content =
|
|
43311
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
42873
43312
|
const config = JSON.parse(content);
|
|
42874
43313
|
if (config.tags && Array.isArray(config.tags)) {
|
|
42875
43314
|
checkTags(config.tags, `partials/${file}`, 15);
|
|
@@ -42883,7 +43322,7 @@ var ConfigBuilder = class {
|
|
|
42883
43322
|
for (const file of cardFiles) {
|
|
42884
43323
|
const filePath = path3.join(outputFolderCards, file);
|
|
42885
43324
|
try {
|
|
42886
|
-
const content =
|
|
43325
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
42887
43326
|
const config = JSON.parse(content);
|
|
42888
43327
|
const expectedKey = file.replace(".jsonc", "");
|
|
42889
43328
|
if (config.key && config.key !== expectedKey) {
|
|
@@ -42919,6 +43358,497 @@ var ConfigBuilder = class {
|
|
|
42919
43358
|
}
|
|
42920
43359
|
};
|
|
42921
43360
|
|
|
43361
|
+
// src/parser/html/HtmlDom.ts
|
|
43362
|
+
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
43363
|
+
"area",
|
|
43364
|
+
"base",
|
|
43365
|
+
"br",
|
|
43366
|
+
"col",
|
|
43367
|
+
"embed",
|
|
43368
|
+
"hr",
|
|
43369
|
+
"img",
|
|
43370
|
+
"input",
|
|
43371
|
+
"link",
|
|
43372
|
+
"meta",
|
|
43373
|
+
"param",
|
|
43374
|
+
"source",
|
|
43375
|
+
"track",
|
|
43376
|
+
"wbr"
|
|
43377
|
+
]);
|
|
43378
|
+
var IMPLIED_CLOSE = {
|
|
43379
|
+
li: /* @__PURE__ */ new Set(["li"]),
|
|
43380
|
+
td: /* @__PURE__ */ new Set(["td", "th"]),
|
|
43381
|
+
th: /* @__PURE__ */ new Set(["td", "th"]),
|
|
43382
|
+
tr: /* @__PURE__ */ new Set(["td", "th", "tr"]),
|
|
43383
|
+
thead: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
|
|
43384
|
+
tbody: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
|
|
43385
|
+
tfoot: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
|
|
43386
|
+
p: /* @__PURE__ */ new Set(["p"]),
|
|
43387
|
+
option: /* @__PURE__ */ new Set(["option"])
|
|
43388
|
+
};
|
|
43389
|
+
var TAG_RE = /<(\/)?([a-zA-Z][a-zA-Z0-9-]*)((?:\s+(?:"[^"]*"|'[^']*'|[^<>"'])*)?)(\/)?>/g;
|
|
43390
|
+
var ATTR_RE = /([a-zA-Z_:][a-zA-Z0-9:._-]*)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s"'>]+))?/g;
|
|
43391
|
+
function parseAttrs(raw) {
|
|
43392
|
+
const attrs = {};
|
|
43393
|
+
if (!raw) return attrs;
|
|
43394
|
+
ATTR_RE.lastIndex = 0;
|
|
43395
|
+
let m;
|
|
43396
|
+
while ((m = ATTR_RE.exec(raw)) !== null) {
|
|
43397
|
+
const name = m[1].toLowerCase();
|
|
43398
|
+
let value = m[2] ?? "";
|
|
43399
|
+
if (value.length >= 2 && (value[0] === '"' || value[0] === "'")) {
|
|
43400
|
+
value = value.slice(1, -1);
|
|
43401
|
+
}
|
|
43402
|
+
attrs[name] = value;
|
|
43403
|
+
}
|
|
43404
|
+
return attrs;
|
|
43405
|
+
}
|
|
43406
|
+
function stripNonContent(html) {
|
|
43407
|
+
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, "");
|
|
43408
|
+
}
|
|
43409
|
+
function tokenize(html) {
|
|
43410
|
+
const tokens = [];
|
|
43411
|
+
const clean = stripNonContent(html);
|
|
43412
|
+
TAG_RE.lastIndex = 0;
|
|
43413
|
+
let lastIndex = 0;
|
|
43414
|
+
let m;
|
|
43415
|
+
while ((m = TAG_RE.exec(clean)) !== null) {
|
|
43416
|
+
if (m.index > lastIndex) {
|
|
43417
|
+
tokens.push({ kind: "text", text: clean.slice(lastIndex, m.index) });
|
|
43418
|
+
}
|
|
43419
|
+
lastIndex = TAG_RE.lastIndex;
|
|
43420
|
+
const isClose = m[1] === "/";
|
|
43421
|
+
const name = m[2].toLowerCase();
|
|
43422
|
+
if (isClose) {
|
|
43423
|
+
tokens.push({ kind: "close", name });
|
|
43424
|
+
} else {
|
|
43425
|
+
tokens.push({
|
|
43426
|
+
kind: "open",
|
|
43427
|
+
name,
|
|
43428
|
+
attrs: parseAttrs(m[3]),
|
|
43429
|
+
selfClose: m[4] === "/"
|
|
43430
|
+
});
|
|
43431
|
+
}
|
|
43432
|
+
}
|
|
43433
|
+
if (lastIndex < clean.length) {
|
|
43434
|
+
tokens.push({ kind: "text", text: clean.slice(lastIndex) });
|
|
43435
|
+
}
|
|
43436
|
+
return tokens;
|
|
43437
|
+
}
|
|
43438
|
+
function parseHtml(html) {
|
|
43439
|
+
const root = { type: "element", name: "#root", attrs: {}, children: [] };
|
|
43440
|
+
const stack = [root];
|
|
43441
|
+
const top = () => stack[stack.length - 1];
|
|
43442
|
+
for (const token of tokenize(html)) {
|
|
43443
|
+
if (token.kind === "text") {
|
|
43444
|
+
if (token.text) top().children.push({ type: "text", value: token.text });
|
|
43445
|
+
continue;
|
|
43446
|
+
}
|
|
43447
|
+
if (token.kind === "open") {
|
|
43448
|
+
const name = token.name;
|
|
43449
|
+
const closes = IMPLIED_CLOSE[name];
|
|
43450
|
+
if (closes) {
|
|
43451
|
+
while (stack.length > 1 && closes.has(top().name)) stack.pop();
|
|
43452
|
+
}
|
|
43453
|
+
const el = {
|
|
43454
|
+
type: "element",
|
|
43455
|
+
name,
|
|
43456
|
+
attrs: token.attrs ?? {},
|
|
43457
|
+
children: []
|
|
43458
|
+
};
|
|
43459
|
+
top().children.push(el);
|
|
43460
|
+
if (!token.selfClose && !VOID_ELEMENTS.has(name)) {
|
|
43461
|
+
stack.push(el);
|
|
43462
|
+
}
|
|
43463
|
+
continue;
|
|
43464
|
+
}
|
|
43465
|
+
for (let i = stack.length - 1; i > 0; i--) {
|
|
43466
|
+
if (stack[i].name === token.name) {
|
|
43467
|
+
stack.length = i;
|
|
43468
|
+
break;
|
|
43469
|
+
}
|
|
43470
|
+
}
|
|
43471
|
+
}
|
|
43472
|
+
return root.children;
|
|
43473
|
+
}
|
|
43474
|
+
function childElements(el, names) {
|
|
43475
|
+
return el.children.filter((c) => c.type === "element" && names.has(c.name));
|
|
43476
|
+
}
|
|
43477
|
+
|
|
43478
|
+
// src/parser/html/HtmlTableParser.ts
|
|
43479
|
+
var MARK_TAGS = {
|
|
43480
|
+
b: "bold",
|
|
43481
|
+
strong: "bold",
|
|
43482
|
+
i: "italic",
|
|
43483
|
+
em: "italic",
|
|
43484
|
+
sup: "superscript",
|
|
43485
|
+
sub: "subscript",
|
|
43486
|
+
s: "strike",
|
|
43487
|
+
strike: "strike",
|
|
43488
|
+
del: "del",
|
|
43489
|
+
ins: "ins",
|
|
43490
|
+
u: "underline",
|
|
43491
|
+
mark: "highlight",
|
|
43492
|
+
code: "code"
|
|
43493
|
+
};
|
|
43494
|
+
var SECTION_TAGS = /* @__PURE__ */ new Set(["thead", "tbody", "tfoot"]);
|
|
43495
|
+
var ROW_TAGS = /* @__PURE__ */ new Set(["tr"]);
|
|
43496
|
+
var CELL_TAGS = /* @__PURE__ */ new Set(["td", "th"]);
|
|
43497
|
+
var LI_TAGS = /* @__PURE__ */ new Set(["li"]);
|
|
43498
|
+
var VALID_SCOPES = /* @__PURE__ */ new Set(["row", "col", "rowgroup", "colgroup"]);
|
|
43499
|
+
var NAMED_ENTITIES = {
|
|
43500
|
+
amp: "&",
|
|
43501
|
+
lt: "<",
|
|
43502
|
+
gt: ">",
|
|
43503
|
+
quot: '"',
|
|
43504
|
+
apos: "'",
|
|
43505
|
+
nbsp: "\xA0"
|
|
43506
|
+
};
|
|
43507
|
+
function decodeEntities(text) {
|
|
43508
|
+
return text.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z][a-zA-Z0-9]*);/g, (whole, body) => {
|
|
43509
|
+
if (body[0] === "#") {
|
|
43510
|
+
const code = body[1] === "x" || body[1] === "X" ? Number.parseInt(body.slice(2), 16) : Number.parseInt(body.slice(1), 10);
|
|
43511
|
+
if (Number.isFinite(code) && code >= 0 && code <= 1114111) {
|
|
43512
|
+
try {
|
|
43513
|
+
return String.fromCodePoint(code);
|
|
43514
|
+
} catch {
|
|
43515
|
+
return whole;
|
|
43516
|
+
}
|
|
43517
|
+
}
|
|
43518
|
+
return whole;
|
|
43519
|
+
}
|
|
43520
|
+
return NAMED_ENTITIES[body] ?? whole;
|
|
43521
|
+
});
|
|
43522
|
+
}
|
|
43523
|
+
function intAttr(value) {
|
|
43524
|
+
if (value == null) return void 0;
|
|
43525
|
+
const n = Number.parseInt(value, 10);
|
|
43526
|
+
return Number.isInteger(n) ? n : void 0;
|
|
43527
|
+
}
|
|
43528
|
+
function isElement(node) {
|
|
43529
|
+
return node.type === "element";
|
|
43530
|
+
}
|
|
43531
|
+
var HtmlTableParser = class {
|
|
43532
|
+
keepUnknownTags = false;
|
|
43533
|
+
/**
|
|
43534
|
+
* Parse an HTML string and return one table bit per top-level `<table>`.
|
|
43535
|
+
*/
|
|
43536
|
+
parse(html, options) {
|
|
43537
|
+
this.keepUnknownTags = options?.keepUnknownTags ?? false;
|
|
43538
|
+
const tableFormat = options?.tableFormat ?? "table-extended";
|
|
43539
|
+
const onWarning = options?.onWarning;
|
|
43540
|
+
const tables = this.collectTopLevelTables(parseHtml(html));
|
|
43541
|
+
const bits = [];
|
|
43542
|
+
for (const table of tables) {
|
|
43543
|
+
const bit = this.tableToBit(table, tableFormat, onWarning);
|
|
43544
|
+
if (bit) bits.push(bit);
|
|
43545
|
+
}
|
|
43546
|
+
return bits;
|
|
43547
|
+
}
|
|
43548
|
+
// --- table extraction -----------------------------------------------------
|
|
43549
|
+
/** Collect every `<table>` element, NOT descending into nested tables. */
|
|
43550
|
+
collectTopLevelTables(nodes) {
|
|
43551
|
+
const tables = [];
|
|
43552
|
+
const visit = (node) => {
|
|
43553
|
+
if (!isElement(node)) return;
|
|
43554
|
+
if (node.name === "table") {
|
|
43555
|
+
tables.push(node);
|
|
43556
|
+
return;
|
|
43557
|
+
}
|
|
43558
|
+
node.children.forEach(visit);
|
|
43559
|
+
};
|
|
43560
|
+
nodes.forEach(visit);
|
|
43561
|
+
return tables;
|
|
43562
|
+
}
|
|
43563
|
+
tableToBit(table, tableFormat, onWarning) {
|
|
43564
|
+
const header = [];
|
|
43565
|
+
const body = [];
|
|
43566
|
+
const footer = [];
|
|
43567
|
+
let caption;
|
|
43568
|
+
for (const child of table.children) {
|
|
43569
|
+
if (!isElement(child)) continue;
|
|
43570
|
+
if (child.name === "caption") {
|
|
43571
|
+
const capContent = this.inlineNodes(child.children, []);
|
|
43572
|
+
const trimmed = this.trimInline(capContent);
|
|
43573
|
+
if (trimmed.length > 0) caption = trimmed;
|
|
43574
|
+
} else if (SECTION_TAGS.has(child.name)) {
|
|
43575
|
+
const target = child.name === "thead" ? header : child.name === "tfoot" ? footer : body;
|
|
43576
|
+
for (const tr of childElements(child, ROW_TAGS)) {
|
|
43577
|
+
target.push(this.rowToCells(tr));
|
|
43578
|
+
}
|
|
43579
|
+
} else if (ROW_TAGS.has(child.name)) {
|
|
43580
|
+
body.push(this.rowToCells(child));
|
|
43581
|
+
}
|
|
43582
|
+
}
|
|
43583
|
+
if (header.length === 0 && body.length === 0 && footer.length === 0) {
|
|
43584
|
+
return void 0;
|
|
43585
|
+
}
|
|
43586
|
+
const tableExtended = {};
|
|
43587
|
+
if (header.length > 0) tableExtended.header = { rows: header };
|
|
43588
|
+
if (body.length > 0) tableExtended.body = { rows: body };
|
|
43589
|
+
if (footer.length > 0) tableExtended.footer = { rows: footer };
|
|
43590
|
+
let tableData = tableExtended;
|
|
43591
|
+
if (tableFormat === "table") {
|
|
43592
|
+
if (this.isLossyAsBasic(tableExtended)) {
|
|
43593
|
+
onWarning?.(
|
|
43594
|
+
"Converting an HTML table to [.table] loses rowspan/colspan/scope and multi-section structure; use --tableFormat table-extended to preserve them."
|
|
43595
|
+
);
|
|
43596
|
+
}
|
|
43597
|
+
tableData = convertExtendedToBasicTableFormat(tableExtended);
|
|
43598
|
+
}
|
|
43599
|
+
const bit = {
|
|
43600
|
+
type: tableFormat,
|
|
43601
|
+
format: "bitmark++",
|
|
43602
|
+
table: tableData
|
|
43603
|
+
};
|
|
43604
|
+
if (caption) bit.caption = caption;
|
|
43605
|
+
return bit;
|
|
43606
|
+
}
|
|
43607
|
+
rowToCells(tr) {
|
|
43608
|
+
const cells = [];
|
|
43609
|
+
for (const cell of childElements(tr, CELL_TAGS)) {
|
|
43610
|
+
cells.push(this.cellToJson(cell));
|
|
43611
|
+
}
|
|
43612
|
+
return { cells };
|
|
43613
|
+
}
|
|
43614
|
+
cellToJson(cell) {
|
|
43615
|
+
const json = {
|
|
43616
|
+
content: this.blockNodes(cell.children)
|
|
43617
|
+
};
|
|
43618
|
+
if (cell.name === "th") json.title = true;
|
|
43619
|
+
const rowspan = intAttr(cell.attrs.rowspan);
|
|
43620
|
+
if (rowspan != null && rowspan >= 2) json.rowspan = rowspan;
|
|
43621
|
+
const colspan = intAttr(cell.attrs.colspan);
|
|
43622
|
+
if (colspan != null && colspan >= 2) json.colspan = colspan;
|
|
43623
|
+
const scope = cell.attrs.scope?.toLowerCase();
|
|
43624
|
+
if (scope && VALID_SCOPES.has(scope)) {
|
|
43625
|
+
json.scope = scope;
|
|
43626
|
+
}
|
|
43627
|
+
const width = this.widthFromCell(cell);
|
|
43628
|
+
if (width != null) json.colwidth = width;
|
|
43629
|
+
return json;
|
|
43630
|
+
}
|
|
43631
|
+
widthFromCell(cell) {
|
|
43632
|
+
const attrWidth = intAttr(cell.attrs.width);
|
|
43633
|
+
if (attrWidth != null && attrWidth > 0) return attrWidth;
|
|
43634
|
+
const style = cell.attrs.style;
|
|
43635
|
+
if (style) {
|
|
43636
|
+
const m = style.match(/width\s*:\s*(\d+)\s*px/i);
|
|
43637
|
+
if (m) {
|
|
43638
|
+
const n = Number.parseInt(m[1], 10);
|
|
43639
|
+
if (Number.isInteger(n) && n > 0) return n;
|
|
43640
|
+
}
|
|
43641
|
+
}
|
|
43642
|
+
return void 0;
|
|
43643
|
+
}
|
|
43644
|
+
isLossyAsBasic(table) {
|
|
43645
|
+
if (table.footer) return true;
|
|
43646
|
+
if (table.header && table.header.rows.length > 1) return true;
|
|
43647
|
+
const sections = [table.header, table.body, table.footer];
|
|
43648
|
+
for (const section of sections) {
|
|
43649
|
+
if (!section) continue;
|
|
43650
|
+
for (const row of section.rows) {
|
|
43651
|
+
for (const cell of row.cells) {
|
|
43652
|
+
if (cell.rowspan || cell.colspan || cell.scope) return true;
|
|
43653
|
+
}
|
|
43654
|
+
}
|
|
43655
|
+
}
|
|
43656
|
+
return false;
|
|
43657
|
+
}
|
|
43658
|
+
// --- content conversion (HTML -> TextAst) ---------------------------------
|
|
43659
|
+
/**
|
|
43660
|
+
* Convert a cell/li's child nodes into block-level TextAst nodes (paragraphs, lists, images).
|
|
43661
|
+
*/
|
|
43662
|
+
blockNodes(nodes) {
|
|
43663
|
+
const blocks = [];
|
|
43664
|
+
let inline = [];
|
|
43665
|
+
const flush = () => {
|
|
43666
|
+
const trimmed = this.trimInline(inline);
|
|
43667
|
+
inline = [];
|
|
43668
|
+
if (trimmed.length === 0) return;
|
|
43669
|
+
if (trimmed.length === 1 && trimmed[0].type === "imageInline") {
|
|
43670
|
+
blocks.push({ ...trimmed[0], type: "image" });
|
|
43671
|
+
} else {
|
|
43672
|
+
blocks.push({ type: "paragraph", content: trimmed, attrs: {} });
|
|
43673
|
+
}
|
|
43674
|
+
};
|
|
43675
|
+
for (const node of nodes) {
|
|
43676
|
+
if (!isElement(node)) {
|
|
43677
|
+
inline.push(...this.inlineText(node.value, []));
|
|
43678
|
+
continue;
|
|
43679
|
+
}
|
|
43680
|
+
const name = node.name;
|
|
43681
|
+
if (name === "p") {
|
|
43682
|
+
flush();
|
|
43683
|
+
const content = this.trimInline(this.inlineNodes(node.children, []));
|
|
43684
|
+
if (content.length > 0) {
|
|
43685
|
+
blocks.push({ type: "paragraph", content, attrs: {} });
|
|
43686
|
+
}
|
|
43687
|
+
} else if (this.isListTag(name)) {
|
|
43688
|
+
flush();
|
|
43689
|
+
const list = this.listNode(node);
|
|
43690
|
+
if (list) blocks.push(list);
|
|
43691
|
+
} else {
|
|
43692
|
+
inline.push(...this.inlineFromElement(node, []));
|
|
43693
|
+
}
|
|
43694
|
+
}
|
|
43695
|
+
flush();
|
|
43696
|
+
return blocks;
|
|
43697
|
+
}
|
|
43698
|
+
/** Convert child nodes to a flat list of inline TextNodes, applying the given marks. */
|
|
43699
|
+
inlineNodes(nodes, marks) {
|
|
43700
|
+
const out = [];
|
|
43701
|
+
for (const node of nodes) {
|
|
43702
|
+
if (!isElement(node)) {
|
|
43703
|
+
out.push(...this.inlineText(node.value, marks));
|
|
43704
|
+
} else {
|
|
43705
|
+
out.push(...this.inlineFromElement(node, marks));
|
|
43706
|
+
}
|
|
43707
|
+
}
|
|
43708
|
+
return out;
|
|
43709
|
+
}
|
|
43710
|
+
inlineFromElement(el, marks) {
|
|
43711
|
+
const name = el.name;
|
|
43712
|
+
if (name === "br") {
|
|
43713
|
+
return [{ type: "hardBreak" }];
|
|
43714
|
+
}
|
|
43715
|
+
if (name === "img") {
|
|
43716
|
+
return [this.imageNode(el, true)];
|
|
43717
|
+
}
|
|
43718
|
+
const markType = MARK_TAGS[name];
|
|
43719
|
+
if (markType) {
|
|
43720
|
+
return this.inlineNodes(el.children, [...marks, { type: markType }]);
|
|
43721
|
+
}
|
|
43722
|
+
if (name === "a") {
|
|
43723
|
+
const linkMark = {
|
|
43724
|
+
type: "link",
|
|
43725
|
+
attrs: {
|
|
43726
|
+
href: el.attrs.href ?? "",
|
|
43727
|
+
...el.attrs.target ? { target: el.attrs.target } : {}
|
|
43728
|
+
}
|
|
43729
|
+
};
|
|
43730
|
+
return this.inlineNodes(el.children, [...marks, linkMark]);
|
|
43731
|
+
}
|
|
43732
|
+
if (this.keepUnknownTags) {
|
|
43733
|
+
const open = this.serializeOpenTag(el);
|
|
43734
|
+
const close = `</${name}>`;
|
|
43735
|
+
return [
|
|
43736
|
+
...this.inlineText(open, marks),
|
|
43737
|
+
...this.inlineNodes(el.children, marks),
|
|
43738
|
+
...this.inlineText(close, marks)
|
|
43739
|
+
];
|
|
43740
|
+
}
|
|
43741
|
+
return this.inlineNodes(el.children, marks);
|
|
43742
|
+
}
|
|
43743
|
+
inlineText(raw, marks) {
|
|
43744
|
+
const text = decodeEntities(raw).replace(/\s+/g, " ");
|
|
43745
|
+
if (text === "") return [];
|
|
43746
|
+
const node = { text, type: "text" };
|
|
43747
|
+
if (marks.length > 0) node.marks = marks.map((m) => ({ ...m }));
|
|
43748
|
+
return [node];
|
|
43749
|
+
}
|
|
43750
|
+
serializeOpenTag(el) {
|
|
43751
|
+
const attrs = Object.entries(el.attrs).map(([k, v]) => v === "" ? ` ${k}` : ` ${k}="${v}"`).join("");
|
|
43752
|
+
return `<${el.name}${attrs}>`;
|
|
43753
|
+
}
|
|
43754
|
+
// --- lists ----------------------------------------------------------------
|
|
43755
|
+
isListTag(name) {
|
|
43756
|
+
return name === "ul" || name === "ol";
|
|
43757
|
+
}
|
|
43758
|
+
listNode(el) {
|
|
43759
|
+
const items = childElements(el, LI_TAGS);
|
|
43760
|
+
if (items.length === 0) return void 0;
|
|
43761
|
+
const isTask = el.name === "ul" && items.some((li) => {
|
|
43762
|
+
const firstEl = li.children.find(isElement);
|
|
43763
|
+
return firstEl?.name === "input" && firstEl.attrs.type?.toLowerCase() === "checkbox";
|
|
43764
|
+
});
|
|
43765
|
+
if (isTask) {
|
|
43766
|
+
return {
|
|
43767
|
+
type: "taskList",
|
|
43768
|
+
content: items.map((li) => this.taskItemNode(li))
|
|
43769
|
+
};
|
|
43770
|
+
}
|
|
43771
|
+
const type = this.listType(el);
|
|
43772
|
+
const node = {
|
|
43773
|
+
type,
|
|
43774
|
+
content: items.map((li) => this.listItemNode(li))
|
|
43775
|
+
};
|
|
43776
|
+
if (el.name === "ol") {
|
|
43777
|
+
const start = intAttr(el.attrs.start);
|
|
43778
|
+
if (start != null) {
|
|
43779
|
+
node.attrs = { start };
|
|
43780
|
+
}
|
|
43781
|
+
}
|
|
43782
|
+
return node;
|
|
43783
|
+
}
|
|
43784
|
+
listType(el) {
|
|
43785
|
+
if (el.name === "ol") {
|
|
43786
|
+
switch (el.attrs.type) {
|
|
43787
|
+
case "i":
|
|
43788
|
+
return "orderedListRomanLower";
|
|
43789
|
+
case "I":
|
|
43790
|
+
return "orderedListRoman";
|
|
43791
|
+
case "a":
|
|
43792
|
+
return "letteredListLower";
|
|
43793
|
+
case "A":
|
|
43794
|
+
return "letteredList";
|
|
43795
|
+
default:
|
|
43796
|
+
return "orderedList";
|
|
43797
|
+
}
|
|
43798
|
+
}
|
|
43799
|
+
const style = el.attrs.style ?? "";
|
|
43800
|
+
if (/list-style(-type)?\s*:\s*none/i.test(style)) return "noBulletList";
|
|
43801
|
+
return "bulletList";
|
|
43802
|
+
}
|
|
43803
|
+
listItemNode(li) {
|
|
43804
|
+
let content = this.blockNodes(li.children);
|
|
43805
|
+
if (content.length === 0) {
|
|
43806
|
+
content = [{ type: "paragraph", content: [], attrs: {} }];
|
|
43807
|
+
}
|
|
43808
|
+
return { type: "listItem", content };
|
|
43809
|
+
}
|
|
43810
|
+
taskItemNode(li) {
|
|
43811
|
+
const checkbox = li.children.find(
|
|
43812
|
+
(c) => isElement(c) && c.name === "input" && c.attrs.type?.toLowerCase() === "checkbox"
|
|
43813
|
+
);
|
|
43814
|
+
const checked = checkbox ? "checked" in checkbox.attrs : false;
|
|
43815
|
+
const rest = li.children.filter((c) => c !== checkbox);
|
|
43816
|
+
let content = this.blockNodes(rest);
|
|
43817
|
+
if (content.length === 0) {
|
|
43818
|
+
content = [{ type: "paragraph", content: [], attrs: {} }];
|
|
43819
|
+
}
|
|
43820
|
+
return { type: "taskItem", attrs: { checked }, content };
|
|
43821
|
+
}
|
|
43822
|
+
// --- images ---------------------------------------------------------------
|
|
43823
|
+
imageNode(el, inline) {
|
|
43824
|
+
const attrs = { src: el.attrs.src ?? "" };
|
|
43825
|
+
attrs.alt = el.attrs.alt ?? null;
|
|
43826
|
+
attrs.title = el.attrs.title ?? null;
|
|
43827
|
+
const width = intAttr(el.attrs.width);
|
|
43828
|
+
if (width != null) attrs.width = width;
|
|
43829
|
+
const height = intAttr(el.attrs.height);
|
|
43830
|
+
if (height != null) attrs.height = height;
|
|
43831
|
+
if (el.attrs.class) attrs.class = el.attrs.class;
|
|
43832
|
+
return { type: inline ? "imageInline" : "image", attrs };
|
|
43833
|
+
}
|
|
43834
|
+
// --- whitespace -----------------------------------------------------------
|
|
43835
|
+
/** Trim leading/trailing whitespace from inline content (edges only). */
|
|
43836
|
+
trimInline(nodes) {
|
|
43837
|
+
const out = nodes.slice();
|
|
43838
|
+
const isWs = (n) => n.type === "text" && /^\s*$/.test(n.text ?? "");
|
|
43839
|
+
while (out.length > 0 && isWs(out[0])) out.shift();
|
|
43840
|
+
if (out.length > 0 && out[0].type === "text") {
|
|
43841
|
+
out[0] = { ...out[0], text: (out[0].text ?? "").replace(/^\s+/, "") };
|
|
43842
|
+
}
|
|
43843
|
+
while (out.length > 0 && isWs(out[out.length - 1])) out.pop();
|
|
43844
|
+
if (out.length > 0 && out[out.length - 1].type === "text") {
|
|
43845
|
+
const last = out.length - 1;
|
|
43846
|
+
out[last] = { ...out[last], text: (out[last].text ?? "").replace(/\s+$/, "") };
|
|
43847
|
+
}
|
|
43848
|
+
return out.filter((n) => !(n.type === "text" && n.text === ""));
|
|
43849
|
+
}
|
|
43850
|
+
};
|
|
43851
|
+
|
|
42922
43852
|
// src/BitmarkParserGenerator.ts
|
|
42923
43853
|
var Input = {
|
|
42924
43854
|
/**
|
|
@@ -42956,7 +43886,11 @@ var InputFormat = {
|
|
|
42956
43886
|
/**
|
|
42957
43887
|
* Input is plain text
|
|
42958
43888
|
*/
|
|
42959
|
-
plainText: "plainText"
|
|
43889
|
+
plainText: "plainText",
|
|
43890
|
+
/**
|
|
43891
|
+
* Input is HTML (used by convertHtmlTable)
|
|
43892
|
+
*/
|
|
43893
|
+
html: "html"
|
|
42960
43894
|
};
|
|
42961
43895
|
var BitmarkParserGenerator = class {
|
|
42962
43896
|
ast = new Ast();
|
|
@@ -43077,8 +44011,8 @@ var BitmarkParserGenerator = class {
|
|
|
43077
44011
|
}
|
|
43078
44012
|
if (!opts.inputFormat || opts.inputFormat === Input.file) {
|
|
43079
44013
|
if (env.isNode) {
|
|
43080
|
-
if (inputIsString &&
|
|
43081
|
-
inStr =
|
|
44014
|
+
if (inputIsString && fs4.existsSync(inStr)) {
|
|
44015
|
+
inStr = fs4.readFileSync(inStr, {
|
|
43082
44016
|
encoding: "utf8"
|
|
43083
44017
|
});
|
|
43084
44018
|
}
|
|
@@ -43124,7 +44058,7 @@ var BitmarkParserGenerator = class {
|
|
|
43124
44058
|
const textGenerator = new PlainTextGenerator();
|
|
43125
44059
|
const str = textGenerator.generate(json);
|
|
43126
44060
|
if (opts.outputFile) {
|
|
43127
|
-
|
|
44061
|
+
fs4.writeFileSync(opts.outputFile, str, {
|
|
43128
44062
|
encoding: "utf8"
|
|
43129
44063
|
});
|
|
43130
44064
|
} else {
|
|
@@ -43159,7 +44093,7 @@ var BitmarkParserGenerator = class {
|
|
|
43159
44093
|
const textGenerator = new PlainTextGenerator();
|
|
43160
44094
|
const str = textGenerator.generate(json);
|
|
43161
44095
|
if (opts.outputFile) {
|
|
43162
|
-
|
|
44096
|
+
fs4.writeFileSync(opts.outputFile, str, {
|
|
43163
44097
|
encoding: "utf8"
|
|
43164
44098
|
});
|
|
43165
44099
|
} else {
|
|
@@ -43184,7 +44118,7 @@ var BitmarkParserGenerator = class {
|
|
|
43184
44118
|
const textGenerator = new PlainTextGenerator();
|
|
43185
44119
|
const str = textGenerator.generate(json);
|
|
43186
44120
|
if (opts.outputFile) {
|
|
43187
|
-
|
|
44121
|
+
fs4.writeFileSync(opts.outputFile, str, {
|
|
43188
44122
|
encoding: "utf8"
|
|
43189
44123
|
});
|
|
43190
44124
|
} else {
|
|
@@ -43268,8 +44202,8 @@ var BitmarkParserGenerator = class {
|
|
|
43268
44202
|
}
|
|
43269
44203
|
if (!opts.inputFormat || opts.inputFormat === Input.file) {
|
|
43270
44204
|
if (env.isNode) {
|
|
43271
|
-
if (inputIsString &&
|
|
43272
|
-
inStr =
|
|
44205
|
+
if (inputIsString && fs4.existsSync(inStr)) {
|
|
44206
|
+
inStr = fs4.readFileSync(inStr, {
|
|
43273
44207
|
encoding: "utf8"
|
|
43274
44208
|
});
|
|
43275
44209
|
}
|
|
@@ -43327,8 +44261,8 @@ var BitmarkParserGenerator = class {
|
|
|
43327
44261
|
const opts = Object.assign({}, options);
|
|
43328
44262
|
if (!opts.inputFormat || opts.inputFormat === Input.file) {
|
|
43329
44263
|
if (env.isNode) {
|
|
43330
|
-
if (inputIsString &&
|
|
43331
|
-
inStr =
|
|
44264
|
+
if (inputIsString && fs4.existsSync(inStr)) {
|
|
44265
|
+
inStr = fs4.readFileSync(inStr, {
|
|
43332
44266
|
encoding: "utf8"
|
|
43333
44267
|
});
|
|
43334
44268
|
}
|
|
@@ -43388,8 +44322,8 @@ var BitmarkParserGenerator = class {
|
|
|
43388
44322
|
}
|
|
43389
44323
|
if (!opts.inputFormat || opts.inputFormat === Input.file) {
|
|
43390
44324
|
if (env.isNode) {
|
|
43391
|
-
if (inputIsString &&
|
|
43392
|
-
inStr =
|
|
44325
|
+
if (inputIsString && fs4.existsSync(inStr)) {
|
|
44326
|
+
inStr = fs4.readFileSync(inStr, {
|
|
43393
44327
|
encoding: "utf8"
|
|
43394
44328
|
});
|
|
43395
44329
|
}
|
|
@@ -43412,8 +44346,8 @@ var BitmarkParserGenerator = class {
|
|
|
43412
44346
|
strRes = this.jsonStringifyPrettify(preRes, jsonOptions, true);
|
|
43413
44347
|
}
|
|
43414
44348
|
const flag = fileOptions.append ? "a" : "w";
|
|
43415
|
-
|
|
43416
|
-
|
|
44349
|
+
fs4.ensureDirSync(path3.dirname(output));
|
|
44350
|
+
fs4.writeFileSync(output, strRes, {
|
|
43417
44351
|
flag
|
|
43418
44352
|
});
|
|
43419
44353
|
} else {
|
|
@@ -43473,6 +44407,87 @@ var BitmarkParserGenerator = class {
|
|
|
43473
44407
|
const res = generator.generate(data);
|
|
43474
44408
|
return res;
|
|
43475
44409
|
}
|
|
44410
|
+
/**
|
|
44411
|
+
* Convert between HTML tables and bitmark tables.
|
|
44412
|
+
*
|
|
44413
|
+
* Direction is auto-detected (override with `options.inputFormat`):
|
|
44414
|
+
* - HTML input: every `<table>` is extracted and emitted as a `[.table-extended]` (or `[.table]`)
|
|
44415
|
+
* bit; output as bitmark (default), JSON, AST, or HTML (re-emit).
|
|
44416
|
+
* - bitmark / JSON / AST input: each `table` / `table-extended` bit is rendered as an HTML
|
|
44417
|
+
* `<table>` fragment.
|
|
44418
|
+
*
|
|
44419
|
+
* Cell content is reproduced verbatim except inline conversion to bitmark marks (bold, italic,
|
|
44420
|
+
* superscript, etc.), with lists and images mapped to their bitmark equivalents.
|
|
44421
|
+
*
|
|
44422
|
+
* @param input - HTML, bitmark, JSON or AST string; or a parsed JSON/AST value; or a file path.
|
|
44423
|
+
* @param options - the conversion options
|
|
44424
|
+
* @returns the converted output as a string (or object for JSON/AST), or void when writing a file
|
|
44425
|
+
* @throws Error if any error occurs
|
|
44426
|
+
*/
|
|
44427
|
+
convertHtmlTable(input, options) {
|
|
44428
|
+
const opts = Object.assign({}, options);
|
|
44429
|
+
if (env.isBrowser && opts.outputFile) {
|
|
44430
|
+
throw new Error("Cannot write to file in browser environment");
|
|
44431
|
+
}
|
|
44432
|
+
let inStr = input;
|
|
44433
|
+
const inputIsString = typeof input === "string";
|
|
44434
|
+
if (env.isNode && inputIsString && fs4.existsSync(inStr)) {
|
|
44435
|
+
inStr = fs4.readFileSync(inStr, { encoding: "utf8" });
|
|
44436
|
+
}
|
|
44437
|
+
const isHtmlString = (s) => {
|
|
44438
|
+
const t = s.replace(/^\s+/, "");
|
|
44439
|
+
return t.startsWith("<") && /<table/i.test(t);
|
|
44440
|
+
};
|
|
44441
|
+
let htmlInput;
|
|
44442
|
+
if (opts.inputFormat === InputFormat.html) {
|
|
44443
|
+
htmlInput = true;
|
|
44444
|
+
} else if (opts.inputFormat != null) {
|
|
44445
|
+
htmlInput = false;
|
|
44446
|
+
} else {
|
|
44447
|
+
htmlInput = inputIsString && isHtmlString(inStr);
|
|
44448
|
+
}
|
|
44449
|
+
if (htmlInput) {
|
|
44450
|
+
const parser2 = new HtmlTableParser();
|
|
44451
|
+
const bits = parser2.parse(inStr, {
|
|
44452
|
+
tableFormat: opts.tableFormat ?? "table-extended",
|
|
44453
|
+
keepUnknownTags: opts.keepUnknownTags,
|
|
44454
|
+
onWarning: (m) => console.warn(m)
|
|
44455
|
+
});
|
|
44456
|
+
const outputFormat2 = opts.outputFormat ?? Output.bitmark;
|
|
44457
|
+
if (outputFormat2 === "html") {
|
|
44458
|
+
const json2 = this.convert(bits, { outputFormat: Output.json });
|
|
44459
|
+
return this.outputHtml(new HtmlTableGenerator().generate(json2), opts);
|
|
44460
|
+
}
|
|
44461
|
+
return this.convert(bits, {
|
|
44462
|
+
outputFormat: Enum(Output).fromValue(outputFormat2),
|
|
44463
|
+
outputFile: opts.outputFile,
|
|
44464
|
+
fileOptions: opts.fileOptions,
|
|
44465
|
+
jsonOptions: opts.jsonOptions,
|
|
44466
|
+
bitmarkOptions: opts.bitmarkOptions
|
|
44467
|
+
});
|
|
44468
|
+
}
|
|
44469
|
+
const outputFormat = opts.outputFormat ?? "html";
|
|
44470
|
+
if (outputFormat !== "html") {
|
|
44471
|
+
throw new Error(
|
|
44472
|
+
"convertHtmlTable: non-HTML input can only be converted to HTML. Use convert() for bitmark/JSON/AST conversions."
|
|
44473
|
+
);
|
|
44474
|
+
}
|
|
44475
|
+
const json = this.convert(inputIsString ? inStr : input, { outputFormat: Output.json });
|
|
44476
|
+
return this.outputHtml(new HtmlTableGenerator().generate(json), opts);
|
|
44477
|
+
}
|
|
44478
|
+
/**
|
|
44479
|
+
* Write an HTML string to the configured output file, or return it.
|
|
44480
|
+
*/
|
|
44481
|
+
outputHtml(html, opts) {
|
|
44482
|
+
if (opts.outputFile) {
|
|
44483
|
+
const output = opts.outputFile.toString();
|
|
44484
|
+
const flag = opts.fileOptions?.append ? "a" : "w";
|
|
44485
|
+
fs4.ensureDirSync(path3.dirname(output));
|
|
44486
|
+
fs4.writeFileSync(output, html, { flag });
|
|
44487
|
+
return;
|
|
44488
|
+
}
|
|
44489
|
+
return html;
|
|
44490
|
+
}
|
|
43476
44491
|
/**
|
|
43477
44492
|
* Breakscape bitmark text.
|
|
43478
44493
|
*
|
|
@@ -43504,8 +44519,8 @@ var BitmarkParserGenerator = class {
|
|
|
43504
44519
|
}
|
|
43505
44520
|
if (!opts.inputFormat || opts.inputFormat === Input.file) {
|
|
43506
44521
|
if (env.isNode) {
|
|
43507
|
-
if (inputIsString &&
|
|
43508
|
-
inStr =
|
|
44522
|
+
if (inputIsString && fs4.existsSync(inStr)) {
|
|
44523
|
+
inStr = fs4.readFileSync(inStr, {
|
|
43509
44524
|
encoding: "utf8"
|
|
43510
44525
|
});
|
|
43511
44526
|
}
|
|
@@ -43518,8 +44533,8 @@ var BitmarkParserGenerator = class {
|
|
|
43518
44533
|
if (opts.outputFile) {
|
|
43519
44534
|
const output = opts.outputFile.toString();
|
|
43520
44535
|
const flag = fileOptions.append ? "a" : "w";
|
|
43521
|
-
|
|
43522
|
-
|
|
44536
|
+
fs4.ensureDirSync(path3.dirname(output));
|
|
44537
|
+
fs4.writeFileSync(output, res, {
|
|
43523
44538
|
flag
|
|
43524
44539
|
});
|
|
43525
44540
|
} else {
|
|
@@ -43557,8 +44572,8 @@ var BitmarkParserGenerator = class {
|
|
|
43557
44572
|
}
|
|
43558
44573
|
if (!opts.inputFormat || opts.inputFormat === Input.file) {
|
|
43559
44574
|
if (env.isNode) {
|
|
43560
|
-
if (inputIsString &&
|
|
43561
|
-
inStr =
|
|
44575
|
+
if (inputIsString && fs4.existsSync(inStr)) {
|
|
44576
|
+
inStr = fs4.readFileSync(inStr, {
|
|
43562
44577
|
encoding: "utf8"
|
|
43563
44578
|
});
|
|
43564
44579
|
}
|
|
@@ -43571,8 +44586,8 @@ var BitmarkParserGenerator = class {
|
|
|
43571
44586
|
if (opts.outputFile) {
|
|
43572
44587
|
const output = opts.outputFile.toString();
|
|
43573
44588
|
const flag = fileOptions.append ? "a" : "w";
|
|
43574
|
-
|
|
43575
|
-
|
|
44589
|
+
fs4.ensureDirSync(path3.dirname(output));
|
|
44590
|
+
fs4.writeFileSync(output, res, {
|
|
43576
44591
|
flag
|
|
43577
44592
|
});
|
|
43578
44593
|
} else {
|
|
@@ -43627,8 +44642,8 @@ var BitmarkParserGenerator = class {
|
|
|
43627
44642
|
init();
|
|
43628
44643
|
async function readInput(input) {
|
|
43629
44644
|
if (input !== void 0) {
|
|
43630
|
-
if (await
|
|
43631
|
-
return
|
|
44645
|
+
if (await fs4.pathExists(input)) {
|
|
44646
|
+
return fs4.readFile(input, "utf8");
|
|
43632
44647
|
}
|
|
43633
44648
|
return input;
|
|
43634
44649
|
}
|
|
@@ -43641,8 +44656,8 @@ async function readInput(input) {
|
|
|
43641
44656
|
async function writeOutput(content, outputFile, append = false) {
|
|
43642
44657
|
const text = typeof content === "string" ? content : JSON.stringify(content);
|
|
43643
44658
|
if (outputFile) {
|
|
43644
|
-
await
|
|
43645
|
-
await
|
|
44659
|
+
await fs4.ensureDir(path3.dirname(outputFile));
|
|
44660
|
+
await fs4.writeFile(outputFile, text, { flag: append ? "a" : "w" });
|
|
43646
44661
|
} else {
|
|
43647
44662
|
console.log(text);
|
|
43648
44663
|
}
|
|
@@ -43791,6 +44806,70 @@ Examples:
|
|
|
43791
44806
|
);
|
|
43792
44807
|
return cmd;
|
|
43793
44808
|
}
|
|
44809
|
+
var OUTPUT_FORMAT_CHOICES2 = ["html", "bitmark", "json", "ast"];
|
|
44810
|
+
var INPUT_FORMAT_CHOICES = ["html", "bitmark", "json"];
|
|
44811
|
+
var TABLE_FORMAT_CHOICES = ["table", "table-extended"];
|
|
44812
|
+
function createConvertHtmlTableCommand() {
|
|
44813
|
+
const bpg = new BitmarkParserGenerator();
|
|
44814
|
+
const cmd = new Command("convertHtmlTable").description("Convert between HTML tables and bitmark tables").argument(
|
|
44815
|
+
"[input]",
|
|
44816
|
+
"file to read, or HTML / bitmark / json string. If not specified, input will be from <stdin>"
|
|
44817
|
+
).addOption(
|
|
44818
|
+
new Option(
|
|
44819
|
+
"-f, --format <format>",
|
|
44820
|
+
"output format (default: bitmark for HTML input, html for bitmark/json input)"
|
|
44821
|
+
).choices(OUTPUT_FORMAT_CHOICES2)
|
|
44822
|
+
).addOption(
|
|
44823
|
+
new Option("--inputFormat <format>", "force input format (auto-detected by default)").choices(
|
|
44824
|
+
INPUT_FORMAT_CHOICES
|
|
44825
|
+
)
|
|
44826
|
+
).addOption(
|
|
44827
|
+
new Option("--tableFormat <format>", "bit type to emit for HTML input").choices(TABLE_FORMAT_CHOICES).default("table-extended")
|
|
44828
|
+
).option("--keepUnknownTags", "keep unmappable HTML tags as literal text (HTML input only)").option("-p, --pretty", "prettify the JSON output with indent").option(
|
|
44829
|
+
"--indent <indent>",
|
|
44830
|
+
"prettify indent (default: 2 when --pretty is set)",
|
|
44831
|
+
(v) => Number.parseInt(v, 10)
|
|
44832
|
+
).option("-a, --append", "append to the output file (default is to overwrite)").option("-o, --output <file>", "output file. If not specified, output will be to <stdout>").action(async (input, options) => {
|
|
44833
|
+
try {
|
|
44834
|
+
const dataIn = await readInput(input);
|
|
44835
|
+
const prettify = options.pretty ? options.indent ?? 2 : void 0;
|
|
44836
|
+
const inputFormat = options.inputFormat === "html" ? InputFormat.html : options.inputFormat != null ? InputFormat.bitmark : void 0;
|
|
44837
|
+
const result = bpg.convertHtmlTable(dataIn, {
|
|
44838
|
+
inputFormat,
|
|
44839
|
+
outputFormat: options.format,
|
|
44840
|
+
tableFormat: Enum({ table: "table", "table-extended": "table-extended" }).fromValue(
|
|
44841
|
+
options.tableFormat
|
|
44842
|
+
),
|
|
44843
|
+
keepUnknownTags: options.keepUnknownTags,
|
|
44844
|
+
jsonOptions: {
|
|
44845
|
+
prettify
|
|
44846
|
+
}
|
|
44847
|
+
});
|
|
44848
|
+
let outputValue = result ?? "";
|
|
44849
|
+
if (typeof outputValue !== "string") {
|
|
44850
|
+
outputValue = formatJson(outputValue, options.pretty, options.indent);
|
|
44851
|
+
}
|
|
44852
|
+
await writeOutput(outputValue, options.output, options.append);
|
|
44853
|
+
} catch (error) {
|
|
44854
|
+
console.error("Error:", error instanceof Error ? error.message : String(error));
|
|
44855
|
+
process.exit(1);
|
|
44856
|
+
}
|
|
44857
|
+
}).addHelpText(
|
|
44858
|
+
"after",
|
|
44859
|
+
`
|
|
44860
|
+
Examples:
|
|
44861
|
+
$ bitmark-parser convertHtmlTable '<table><tr><th>Name</th></tr><tr><td>John</td></tr></table>'
|
|
44862
|
+
|
|
44863
|
+
$ bitmark-parser convertHtmlTable input.html -o output.bitmark
|
|
44864
|
+
|
|
44865
|
+
$ bitmark-parser convertHtmlTable input.html -f json -p -o output.json
|
|
44866
|
+
|
|
44867
|
+
$ bitmark-parser convertHtmlTable input.bitmark -o output.html
|
|
44868
|
+
|
|
44869
|
+
$ bitmark-parser convertHtmlTable --tableFormat table input.html`
|
|
44870
|
+
);
|
|
44871
|
+
return cmd;
|
|
44872
|
+
}
|
|
43794
44873
|
var TEXT_FORMAT_CHOICES = (() => {
|
|
43795
44874
|
const choices = enumChoices(BodyTextFormat);
|
|
43796
44875
|
const preferred = BodyTextFormat.bitmarkPlusPlus;
|
|
@@ -43847,7 +44926,7 @@ Examples:
|
|
|
43847
44926
|
);
|
|
43848
44927
|
return cmd;
|
|
43849
44928
|
}
|
|
43850
|
-
var
|
|
44929
|
+
var INPUT_FORMAT_CHOICES2 = enumChoices(InputFormat);
|
|
43851
44930
|
function createExtractPlainTextCommand() {
|
|
43852
44931
|
const bpg = new BitmarkParserGenerator();
|
|
43853
44932
|
const cmd = new Command("extractPlainText").description("Extract plain text from bitmark, bitmark text, or JSON").argument(
|
|
@@ -43857,7 +44936,7 @@ function createExtractPlainTextCommand() {
|
|
|
43857
44936
|
new Option(
|
|
43858
44937
|
"-f, --inputFormat <format>",
|
|
43859
44938
|
"force input format (auto-detected by default)"
|
|
43860
|
-
).choices([...
|
|
44939
|
+
).choices([...INPUT_FORMAT_CHOICES2])
|
|
43861
44940
|
).option("-a, --append", "append to the output file (default is to overwrite)").option("-o, --output <file>", "output file. If not specified, output will be to <stdout>").action(async (input, options) => {
|
|
43862
44941
|
try {
|
|
43863
44942
|
const dataIn = await readInput(input);
|
|
@@ -44009,6 +45088,7 @@ async function asyncInit() {
|
|
|
44009
45088
|
program.outputHelp();
|
|
44010
45089
|
});
|
|
44011
45090
|
program.addCommand(createConvertCommand());
|
|
45091
|
+
program.addCommand(createConvertHtmlTableCommand());
|
|
44012
45092
|
program.addCommand(createConvertTextCommand());
|
|
44013
45093
|
program.addCommand(createExtractPlainTextCommand());
|
|
44014
45094
|
program.addCommand(createBreakscapeCommand());
|