@gmb/bitmark-parser-generator 5.26.0 → 5.28.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.
@@ -545,6 +545,14 @@ var BitType2 = {
545
545
  smartStandardRemarkNonNormativeCollapsible: "smart-standard-remark-non-normative-collapsible",
546
546
  smartStandardRemarkNormative: "smart-standard-remark-normative",
547
547
  smartStandardRemarkNormativeCollapsible: "smart-standard-remark-normative-collapsible",
548
+ smartStandardRemarkTableExtendedImageNonNormative: "smart-standard-remark-table-extended-image-non-normative",
549
+ smartStandardRemarkTableExtendedImageNonNormativeCollapsible: "smart-standard-remark-table-extended-image-non-normative-collapsible",
550
+ smartStandardRemarkTableExtendedImageNormative: "smart-standard-remark-table-extended-image-normative",
551
+ smartStandardRemarkTableExtendedImageNormativeCollapsible: "smart-standard-remark-table-extended-image-normative-collapsible",
552
+ smartStandardRemarkTableExtendedNonNormative: "smart-standard-remark-table-extended-non-normative",
553
+ smartStandardRemarkTableExtendedNonNormativeCollapsible: "smart-standard-remark-table-extended-non-normative-collapsible",
554
+ smartStandardRemarkTableExtendedNormative: "smart-standard-remark-table-extended-normative",
555
+ smartStandardRemarkTableExtendedNormativeCollapsible: "smart-standard-remark-table-extended-normative-collapsible",
548
556
  smartStandardRemarkTableImageNonNormative: "smart-standard-remark-table-image-non-normative",
549
557
  smartStandardRemarkTableImageNonNormativeCollapsible: "smart-standard-remark-table-image-non-normative-collapsible",
550
558
  smartStandardRemarkTableImageNormative: "smart-standard-remark-table-image-normative",
@@ -553,6 +561,14 @@ var BitType2 = {
553
561
  smartStandardRemarkTableNonNormativeCollapsible: "smart-standard-remark-table-non-normative-collapsible",
554
562
  smartStandardRemarkTableNormative: "smart-standard-remark-table-normative",
555
563
  smartStandardRemarkTableNormativeCollapsible: "smart-standard-remark-table-normative-collapsible",
564
+ smartStandardTableExtendedImageNonNormative: "smart-standard-table-extended-image-non-normative",
565
+ smartStandardTableExtendedImageNonNormativeCollapsible: "smart-standard-table-extended-image-non-normative-collapsible",
566
+ smartStandardTableExtendedImageNormative: "smart-standard-table-extended-image-normative",
567
+ smartStandardTableExtendedImageNormativeCollapsible: "smart-standard-table-extended-image-normative-collapsible",
568
+ smartStandardTableExtendedNonNormative: "smart-standard-table-extended-non-normative",
569
+ smartStandardTableExtendedNonNormativeCollapsible: "smart-standard-table-extended-non-normative-collapsible",
570
+ smartStandardTableExtendedNormative: "smart-standard-table-extended-normative",
571
+ smartStandardTableExtendedNormativeCollapsible: "smart-standard-table-extended-normative-collapsible",
556
572
  smartStandardTableImageNonNormative: "smart-standard-table-image-non-normative",
557
573
  smartStandardTableImageNonNormativeCollapsible: "smart-standard-table-image-non-normative-collapsible",
558
574
  smartStandardTableImageNormative: "smart-standard-table-image-normative",
@@ -575,10 +591,18 @@ var BitType2 = {
575
591
  standardNoteNormative: "standard-note-normative",
576
592
  standardRemarkNonNormative: "standard-remark-non-normative",
577
593
  standardRemarkNormative: "standard-remark-normative",
594
+ standardRemarkTableExtendedImageNonNormative: "standard-remark-table-extended-image-non-normative",
595
+ standardRemarkTableExtendedImageNormative: "standard-remark-table-extended-image-normative",
596
+ standardRemarkTableExtendedNonNormative: "standard-remark-table-extended-non-normative",
597
+ standardRemarkTableExtendedNormative: "standard-remark-table-extended-normative",
578
598
  standardRemarkTableImageNonNormative: "standard-remark-table-image-non-normative",
579
599
  standardRemarkTableImageNormative: "standard-remark-table-image-normative",
580
600
  standardRemarkTableNonNormative: "standard-remark-table-non-normative",
581
601
  standardRemarkTableNormative: "standard-remark-table-normative",
602
+ standardTableExtendedImageNonNormative: "standard-table-extended-image-non-normative",
603
+ standardTableExtendedImageNormative: "standard-table-extended-image-normative",
604
+ standardTableExtendedNonNormative: "standard-table-extended-non-normative",
605
+ standardTableExtendedNormative: "standard-table-extended-normative",
582
606
  standardTableImageNonNormative: "standard-table-image-non-normative",
583
607
  standardTableImageNormative: "standard-table-image-normative",
584
608
  standardTableNonNormative: "standard-table-non-normative",
@@ -805,6 +829,10 @@ var AbstractTagConfig = class {
805
829
  // New JSON-pattern jsonKey (export-only)
806
830
  __publicField(this, "hasExportJsonKey");
807
831
  // True iff exportJsonKey was explicitly set
832
+ __publicField(this, "htmlKey");
833
+ // HTML key-pattern (export-only)
834
+ __publicField(this, "hasHtmlKey");
835
+ // True iff htmlKey was explicitly set
808
836
  __publicField(this, "deprecated");
809
837
  this.type = params.type;
810
838
  this.configKey = params.configKey;
@@ -815,6 +843,8 @@ var AbstractTagConfig = class {
815
843
  this.jsonKey = params.jsonKey;
816
844
  this.exportJsonKey = params.exportJsonKey;
817
845
  this.hasExportJsonKey = params.hasExportJsonKey;
846
+ this.htmlKey = params.htmlKey;
847
+ this.hasHtmlKey = params.hasHtmlKey;
818
848
  this.deprecated = params.deprecated;
819
849
  }
820
850
  };
@@ -936,7 +966,7 @@ var ResourceTagConfig = class extends AbstractTagConfig {
936
966
  // src/model/config/CardVariantConfig.ts
937
967
  var CardVariantConfig = class {
938
968
  // Body text format. Default: bitmark++
939
- constructor(tags2, bodyAllowed, bodyRequired, repeatCount, jsonKey, exportJsonKey, hasExportJsonKey = false, format) {
969
+ constructor(tags2, bodyAllowed, bodyRequired, repeatCount, jsonKey, exportJsonKey, hasExportJsonKey = false, format, htmlKey, hasHtmlKey = false) {
940
970
  __publicField(this, "tags");
941
971
  __publicField(this, "bodyAllowed");
942
972
  // Default: true
@@ -950,6 +980,9 @@ var CardVariantConfig = class {
950
980
  __publicField(this, "exportJsonKey");
951
981
  // New JSON-pattern jsonKey
952
982
  __publicField(this, "hasExportJsonKey");
983
+ __publicField(this, "htmlKey");
984
+ // HTML key-pattern
985
+ __publicField(this, "hasHtmlKey");
953
986
  __publicField(this, "format");
954
987
  this.tags = tags2;
955
988
  this.bodyAllowed = bodyAllowed == null ? true : bodyAllowed;
@@ -958,6 +991,8 @@ var CardVariantConfig = class {
958
991
  this.jsonKey = jsonKey;
959
992
  this.exportJsonKey = exportJsonKey;
960
993
  this.hasExportJsonKey = hasExportJsonKey;
994
+ this.htmlKey = htmlKey;
995
+ this.hasHtmlKey = hasHtmlKey;
961
996
  this.format = format;
962
997
  }
963
998
  toString(options) {
@@ -982,18 +1017,22 @@ ${tag.toString(opts)}`;
982
1017
 
983
1018
  // src/model/config/CardSideConfig.ts
984
1019
  var CardSideConfig = class {
985
- constructor(name, repeat, variants, jsonKey, exportJsonKey, hasExportJsonKey = false) {
1020
+ constructor(name, repeat, variants, jsonKey, exportJsonKey, hasExportJsonKey = false, htmlKey, hasHtmlKey = false) {
986
1021
  __publicField(this, "name");
987
1022
  __publicField(this, "repeat");
988
1023
  __publicField(this, "jsonKey");
989
1024
  __publicField(this, "exportJsonKey");
990
1025
  __publicField(this, "hasExportJsonKey");
1026
+ __publicField(this, "htmlKey");
1027
+ __publicField(this, "hasHtmlKey");
991
1028
  __publicField(this, "variants");
992
1029
  this.name = name;
993
1030
  this.repeat = repeat;
994
1031
  this.jsonKey = jsonKey;
995
1032
  this.exportJsonKey = exportJsonKey;
996
1033
  this.hasExportJsonKey = hasExportJsonKey;
1034
+ this.htmlKey = htmlKey;
1035
+ this.hasHtmlKey = hasHtmlKey;
997
1036
  this.variants = variants;
998
1037
  }
999
1038
  toString(options) {
@@ -1015,17 +1054,21 @@ var CardSideConfig = class {
1015
1054
 
1016
1055
  // src/model/config/CardSetConfig.ts
1017
1056
  var CardSetConfig = class {
1018
- constructor(configKey, jsonKey, exportJsonKey, hasExportJsonKey, sections, sides) {
1057
+ constructor(configKey, jsonKey, exportJsonKey, hasExportJsonKey, sections, sides, htmlKey = void 0, hasHtmlKey = false) {
1019
1058
  __publicField(this, "configKey");
1020
1059
  __publicField(this, "jsonKey");
1021
1060
  __publicField(this, "exportJsonKey");
1022
1061
  __publicField(this, "hasExportJsonKey");
1062
+ __publicField(this, "htmlKey");
1063
+ __publicField(this, "hasHtmlKey");
1023
1064
  __publicField(this, "sections");
1024
1065
  __publicField(this, "sides");
1025
1066
  this.configKey = configKey;
1026
1067
  this.jsonKey = jsonKey;
1027
1068
  this.exportJsonKey = exportJsonKey;
1028
1069
  this.hasExportJsonKey = hasExportJsonKey;
1070
+ this.htmlKey = htmlKey;
1071
+ this.hasHtmlKey = hasHtmlKey;
1029
1072
  this.sections = sections;
1030
1073
  this.sides = sides;
1031
1074
  }
@@ -1322,6 +1365,8 @@ var propertyKeys = {
1322
1365
  property_externalLinkText: "@externalLinkText",
1323
1366
  property_feedbackEngine: "@feedbackEngine",
1324
1367
  property_feedbackType: "@feedbackType",
1368
+ property_userFeedbackTranslationUrl: "@userFeedbackTranslationUrl",
1369
+ property_userFeedbackContentUrl: "@userFeedbackContentUrl",
1325
1370
  property_flashcardSet: "@flashcardSet",
1326
1371
  property_focusX: "@focusX",
1327
1372
  property_focusY: "@focusY",
@@ -3705,6 +3750,16 @@ var CARDSETS = {
3705
3750
  [CardSetConfigKey.table]: {
3706
3751
  jsonKey: null,
3707
3752
  exportJsonKey: null,
3753
+ // PLAN-109 / HTML.md §8 — idiomatic HTML mapping. The classic (non-extended)
3754
+ // table produces the same `<table>`/`<thead>`/`<tbody>`/`<tfoot>` structure as
3755
+ // table-extended, so the structural htmlKeys mirror that cardSet. NOTE: the
3756
+ // JSON side routes the FIRST header card → `columns` (header) and SUBSEQUENT
3757
+ // header cards → `data` (body); HTML uses a uniform `<thead>` for the whole
3758
+ // `table-header` section, so a multi-card header (e.g. a second header card
3759
+ // that JSON sends to `data`) renders as additional `<thead>` rows rather than
3760
+ // moving to `<tbody>`. Per-card header/body splitting needs engine-level
3761
+ // routing not yet expressible in the pattern vocabulary — see PLAN-109.
3762
+ htmlKey: { "@el": "table", "@children": "$" },
3708
3763
  sections: {
3709
3764
  "table-header": {
3710
3765
  // First header card's row of cells → `columns`. Subsequent header
@@ -3723,25 +3778,36 @@ var CARDSETS = {
3723
3778
  },
3724
3779
  { "@cardIndex=0": { "@bit": { table: { columns: "$" } } } },
3725
3780
  { "@bit": { table: { data: ["$"] } } }
3726
- ]
3781
+ ],
3782
+ // Header section → `<thead>` rows of `<th>`; `@tableColWidth` bubbles a
3783
+ // `width` attr onto the enclosing `<th>` (HTML-C2).
3784
+ htmlKey: { "@el": "thead", "@children": { "@el": "tr", "@children": "$" } },
3785
+ sideHtmlKey: { "@el": "th", "@children": "$" }
3727
3786
  },
3728
3787
  "table-body": {
3729
3788
  // Batched emission: `$` is the entire 2D array of body card rows.
3730
3789
  // This is the default section (no qualifier → cards land here).
3731
3790
  jsonKey: "table.data",
3732
3791
  exportJsonKey: { "@bit": { table: { data: "$" } } },
3792
+ htmlKey: { "@el": "tbody", "@children": { "@el": "tr", "@children": "$" } },
3733
3793
  isDefault: true
3734
3794
  },
3735
3795
  "table-footer": {
3736
3796
  // Batched emission: `$` is the entire 2D array of footer rows.
3737
3797
  jsonKey: "table.data",
3738
- exportJsonKey: { "@bit": { table: { data: "$" } } }
3798
+ exportJsonKey: { "@bit": { table: { data: "$" } } },
3799
+ // Footer cells route to `data` (not `columns`), so they are `<td>` (no
3800
+ // sideHtmlKey override — the cell side default applies).
3801
+ htmlKey: { "@el": "tfoot", "@children": { "@el": "tr", "@children": "$" } }
3739
3802
  }
3740
3803
  },
3741
3804
  sides: [
3742
3805
  {
3743
3806
  name: "cell",
3744
3807
  repeat: true,
3808
+ // Default (body/footer) cell → `<td>`; the header section overrides to
3809
+ // `<th>` via its sideHtmlKey (HTML.md §8).
3810
+ htmlKey: { "@el": "td", "@children": "$" },
3745
3811
  variants: [
3746
3812
  {
3747
3813
  jsonKey: null,
@@ -3758,21 +3824,32 @@ var CARDSETS = {
3758
3824
  },
3759
3825
  {
3760
3826
  key: ConfigKey.property_tableCellType,
3827
+ // HTML.md §8: first-match predicate selecting `<th>` vs `<td>`.
3828
+ htmlKey: [{ "@value=th": { "@el": "th" } }, { "@absent": { "@el": "td" } }],
3761
3829
  description: "Table cell type (th/td).",
3762
3830
  format: TagFormat.plainText
3763
3831
  },
3764
3832
  {
3765
3833
  key: ConfigKey.property_tableRowSpan,
3834
+ // HTML-C2: contribute a `rowspan` attribute onto the enclosing
3835
+ // cell element (`<th>`/`<td>`).
3836
+ htmlKey: { "@el": { "@attr": { rowspan: "$" } } },
3766
3837
  description: "Number of rows the cell spans.",
3767
3838
  format: TagFormat.number
3768
3839
  },
3769
3840
  {
3770
3841
  key: ConfigKey.property_tableColSpan,
3842
+ // HTML-C2: contribute a `colspan` attribute onto the enclosing
3843
+ // cell element (`<th>`/`<td>`).
3844
+ htmlKey: { "@el": { "@attr": { colspan: "$" } } },
3771
3845
  description: "Number of columns the cell spans.",
3772
3846
  format: TagFormat.number
3773
3847
  },
3774
3848
  {
3775
3849
  key: ConfigKey.property_tableScope,
3850
+ // HTML-C2: contribute a `scope` attribute onto the enclosing
3851
+ // cell element (`<th>`/`<td>`).
3852
+ htmlKey: { "@el": { "@attr": { scope: "$" } } },
3776
3853
  description: "Scope attribute for header cells.",
3777
3854
  format: TagFormat.plainText
3778
3855
  },
@@ -3780,6 +3857,9 @@ var CARDSETS = {
3780
3857
  key: ConfigKey.property_tableColWidth,
3781
3858
  jsonKey: "^table.columnWidths[{s}]",
3782
3859
  exportJsonKey: { "@bit": { table: { columnWidths: { $s: "$" } } } },
3860
+ // HTML.md §8 + HTML-C2: contribute a `width` attribute onto the
3861
+ // enclosing cell element (`<th>`/`<td>`).
3862
+ htmlKey: { "@el": { "@attr": { width: "$" } } },
3783
3863
  description: "Width for the column.",
3784
3864
  format: TagFormat.number
3785
3865
  }
@@ -3795,6 +3875,12 @@ var CARDSETS = {
3795
3875
  //
3796
3876
  [CardSetConfigKey.tableExtended]: {
3797
3877
  jsonKey: null,
3878
+ // PLAN-109 / HTML.md §8 — idiomatic HTML mapping for the extended table.
3879
+ // The card-set container is the `<table>` element; each section is a
3880
+ // table section element (`<thead>`/`<tbody>`/`<tfoot>`) whose children are
3881
+ // `<tr>` rows, and each cell side is a `<td>` (body) or `<th>` (header /
3882
+ // footer, via the section sideHtmlKey override).
3883
+ htmlKey: { "@el": "table", "@children": "$" },
3798
3884
  sections: {
3799
3885
  "table-header": {
3800
3886
  jsonKey: "table.header.rows",
@@ -3814,19 +3900,29 @@ var CARDSETS = {
3814
3900
  },
3815
3901
  { table: { header: { rows: ["$"] } } }
3816
3902
  ],
3903
+ htmlKey: { "@el": "thead", "@children": { "@el": "tr", "@children": "$" } },
3817
3904
  sideJsonKey: "cells[{s}]|set(title=true)",
3818
- sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } }
3905
+ sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } },
3906
+ // Header cells are `<th>`. The `width` attribute is contributed by the
3907
+ // `@tableColWidth` tag, which bubbles it onto the enclosing `<th>`
3908
+ // (HTML-C2) — so it is not repeated here.
3909
+ sideHtmlKey: { "@el": "th", "@children": "$" }
3819
3910
  },
3820
3911
  "table-body": {
3821
3912
  jsonKey: "table.body.rows",
3822
3913
  exportJsonKey: { table: { body: { rows: "$" } } },
3914
+ htmlKey: { "@el": "tbody", "@children": { "@el": "tr", "@children": "$" } },
3823
3915
  isDefault: true
3824
3916
  },
3825
3917
  "table-footer": {
3826
3918
  jsonKey: "table.footer.rows",
3827
3919
  exportJsonKey: { table: { footer: { rows: "$" } } },
3920
+ htmlKey: { "@el": "tfoot", "@children": { "@el": "tr", "@children": "$" } },
3828
3921
  sideJsonKey: "cells[{s}]|set(title=true)",
3829
- sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } }
3922
+ sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } },
3923
+ // Footer cells render as `<th>` (mirrors the header `title: true`
3924
+ // mapping); §8 lists only the header side, so this parallels it.
3925
+ sideHtmlKey: { "@el": "th", "@children": "$" }
3830
3926
  }
3831
3927
  },
3832
3928
  sides: [
@@ -3835,6 +3931,9 @@ var CARDSETS = {
3835
3931
  repeat: true,
3836
3932
  jsonKey: "cells[{s}]",
3837
3933
  exportJsonKey: { cells: { $s: "$" } },
3934
+ // Default (body) cell → `<td>`; the header/footer sections override the
3935
+ // side to `<th>` via their sideHtmlKey (HTML.md §8).
3936
+ htmlKey: { "@el": "td", "@children": "$" },
3838
3937
  variants: [
3839
3938
  {
3840
3939
  jsonKey: "content",
@@ -3858,6 +3957,9 @@ var CARDSETS = {
3858
3957
  key: ConfigKey.property_tableCellType,
3859
3958
  jsonKey: "title|bool(th)",
3860
3959
  exportJsonKey: [{ "@value=th": { title: true } }],
3960
+ // HTML.md §8: same first-match predicate machinery selecting
3961
+ // `<th>` vs `<td>` instead of `title:true` vs nothing.
3962
+ htmlKey: [{ "@value=th": { "@el": "th" } }, { "@absent": { "@el": "td" } }],
3861
3963
  description: "Table cell type (th/td).",
3862
3964
  format: TagFormat.plainText
3863
3965
  },
@@ -3865,6 +3967,9 @@ var CARDSETS = {
3865
3967
  key: ConfigKey.property_tableRowSpan,
3866
3968
  jsonKey: "rowspan",
3867
3969
  exportJsonKey: { rowspan: "$" },
3970
+ // HTML-C2: contribute a `rowspan` attribute onto the enclosing
3971
+ // cell element (`<th>`/`<td>`).
3972
+ htmlKey: { "@el": { "@attr": { rowspan: "$" } } },
3868
3973
  description: "Number of rows the cell spans.",
3869
3974
  format: TagFormat.number
3870
3975
  },
@@ -3872,6 +3977,9 @@ var CARDSETS = {
3872
3977
  key: ConfigKey.property_tableColSpan,
3873
3978
  jsonKey: "colspan",
3874
3979
  exportJsonKey: { colspan: "$" },
3980
+ // HTML-C2: contribute a `colspan` attribute onto the enclosing
3981
+ // cell element (`<th>`/`<td>`).
3982
+ htmlKey: { "@el": { "@attr": { colspan: "$" } } },
3875
3983
  description: "Number of columns the cell spans.",
3876
3984
  format: TagFormat.number
3877
3985
  },
@@ -3879,6 +3987,9 @@ var CARDSETS = {
3879
3987
  key: ConfigKey.property_tableScope,
3880
3988
  jsonKey: "scope",
3881
3989
  exportJsonKey: { scope: "$" },
3990
+ // HTML-C2: contribute a `scope` attribute onto the enclosing
3991
+ // cell element (`<th>`/`<td>`).
3992
+ htmlKey: { "@el": { "@attr": { scope: "$" } } },
3882
3993
  description: "Scope attribute for header cells.",
3883
3994
  format: TagFormat.plainText
3884
3995
  },
@@ -3887,6 +3998,9 @@ var CARDSETS = {
3887
3998
  // PLAN-080: write to the cell's `colwidth` field.
3888
3999
  jsonKey: "colwidth",
3889
4000
  exportJsonKey: { colwidth: "$" },
4001
+ // HTML.md §8 + HTML-C2: contribute a `width` attribute onto the
4002
+ // enclosing cell element (`<th>`/`<td>`).
4003
+ htmlKey: { "@el": { "@attr": { width: "$" } } },
3890
4004
  description: "Width for the column.",
3891
4005
  format: TagFormat.number
3892
4006
  }
@@ -5686,6 +5800,16 @@ var GROUPS = {
5686
5800
  description: "External Id of the translated book",
5687
5801
  format: TagFormat.plainText
5688
5802
  },
5803
+ {
5804
+ key: ConfigKey.property_userFeedbackTranslationUrl,
5805
+ description: "URL to an external feedback form for book translation feedback",
5806
+ format: TagFormat.plainText
5807
+ },
5808
+ {
5809
+ key: ConfigKey.property_userFeedbackContentUrl,
5810
+ description: "URL to an external feedback form for book content feedback",
5811
+ format: TagFormat.plainText
5812
+ },
5689
5813
  {
5690
5814
  key: ConfigKey.property_duration,
5691
5815
  description: "The duration of the book",
@@ -6815,7 +6939,9 @@ var ConfigHydrator = class {
6815
6939
  variantsOfSide,
6816
6940
  _side.jsonKey,
6817
6941
  _side.exportJsonKey,
6818
- Object.prototype.hasOwnProperty.call(_side, "exportJsonKey")
6942
+ Object.prototype.hasOwnProperty.call(_side, "exportJsonKey"),
6943
+ _side.htmlKey,
6944
+ Object.prototype.hasOwnProperty.call(_side, "htmlKey")
6819
6945
  );
6820
6946
  sides.push(sideConfig);
6821
6947
  }
@@ -6825,7 +6951,9 @@ var ConfigHydrator = class {
6825
6951
  _cardSetConfig.exportJsonKey,
6826
6952
  Object.prototype.hasOwnProperty.call(_cardSetConfig, "exportJsonKey"),
6827
6953
  this.hydrateCardSections(_cardSetConfig.sections),
6828
- sides
6954
+ sides,
6955
+ _cardSetConfig.htmlKey,
6956
+ Object.prototype.hasOwnProperty.call(_cardSetConfig, "htmlKey")
6829
6957
  );
6830
6958
  return cardSetConfig;
6831
6959
  }
@@ -6837,10 +6965,14 @@ var ConfigHydrator = class {
6837
6965
  jsonKey: v.jsonKey,
6838
6966
  exportJsonKey: v.exportJsonKey,
6839
6967
  hasExportJsonKey: Object.prototype.hasOwnProperty.call(v, "exportJsonKey"),
6968
+ htmlKey: v.htmlKey,
6969
+ hasHtmlKey: Object.prototype.hasOwnProperty.call(v, "htmlKey"),
6840
6970
  isDefault: v.isDefault,
6841
6971
  sideJsonKey: v.sideJsonKey,
6842
6972
  sideExportJsonKey: v.sideExportJsonKey,
6843
6973
  hasSideExportJsonKey: Object.prototype.hasOwnProperty.call(v, "sideExportJsonKey"),
6974
+ sideHtmlKey: v.sideHtmlKey,
6975
+ hasSideHtmlKey: Object.prototype.hasOwnProperty.call(v, "sideHtmlKey"),
6844
6976
  // PLAN-085: cardinality fields pass through; defaults applied
6845
6977
  // downstream by the config consumer (Rust treats `0` / undefined
6846
6978
  // as unbounded).
@@ -6858,7 +6990,8 @@ var ConfigHydrator = class {
6858
6990
  chain: _chain,
6859
6991
  deprecated,
6860
6992
  jsonKey,
6861
- exportJsonKey
6993
+ exportJsonKey,
6994
+ htmlKey
6862
6995
  } = _tag;
6863
6996
  const configKey = Enum2(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
6864
6997
  if (!configKey) throw new Error(`No tag key found for config key '${configKey}'`);
@@ -6877,6 +7010,8 @@ var ConfigHydrator = class {
6877
7010
  jsonKey,
6878
7011
  exportJsonKey,
6879
7012
  hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
7013
+ htmlKey,
7014
+ hasHtmlKey: Object.prototype.hasOwnProperty.call(_tag, "htmlKey"),
6880
7015
  deprecated
6881
7016
  });
6882
7017
  return {
@@ -6896,7 +7031,8 @@ var ConfigHydrator = class {
6896
7031
  values,
6897
7032
  defaultValue,
6898
7033
  jsonKey,
6899
- exportJsonKey
7034
+ exportJsonKey,
7035
+ htmlKey
6900
7036
  } = _tag;
6901
7037
  const configKey = Enum2(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
6902
7038
  if (!configKey) throw new Error(`No property key found for config key '${configKey}'`);
@@ -6914,6 +7050,8 @@ var ConfigHydrator = class {
6914
7050
  jsonKey,
6915
7051
  exportJsonKey,
6916
7052
  hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
7053
+ htmlKey,
7054
+ hasHtmlKey: Object.prototype.hasOwnProperty.call(_tag, "htmlKey"),
6917
7055
  format,
6918
7056
  values,
6919
7057
  defaultValue,
@@ -6933,7 +7071,8 @@ var ConfigHydrator = class {
6933
7071
  chain: _chain,
6934
7072
  deprecated,
6935
7073
  jsonKey,
6936
- exportJsonKey
7074
+ exportJsonKey,
7075
+ htmlKey
6937
7076
  } = _tag;
6938
7077
  const configKey = Enum2(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
6939
7078
  if (!configKey) throw new Error(`No resource key found for config key '${configKey}'`);
@@ -6951,6 +7090,8 @@ var ConfigHydrator = class {
6951
7090
  jsonKey,
6952
7091
  exportJsonKey,
6953
7092
  hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
7093
+ htmlKey,
7094
+ hasHtmlKey: Object.prototype.hasOwnProperty.call(_tag, "htmlKey"),
6954
7095
  deprecated
6955
7096
  });
6956
7097
  return {
@@ -6989,6 +7130,7 @@ var ConfigHydrator = class {
6989
7130
  repeatCount,
6990
7131
  jsonKey,
6991
7132
  exportJsonKey,
7133
+ htmlKey,
6992
7134
  format
6993
7135
  } = _variant;
6994
7136
  const tags2 = this.hydrateTagsConfig(_tags);
@@ -7000,7 +7142,9 @@ var ConfigHydrator = class {
7000
7142
  jsonKey,
7001
7143
  exportJsonKey,
7002
7144
  Object.prototype.hasOwnProperty.call(_variant, "exportJsonKey"),
7003
- format
7145
+ format,
7146
+ htmlKey,
7147
+ Object.prototype.hasOwnProperty.call(_variant, "htmlKey")
7004
7148
  );
7005
7149
  return cardSetConfig;
7006
7150
  }
@@ -10133,11 +10277,6 @@ var BITS = {
10133
10277
  baseBitType: BitType2._standard,
10134
10278
  description: "Extractor rule bit, used to define extraction rules with reference images and instructions",
10135
10279
  tags: [
10136
- {
10137
- exportJsonKey: { title: "$" },
10138
- key: ConfigKey.tag_title,
10139
- description: "The name of the extraction rule"
10140
- },
10141
10280
  {
10142
10281
  key: ConfigKey.group_resourceBitTags,
10143
10282
  description: "Resource bit tags for extraction rule images"
@@ -10773,7 +10912,9 @@ var BITS = {
10773
10912
  {
10774
10913
  key: ConfigKey.property_caption,
10775
10914
  description: "Caption for the table image, used to provide a description for the image",
10776
- format: TagFormat.bitmarkText
10915
+ format: TagFormat.bitmarkText,
10916
+ // HTML-10 / HTML-C2: render as the table's `<caption>` (see table bit).
10917
+ htmlKey: { "@el": "caption", "@children": "$" }
10777
10918
  },
10778
10919
  {
10779
10920
  key: ConfigKey.group_backgroundWallpaper,
@@ -10816,6 +10957,26 @@ var BITS = {
10816
10957
  baseBitType: BitType2.tableImage,
10817
10958
  description: "Standard non-normative remark table image bit, used to create non-normative remark images in tables in articles or books"
10818
10959
  },
10960
+ [BitType2.standardTableExtendedImageNormative]: {
10961
+ since: "1.16.0",
10962
+ baseBitType: BitType2.tableExtendedImage,
10963
+ description: "Standard normative extended table image bit, used to create normative extended images in tables in articles or books"
10964
+ },
10965
+ [BitType2.standardTableExtendedImageNonNormative]: {
10966
+ since: "1.16.0",
10967
+ baseBitType: BitType2.tableExtendedImage,
10968
+ description: "Standard non-normative extended table image bit, used to create non-normative extended images in tables in articles or books"
10969
+ },
10970
+ [BitType2.standardRemarkTableExtendedImageNormative]: {
10971
+ since: "1.17.0",
10972
+ baseBitType: BitType2.tableExtendedImage,
10973
+ description: "Standard normative remark extended table image bit, used to create normative remark extended images in tables in articles or books"
10974
+ },
10975
+ [BitType2.standardRemarkTableExtendedImageNonNormative]: {
10976
+ since: "1.17.0",
10977
+ baseBitType: BitType2.tableExtendedImage,
10978
+ description: "Standard non-normative remark extended table image bit, used to create non-normative remark extended images in tables in articles or books"
10979
+ },
10819
10980
  [BitType2.smartStandardTableImageNormative]: {
10820
10981
  since: "1.28.0",
10821
10982
  baseBitType: BitType2.standardTableImageNormative,
@@ -10836,6 +10997,26 @@ var BITS = {
10836
10997
  baseBitType: BitType2.standardRemarkTableImageNonNormative,
10837
10998
  description: "Smart standard non-normative remark table image bit, used to create smart standard non-normative remark images in tables in articles or books"
10838
10999
  },
11000
+ [BitType2.smartStandardTableExtendedImageNormative]: {
11001
+ since: "1.28.0",
11002
+ baseBitType: BitType2.standardTableExtendedImageNormative,
11003
+ description: "Smart standard normative extended table image bit, used to create smart standard normative extended images in tables in articles or books"
11004
+ },
11005
+ [BitType2.smartStandardTableExtendedImageNonNormative]: {
11006
+ since: "1.28.0",
11007
+ baseBitType: BitType2.standardTableExtendedImageNonNormative,
11008
+ description: "Smart standard non-normative extended table image bit, used to create smart standard non-normative extended images in tables in articles or books"
11009
+ },
11010
+ [BitType2.smartStandardRemarkTableExtendedImageNormative]: {
11011
+ since: "1.28.0",
11012
+ baseBitType: BitType2.standardRemarkTableExtendedImageNormative,
11013
+ description: "Smart standard normative remark extended table image bit, used to create smart standard normative remark extended images in tables in articles or books"
11014
+ },
11015
+ [BitType2.smartStandardRemarkTableExtendedImageNonNormative]: {
11016
+ since: "1.28.0",
11017
+ baseBitType: BitType2.standardRemarkTableExtendedImageNonNormative,
11018
+ description: "Smart standard non-normative remark extended table image bit, used to create smart standard non-normative remark extended images in tables in articles or books"
11019
+ },
10839
11020
  [BitType2.smartStandardTableImageNormativeCollapsible]: {
10840
11021
  since: "1.28.0",
10841
11022
  baseBitType: BitType2.smartStandardTableImageNormative,
@@ -10856,6 +11037,26 @@ var BITS = {
10856
11037
  baseBitType: BitType2.smartStandardRemarkTableImageNonNormative,
10857
11038
  description: "Collapsible smart standard non-normative remark table image bit, used to create collapsible smart standard non-normative remark images in tables in articles or books"
10858
11039
  },
11040
+ [BitType2.smartStandardTableExtendedImageNormativeCollapsible]: {
11041
+ since: "1.28.0",
11042
+ baseBitType: BitType2.smartStandardTableExtendedImageNormative,
11043
+ description: "Collapsible smart standard normative extended table image bit, used to create collapsible smart standard normative extended images in tables in articles or books"
11044
+ },
11045
+ [BitType2.smartStandardTableExtendedImageNonNormativeCollapsible]: {
11046
+ since: "1.28.0",
11047
+ baseBitType: BitType2.smartStandardTableExtendedImageNonNormative,
11048
+ description: "Collapsible smart standard non-normative extended table image bit, used to create collapsible smart standard non-normative extended images in tables in articles or books"
11049
+ },
11050
+ [BitType2.smartStandardRemarkTableExtendedImageNormativeCollapsible]: {
11051
+ since: "1.28.0",
11052
+ baseBitType: BitType2.smartStandardRemarkTableExtendedImageNormative,
11053
+ description: "Collapsible smart standard normative remark extended table image bit, used to create collapsible smart standard normative remark extended images in tables in articles or books"
11054
+ },
11055
+ [BitType2.smartStandardRemarkTableExtendedImageNonNormativeCollapsible]: {
11056
+ since: "1.28.0",
11057
+ baseBitType: BitType2.smartStandardRemarkTableExtendedImageNonNormative,
11058
+ description: "Collapsible smart standard non-normative remark extended table image bit, used to create collapsible smart standard non-normative remark extended images in tables in articles or books"
11059
+ },
10859
11060
  [BitType2.imageLink]: {
10860
11061
  since: "1.3.0",
10861
11062
  baseBitType: BitType2._standard,
@@ -12404,7 +12605,12 @@ var BITS = {
12404
12605
  {
12405
12606
  key: ConfigKey.property_caption,
12406
12607
  description: "Caption for the table, used to define the title of the table",
12407
- format: TagFormat.bitmarkText
12608
+ format: TagFormat.bitmarkText,
12609
+ // HTML-10 / HTML-C2: a bit-level caption renders as the table's
12610
+ // `<caption>` — placed inside the idiomatic `<table>` container as
12611
+ // its first child. Outside a table context it falls back to the
12612
+ // residual carrier.
12613
+ htmlKey: { "@el": "caption", "@children": "$" }
12408
12614
  },
12409
12615
  {
12410
12616
  key: ConfigKey.property_tableFixedHeader,
@@ -12489,7 +12695,9 @@ var BITS = {
12489
12695
  {
12490
12696
  key: ConfigKey.property_caption,
12491
12697
  description: "Caption for the table image, used to provide a description for the image",
12492
- format: TagFormat.bitmarkText
12698
+ format: TagFormat.bitmarkText,
12699
+ // HTML-10 / HTML-C2: render as the table's `<caption>` (see table bit).
12700
+ htmlKey: { "@el": "caption", "@children": "$" }
12493
12701
  },
12494
12702
  {
12495
12703
  key: ConfigKey.group_backgroundWallpaper,
@@ -12532,6 +12740,26 @@ var BITS = {
12532
12740
  baseBitType: BitType2.table,
12533
12741
  description: "Standard non-normative remark table bit, used to create standard non-normative remark tables in articles or books"
12534
12742
  },
12743
+ [BitType2.standardTableExtendedNormative]: {
12744
+ since: "1.16.0",
12745
+ baseBitType: BitType2.tableExtended,
12746
+ description: "Standard normative extended table bit, used to create standard normative extended tables in articles or books"
12747
+ },
12748
+ [BitType2.standardTableExtendedNonNormative]: {
12749
+ since: "1.16.0",
12750
+ baseBitType: BitType2.tableExtended,
12751
+ description: "Standard non-normative extended table bit, used to create standard non-normative extended tables in articles or books"
12752
+ },
12753
+ [BitType2.standardRemarkTableExtendedNormative]: {
12754
+ since: "1.17.0",
12755
+ baseBitType: BitType2.tableExtended,
12756
+ description: "Standard normative remark extended table bit, used to create standard normative remark extended tables in articles or books"
12757
+ },
12758
+ [BitType2.standardRemarkTableExtendedNonNormative]: {
12759
+ since: "1.17.0",
12760
+ baseBitType: BitType2.tableExtended,
12761
+ description: "Standard non-normative remark extended table bit, used to create standard non-normative remark extended tables in articles or books"
12762
+ },
12535
12763
  [BitType2.smartStandardTableNormative]: {
12536
12764
  since: "1.28.0",
12537
12765
  baseBitType: BitType2.standardTableNormative,
@@ -12552,6 +12780,26 @@ var BITS = {
12552
12780
  baseBitType: BitType2.standardRemarkTableNonNormative,
12553
12781
  description: "Smart standard non-normative remark table bit, used to create smart standard non-normative remark tables in articles or books"
12554
12782
  },
12783
+ [BitType2.smartStandardTableExtendedNormative]: {
12784
+ since: "1.28.0",
12785
+ baseBitType: BitType2.standardTableExtendedNormative,
12786
+ description: "Smart standard normative extended table bit, used to create smart standard normative extended tables in articles or books"
12787
+ },
12788
+ [BitType2.smartStandardTableExtendedNonNormative]: {
12789
+ since: "1.28.0",
12790
+ baseBitType: BitType2.standardTableExtendedNonNormative,
12791
+ description: "Smart standard non-normative extended table bit, used to create smart standard non-normative extended tables in articles or books"
12792
+ },
12793
+ [BitType2.smartStandardRemarkTableExtendedNormative]: {
12794
+ since: "1.28.0",
12795
+ baseBitType: BitType2.standardRemarkTableExtendedNormative,
12796
+ description: "Smart standard normative remark extended table bit, used to create smart standard normative remark extended tables in articles or books"
12797
+ },
12798
+ [BitType2.smartStandardRemarkTableExtendedNonNormative]: {
12799
+ since: "1.28.0",
12800
+ baseBitType: BitType2.standardRemarkTableExtendedNonNormative,
12801
+ description: "Smart standard non-normative remark extended table bit, used to create smart standard non-normative remark extended tables in articles or books"
12802
+ },
12555
12803
  [BitType2.smartStandardTableNormativeCollapsible]: {
12556
12804
  since: "1.28.0",
12557
12805
  baseBitType: BitType2.smartStandardTableNormative,
@@ -12572,6 +12820,26 @@ var BITS = {
12572
12820
  baseBitType: BitType2.smartStandardRemarkTableNonNormative,
12573
12821
  description: "Collapsible smart standard non-normative remark table bit, used to create collapsible smart standard non-normative remark tables in articles or books"
12574
12822
  },
12823
+ [BitType2.smartStandardTableExtendedNormativeCollapsible]: {
12824
+ since: "1.28.0",
12825
+ baseBitType: BitType2.smartStandardTableExtendedNormative,
12826
+ description: "Collapsible smart standard normative extended table bit, used to create collapsible smart standard normative extended tables in articles or books"
12827
+ },
12828
+ [BitType2.smartStandardTableExtendedNonNormativeCollapsible]: {
12829
+ since: "1.28.0",
12830
+ baseBitType: BitType2.smartStandardTableExtendedNonNormative,
12831
+ description: "Collapsible smart standard non-normative extended table bit, used to create collapsible smart standard non-normative extended tables in articles or books"
12832
+ },
12833
+ [BitType2.smartStandardRemarkTableExtendedNormativeCollapsible]: {
12834
+ since: "1.28.0",
12835
+ baseBitType: BitType2.smartStandardRemarkTableExtendedNormative,
12836
+ description: "Collapsible smart standard normative remark extended table bit, used to create collapsible smart standard normative remark extended tables in articles or books"
12837
+ },
12838
+ [BitType2.smartStandardRemarkTableExtendedNonNormativeCollapsible]: {
12839
+ since: "1.28.0",
12840
+ baseBitType: BitType2.smartStandardRemarkTableExtendedNonNormative,
12841
+ description: "Collapsible smart standard non-normative remark extended table bit, used to create collapsible smart standard non-normative remark extended tables in articles or books"
12842
+ },
12575
12843
  [BitType2.parameters]: {
12576
12844
  since: "1.18.0",
12577
12845
  baseBitType: BitType2.table,
@@ -13513,6 +13781,8 @@ var Config = class {
13513
13781
  jsonKey: tag.jsonKey,
13514
13782
  exportJsonKey: tag.exportJsonKey,
13515
13783
  hasExportJsonKey: tag.hasExportJsonKey,
13784
+ htmlKey: tag.htmlKey,
13785
+ hasHtmlKey: tag.hasHtmlKey,
13516
13786
  deprecated: tag.deprecated
13517
13787
  });
13518
13788
  finalResourceTags[k] = newTag;
@@ -13617,7 +13887,7 @@ var instance2 = new Config();
13617
13887
  // src/generated/package_info.ts
13618
13888
  var PACKAGE_INFO = {
13619
13889
  "name": "@gmb/bitmark-parser-generator",
13620
- "version": "5.26.0",
13890
+ "version": "5.28.0",
13621
13891
  "author": "Get More Brain Ltd",
13622
13892
  "license": "ISC",
13623
13893
  "description": "A bitmark parser and generator using Peggy.js"
@@ -14507,6 +14777,10 @@ var NodeType = {
14507
14777
  relatedBookValue: "relatedBookValue",
14508
14778
  translationOfBook: "translationOfBook",
14509
14779
  translationOfBookValue: "translationOfBookValue",
14780
+ userFeedbackTranslationUrl: "userFeedbackTranslationUrl",
14781
+ userFeedbackTranslationUrlValue: "userFeedbackTranslationUrlValue",
14782
+ userFeedbackContentUrl: "userFeedbackContentUrl",
14783
+ userFeedbackContentUrlValue: "userFeedbackContentUrlValue",
14510
14784
  releaseDate: "releaseDate",
14511
14785
  releaseDateValue: "releaseDateValue",
14512
14786
  releaseKind: "releaseKind",
@@ -27716,6 +27990,18 @@ var Builder = class extends BaseBuilder {
27716
27990
  data.translationOfBook,
27717
27991
  options
27718
27992
  ),
27993
+ userFeedbackTranslationUrl: this.toAstProperty(
27994
+ bitType,
27995
+ ConfigKey.property_userFeedbackTranslationUrl,
27996
+ data.userFeedbackTranslationUrl,
27997
+ options
27998
+ ),
27999
+ userFeedbackContentUrl: this.toAstProperty(
28000
+ bitType,
28001
+ ConfigKey.property_userFeedbackContentUrl,
28002
+ data.userFeedbackContentUrl,
28003
+ options
28004
+ ),
27719
28005
  author: this.toAstProperty(bitType, ConfigKey.property_author, data.author, options),
27720
28006
  subject: this.toAstProperty(bitType, ConfigKey.property_subject, data.subject, options),
27721
28007
  date: this.toAstProperty(bitType, ConfigKey.property_date, data.date, options),
@@ -31507,7 +31793,8 @@ var BitmarkGenerator = class extends AstWalkerGenerator {
31507
31793
  this.writeNL();
31508
31794
  }
31509
31795
  const content = cell.content ?? instance3.EMPTY_STRING;
31510
- this.writeTextOrValue(content, this.textFormat, TextLocation2.body);
31796
+ const options = this.options.noBreakscaping ? { noBreakscaping: true } : void 0;
31797
+ this.writeTextOrValue(content, this.textFormat, TextLocation2.body, options);
31511
31798
  }
31512
31799
  writeTableCellProperty(name, value) {
31513
31800
  this.writeOPA();
@@ -32973,6 +33260,278 @@ var BitmarkStringGenerator = class {
32973
33260
  }
32974
33261
  };
32975
33262
 
33263
+ // src/generator/html/HtmlTableGenerator.ts
33264
+ var MARK_TO_TAG = {
33265
+ bold: "b",
33266
+ italic: "i",
33267
+ superscript: "sup",
33268
+ subscript: "sub",
33269
+ strike: "s",
33270
+ del: "del",
33271
+ ins: "ins",
33272
+ underline: "u",
33273
+ highlight: "mark",
33274
+ code: "code"
33275
+ };
33276
+ var INLINE_IMAGE_RE = /==([^=]*(?:=(?!=)[^=]*)*)==\|imageInline:([^|\s]+)((?:\|(?:@?[A-Za-z][A-Za-z0-9_-]*:[^|\s]+|#[^|\s]*))*)\|?/g;
33277
+ var MAX_IMAGE_DIMENSION = 9999;
33278
+ var HtmlTableGenerator = class {
33279
+ constructor() {
33280
+ __publicField(this, "indentUnit", " ");
33281
+ }
33282
+ /**
33283
+ * Generate HTML table fragments from a string or JSON value.
33284
+ * @returns the concatenated `<table>` fragments, blank-line separated (empty string if none).
33285
+ */
33286
+ generate(input) {
33287
+ let data = input;
33288
+ if (typeof data === "string") {
33289
+ try {
33290
+ data = JSON.parse(data);
33291
+ } catch {
33292
+ return "";
33293
+ }
33294
+ }
33295
+ const bits = this.collectBits(data);
33296
+ const fragments = [];
33297
+ for (const bit of bits) {
33298
+ const html = this.renderTableBit(bit);
33299
+ if (html) fragments.push(html);
33300
+ }
33301
+ return fragments.join("\n\n");
33302
+ }
33303
+ // --- bit collection -------------------------------------------------------
33304
+ collectBits(data) {
33305
+ const out = [];
33306
+ const visit = (value) => {
33307
+ if (value == null || typeof value !== "object") return;
33308
+ if (Array.isArray(value)) {
33309
+ value.forEach(visit);
33310
+ return;
33311
+ }
33312
+ const obj = value;
33313
+ if ("bit" in obj && obj.bit && typeof obj.bit === "object") {
33314
+ out.push(obj.bit);
33315
+ } else if ("type" in obj) {
33316
+ out.push(obj);
33317
+ }
33318
+ };
33319
+ visit(data);
33320
+ return out;
33321
+ }
33322
+ // --- table rendering ------------------------------------------------------
33323
+ renderTableBit(bit) {
33324
+ const table = bit.table;
33325
+ if (!table) return "";
33326
+ if (bit.type !== "table" && bit.type !== "table-extended") return "";
33327
+ const extended = this.toExtended(table);
33328
+ const lines = [];
33329
+ lines.push("<table>");
33330
+ if (bit.caption != null) {
33331
+ const caption = this.cellContentToHtml(this.asTextAst(bit.caption));
33332
+ if (caption) lines.push(`${this.indentUnit}<caption>${caption}</caption>`);
33333
+ }
33334
+ this.renderSection(lines, "thead", extended.header, "header");
33335
+ this.renderSection(lines, "tbody", extended.body, "body");
33336
+ this.renderSection(lines, "tfoot", extended.footer, "footer");
33337
+ lines.push("</table>");
33338
+ return lines.join("\n");
33339
+ }
33340
+ toExtended(table) {
33341
+ const t = table;
33342
+ if (t.header || t.body || t.footer) return table;
33343
+ return convertBasicToExtendedTableFormat(table);
33344
+ }
33345
+ renderSection(lines, tag, section, key) {
33346
+ if (!section || !section.rows || section.rows.length === 0) return;
33347
+ lines.push(`${this.indentUnit}<${tag}>`);
33348
+ for (const row of section.rows) {
33349
+ lines.push(`${this.indentUnit.repeat(2)}<tr>`);
33350
+ for (const cell of row.cells ?? []) {
33351
+ lines.push(`${this.indentUnit.repeat(3)}${this.renderCell(cell, key)}`);
33352
+ }
33353
+ lines.push(`${this.indentUnit.repeat(2)}</tr>`);
33354
+ }
33355
+ lines.push(`${this.indentUnit}</${tag}>`);
33356
+ }
33357
+ renderCell(cell, _key) {
33358
+ const tag = cell.title === true ? "th" : "td";
33359
+ const attrs = [];
33360
+ if (cell.rowspan && cell.rowspan > 1) attrs.push(`rowspan="${cell.rowspan}"`);
33361
+ if (cell.colspan && cell.colspan > 1) attrs.push(`colspan="${cell.colspan}"`);
33362
+ if (cell.scope) attrs.push(`scope="${cell.scope}"`);
33363
+ if (cell.colwidth && cell.colwidth > 0) attrs.push(`width="${cell.colwidth}"`);
33364
+ const open = attrs.length > 0 ? `<${tag} ${attrs.join(" ")}>` : `<${tag}>`;
33365
+ return `${open}${this.cellContentToHtml(this.asTextAst(cell.content))}</${tag}>`;
33366
+ }
33367
+ // --- cell content (TextAst -> HTML) ---------------------------------------
33368
+ asTextAst(content) {
33369
+ if (content == null) return [];
33370
+ if (typeof content === "string") return [{ type: "text", text: content }];
33371
+ return content;
33372
+ }
33373
+ cellContentToHtml(blocks) {
33374
+ if (blocks.length === 0) return "";
33375
+ if (blocks.length === 1 && blocks[0].type === "paragraph") {
33376
+ return this.inlineToHtml(blocks[0].content ?? []);
33377
+ }
33378
+ return blocks.map((b) => this.blockToHtml(b)).join("");
33379
+ }
33380
+ blockToHtml(node) {
33381
+ switch (node.type) {
33382
+ case "paragraph":
33383
+ return `<p>${this.inlineToHtml(node.content ?? [])}</p>`;
33384
+ case "bulletList":
33385
+ case "noBulletList":
33386
+ case "orderedList":
33387
+ case "orderedListRoman":
33388
+ case "orderedListRomanLower":
33389
+ case "letteredList":
33390
+ case "letteredListLower":
33391
+ case "taskList":
33392
+ return this.listToHtml(node);
33393
+ case "image":
33394
+ case "imageInline":
33395
+ return this.imageToHtml(node);
33396
+ case "latex":
33397
+ return this.latexToHtml(node);
33398
+ default:
33399
+ return this.inlineToHtml([node]);
33400
+ }
33401
+ }
33402
+ inlineToHtml(nodes) {
33403
+ return nodes.map((n) => this.inlineNodeToHtml(n)).join("");
33404
+ }
33405
+ inlineNodeToHtml(node) {
33406
+ if (node.type === "hardBreak") return "<br>";
33407
+ if (node.type === "image" || node.type === "imageInline") return this.imageToHtml(node);
33408
+ if (node.type === "latex") return this.latexToHtml(node);
33409
+ if (node.type === "text") {
33410
+ return this.wrapMarks(this.textToHtml(node.text ?? ""), node.marks);
33411
+ }
33412
+ if (node.content) return this.inlineToHtml(node.content);
33413
+ return this.escapeText(node.text ?? "");
33414
+ }
33415
+ wrapMarks(text, marks) {
33416
+ if (!marks || marks.length === 0) return text;
33417
+ let open = "";
33418
+ let close = "";
33419
+ for (const mark of marks) {
33420
+ if (mark.type === "link") {
33421
+ const href = mark.attrs?.href ?? "";
33422
+ open += `<a href="${this.escapeAttr(href)}">`;
33423
+ close = `</a>${close}`;
33424
+ } else {
33425
+ const tag = MARK_TO_TAG[mark.type];
33426
+ if (tag) {
33427
+ open += `<${tag}>`;
33428
+ close = `</${tag}>${close}`;
33429
+ }
33430
+ }
33431
+ }
33432
+ return `${open}${text}${close}`;
33433
+ }
33434
+ // --- lists ----------------------------------------------------------------
33435
+ listToHtml(node) {
33436
+ const { tag, attrs } = this.listTag(node);
33437
+ const items = (node.content ?? []).map((item) => this.listItemToHtml(item, node.type === "taskList")).join("");
33438
+ return `<${tag}${attrs}>${items}</${tag}>`;
33439
+ }
33440
+ listTag(node) {
33441
+ const start = node.attrs?.start;
33442
+ const startAttr = typeof start === "number" && start !== 1 ? ` start="${start}"` : "";
33443
+ switch (node.type) {
33444
+ case "orderedList":
33445
+ return { tag: "ol", attrs: startAttr };
33446
+ case "orderedListRoman":
33447
+ return { tag: "ol", attrs: ` type="I"${startAttr}` };
33448
+ case "orderedListRomanLower":
33449
+ return { tag: "ol", attrs: ` type="i"${startAttr}` };
33450
+ case "letteredList":
33451
+ return { tag: "ol", attrs: ` type="A"${startAttr}` };
33452
+ case "letteredListLower":
33453
+ return { tag: "ol", attrs: ` type="a"${startAttr}` };
33454
+ case "noBulletList":
33455
+ return { tag: "ul", attrs: ' style="list-style:none"' };
33456
+ case "taskList":
33457
+ case "bulletList":
33458
+ default:
33459
+ return { tag: "ul", attrs: "" };
33460
+ }
33461
+ }
33462
+ listItemToHtml(item, task) {
33463
+ const inner = (item.content ?? []).map((b) => {
33464
+ if (b.type === "paragraph") return this.inlineToHtml(b.content ?? []);
33465
+ return this.blockToHtml(b);
33466
+ }).join("");
33467
+ if (task) {
33468
+ const checked = item.attrs?.checked ? " checked" : "";
33469
+ return `<li><input type="checkbox"${checked}>${inner}</li>`;
33470
+ }
33471
+ return `<li>${inner}</li>`;
33472
+ }
33473
+ // --- images ---------------------------------------------------------------
33474
+ imageToHtml(node) {
33475
+ const attrs = node.attrs ?? {};
33476
+ const parts = [];
33477
+ const src = attrs.src;
33478
+ parts.push(`src="${this.escapeAttr(typeof src === "string" ? src : "")}"`);
33479
+ if (typeof attrs.alt === "string") parts.push(`alt="${this.escapeAttr(attrs.alt)}"`);
33480
+ if (typeof attrs.title === "string") parts.push(`title="${this.escapeAttr(attrs.title)}"`);
33481
+ if (attrs.width != null) parts.push(`width="${attrs.width}"`);
33482
+ if (attrs.height != null) parts.push(`height="${attrs.height}"`);
33483
+ if (typeof attrs.class === "string" && attrs.class) {
33484
+ parts.push(`class="${this.escapeAttr(attrs.class)}"`);
33485
+ }
33486
+ return `<img ${parts.join(" ")}>`;
33487
+ }
33488
+ textToHtml(text) {
33489
+ let html = "";
33490
+ let lastIndex = 0;
33491
+ for (const match of text.matchAll(INLINE_IMAGE_RE)) {
33492
+ const index = match.index ?? 0;
33493
+ html += this.escapeText(text.slice(lastIndex, index));
33494
+ html += this.inlineImageTokenToHtml(match);
33495
+ lastIndex = index + match[0].length;
33496
+ }
33497
+ html += this.escapeText(text.slice(lastIndex));
33498
+ return html;
33499
+ }
33500
+ inlineImageTokenToHtml(match) {
33501
+ const attrs = {
33502
+ alt: match[1],
33503
+ src: match[2]
33504
+ };
33505
+ const rawAttrs = match[3] ?? "";
33506
+ for (const attr of rawAttrs.split("|")) {
33507
+ if (!attr || attr.startsWith("#")) continue;
33508
+ const colon = attr.indexOf(":");
33509
+ if (colon < 1) continue;
33510
+ const key = attr.slice(0, colon).replace(/^@/, "");
33511
+ const value = attr.slice(colon + 1);
33512
+ if (key === "width" || key === "height") {
33513
+ const n = Number.parseInt(value, 10);
33514
+ if (!Number.isNaN(n) && n > 0 && n <= MAX_IMAGE_DIMENSION) attrs[key] = n;
33515
+ } else if (key === "class" || key === "title") {
33516
+ attrs[key] = value;
33517
+ }
33518
+ }
33519
+ return this.imageToHtml({ type: "imageInline", attrs });
33520
+ }
33521
+ // --- formulas -------------------------------------------------------------
33522
+ latexToHtml(node) {
33523
+ const formula = node.attrs?.formula ?? "";
33524
+ return `<math alttext="${this.escapeAttr(formula)}"></math>`;
33525
+ }
33526
+ // --- escaping -------------------------------------------------------------
33527
+ escapeText(text) {
33528
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
33529
+ }
33530
+ escapeAttr(text) {
33531
+ return this.escapeText(text).replace(/"/g, "&quot;");
33532
+ }
33533
+ };
33534
+
32976
33535
  // src/generator/json/JsonGenerator.ts
32977
33536
  import { Enum as Enum9 } from "@ncoderz/superenum";
32978
33537
  var MOVE_BODY_RECURSION_LIMIT = 5e3;
@@ -33275,6 +33834,7 @@ var JsonGenerator = class extends AstWalkerGenerator {
33275
33834
  this.addProperty(this.bitJson, k, values, { array: true });
33276
33835
  }
33277
33836
  }
33837
+ return false;
33278
33838
  }
33279
33839
  // bitmarkAst -> bits -> bitsValue -> cardNode -> cardBits -> cardBitsValue
33280
33840
  enter_cardBitsValue(node, route) {
@@ -37900,6 +38460,8 @@ function propertyContentProcessor(context, contentDepth, tagsConfig, content, ta
37900
38460
  jsonKey: void 0,
37901
38461
  exportJsonKey: void 0,
37902
38462
  hasExportJsonKey: false,
38463
+ htmlKey: void 0,
38464
+ hasHtmlKey: false,
37903
38465
  format: TagFormat.bitmarkText,
37904
38466
  values: void 0,
37905
38467
  defaultValue: void 0,
@@ -42279,6 +42841,539 @@ var BitmarkParser = class {
42279
42841
  }
42280
42842
  };
42281
42843
 
42844
+ // src/parser/html/HtmlDom.ts
42845
+ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
42846
+ "area",
42847
+ "base",
42848
+ "br",
42849
+ "col",
42850
+ "embed",
42851
+ "hr",
42852
+ "img",
42853
+ "input",
42854
+ "link",
42855
+ "meta",
42856
+ "param",
42857
+ "source",
42858
+ "track",
42859
+ "wbr"
42860
+ ]);
42861
+ var IMPLIED_CLOSE = {
42862
+ li: /* @__PURE__ */ new Set(["li"]),
42863
+ td: /* @__PURE__ */ new Set(["td", "th"]),
42864
+ th: /* @__PURE__ */ new Set(["td", "th"]),
42865
+ tr: /* @__PURE__ */ new Set(["td", "th", "tr"]),
42866
+ thead: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
42867
+ tbody: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
42868
+ tfoot: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
42869
+ p: /* @__PURE__ */ new Set(["p"]),
42870
+ option: /* @__PURE__ */ new Set(["option"])
42871
+ };
42872
+ var TAG_RE = /<(\/)?([a-zA-Z][a-zA-Z0-9:-]*)((?:\s+(?:"[^"]*"|'[^']*'|[^<>"'])*)?)(\/)?>/g;
42873
+ var ATTR_RE = /([a-zA-Z_:][a-zA-Z0-9:._-]*)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s"'>]+))?/g;
42874
+ function parseAttrs(raw) {
42875
+ const attrs = {};
42876
+ if (!raw) return attrs;
42877
+ ATTR_RE.lastIndex = 0;
42878
+ let m;
42879
+ while ((m = ATTR_RE.exec(raw)) !== null) {
42880
+ const name = m[1].toLowerCase();
42881
+ let value = m[2] ?? "";
42882
+ if (value.length >= 2 && (value[0] === '"' || value[0] === "'")) {
42883
+ value = value.slice(1, -1);
42884
+ }
42885
+ attrs[name] = value;
42886
+ }
42887
+ return attrs;
42888
+ }
42889
+ function stripNonContent(html) {
42890
+ 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, "");
42891
+ }
42892
+ function tokenize(html) {
42893
+ const tokens = [];
42894
+ const clean = stripNonContent(html);
42895
+ TAG_RE.lastIndex = 0;
42896
+ let lastIndex = 0;
42897
+ let m;
42898
+ while ((m = TAG_RE.exec(clean)) !== null) {
42899
+ if (m.index > lastIndex) {
42900
+ tokens.push({ kind: "text", text: clean.slice(lastIndex, m.index) });
42901
+ }
42902
+ lastIndex = TAG_RE.lastIndex;
42903
+ const isClose = m[1] === "/";
42904
+ const name = m[2].toLowerCase();
42905
+ if (isClose) {
42906
+ tokens.push({ kind: "close", name });
42907
+ } else {
42908
+ tokens.push({
42909
+ kind: "open",
42910
+ name,
42911
+ attrs: parseAttrs(m[3]),
42912
+ selfClose: m[4] === "/"
42913
+ });
42914
+ }
42915
+ }
42916
+ if (lastIndex < clean.length) {
42917
+ tokens.push({ kind: "text", text: clean.slice(lastIndex) });
42918
+ }
42919
+ return tokens;
42920
+ }
42921
+ function parseHtml(html) {
42922
+ const root = { type: "element", name: "#root", attrs: {}, children: [] };
42923
+ const stack = [root];
42924
+ const top = () => stack[stack.length - 1];
42925
+ for (const token of tokenize(html)) {
42926
+ if (token.kind === "text") {
42927
+ if (token.text) top().children.push({ type: "text", value: token.text });
42928
+ continue;
42929
+ }
42930
+ if (token.kind === "open") {
42931
+ const name = token.name;
42932
+ const closes = IMPLIED_CLOSE[name];
42933
+ if (closes) {
42934
+ while (stack.length > 1 && closes.has(top().name)) stack.pop();
42935
+ }
42936
+ const el = {
42937
+ type: "element",
42938
+ name,
42939
+ attrs: token.attrs ?? {},
42940
+ children: []
42941
+ };
42942
+ top().children.push(el);
42943
+ if (!token.selfClose && !VOID_ELEMENTS.has(name)) {
42944
+ stack.push(el);
42945
+ }
42946
+ continue;
42947
+ }
42948
+ for (let i = stack.length - 1; i > 0; i--) {
42949
+ if (stack[i].name === token.name) {
42950
+ stack.length = i;
42951
+ break;
42952
+ }
42953
+ }
42954
+ }
42955
+ return root.children;
42956
+ }
42957
+ function childElements(el, names) {
42958
+ return el.children.filter((c) => c.type === "element" && names.has(c.name));
42959
+ }
42960
+
42961
+ // src/parser/html/HtmlTableParser.ts
42962
+ var MARK_TAGS = {
42963
+ b: "bold",
42964
+ strong: "bold",
42965
+ i: "italic",
42966
+ em: "italic",
42967
+ sup: "superscript",
42968
+ sub: "subscript",
42969
+ s: "strike",
42970
+ strike: "strike",
42971
+ del: "del",
42972
+ ins: "ins",
42973
+ u: "underline",
42974
+ mark: "highlight",
42975
+ code: "code"
42976
+ };
42977
+ var SECTION_TAGS = /* @__PURE__ */ new Set(["thead", "tbody", "tfoot"]);
42978
+ var ROW_TAGS = /* @__PURE__ */ new Set(["tr"]);
42979
+ var CELL_TAGS = /* @__PURE__ */ new Set(["td", "th"]);
42980
+ var LI_TAGS = /* @__PURE__ */ new Set(["li"]);
42981
+ var VALID_SCOPES = /* @__PURE__ */ new Set(["row", "col", "rowgroup", "colgroup"]);
42982
+ var NAMED_ENTITIES = {
42983
+ amp: "&",
42984
+ lt: "<",
42985
+ gt: ">",
42986
+ quot: '"',
42987
+ apos: "'",
42988
+ nbsp: "\xA0"
42989
+ };
42990
+ function decodeEntities(text) {
42991
+ return text.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z][a-zA-Z0-9]*);/g, (whole, body) => {
42992
+ if (body[0] === "#") {
42993
+ const code = body[1] === "x" || body[1] === "X" ? Number.parseInt(body.slice(2), 16) : Number.parseInt(body.slice(1), 10);
42994
+ if (Number.isFinite(code) && code >= 0 && code <= 1114111) {
42995
+ try {
42996
+ return String.fromCodePoint(code);
42997
+ } catch {
42998
+ return whole;
42999
+ }
43000
+ }
43001
+ return whole;
43002
+ }
43003
+ return NAMED_ENTITIES[body] ?? whole;
43004
+ });
43005
+ }
43006
+ function intAttr(value) {
43007
+ if (value == null) return void 0;
43008
+ const n = Number.parseInt(value, 10);
43009
+ return Number.isInteger(n) ? n : void 0;
43010
+ }
43011
+ function isElement(node) {
43012
+ return node.type === "element";
43013
+ }
43014
+ var HtmlTableParser = class {
43015
+ constructor() {
43016
+ __publicField(this, "keepUnknownTags", false);
43017
+ }
43018
+ /**
43019
+ * Parse an HTML string and return one table bit per top-level `<table>`.
43020
+ */
43021
+ parse(html, options) {
43022
+ this.keepUnknownTags = options?.keepUnknownTags ?? false;
43023
+ const tableFormat = options?.tableFormat ?? "table-extended";
43024
+ const onWarning = options?.onWarning;
43025
+ const tables = this.collectTopLevelTables(parseHtml(html));
43026
+ const bits = [];
43027
+ for (const table of tables) {
43028
+ const bit = this.tableToBit(table, tableFormat, onWarning);
43029
+ if (bit) bits.push(bit);
43030
+ }
43031
+ return bits;
43032
+ }
43033
+ // --- table extraction -----------------------------------------------------
43034
+ /** Collect every `<table>` element, NOT descending into nested tables. */
43035
+ collectTopLevelTables(nodes) {
43036
+ const tables = [];
43037
+ const visit = (node) => {
43038
+ if (!isElement(node)) return;
43039
+ if (node.name === "table") {
43040
+ tables.push(node);
43041
+ return;
43042
+ }
43043
+ node.children.forEach(visit);
43044
+ };
43045
+ nodes.forEach(visit);
43046
+ return tables;
43047
+ }
43048
+ tableToBit(table, tableFormat, onWarning) {
43049
+ const header = [];
43050
+ const body = [];
43051
+ const footer = [];
43052
+ let caption;
43053
+ for (const child of table.children) {
43054
+ if (!isElement(child)) continue;
43055
+ if (child.name === "caption") {
43056
+ const capContent = this.inlineNodes(child.children, []);
43057
+ const trimmed = this.trimInline(capContent);
43058
+ if (trimmed.length > 0) caption = trimmed;
43059
+ } else if (SECTION_TAGS.has(child.name)) {
43060
+ const target = child.name === "thead" ? header : child.name === "tfoot" ? footer : body;
43061
+ for (const tr of childElements(child, ROW_TAGS)) {
43062
+ target.push(this.rowToCells(tr));
43063
+ }
43064
+ } else if (ROW_TAGS.has(child.name)) {
43065
+ body.push(this.rowToCells(child));
43066
+ }
43067
+ }
43068
+ if (header.length === 0 && body.length === 0 && footer.length === 0) {
43069
+ return void 0;
43070
+ }
43071
+ const tableExtended = {};
43072
+ if (header.length > 0) tableExtended.header = { rows: header };
43073
+ if (body.length > 0) tableExtended.body = { rows: body };
43074
+ if (footer.length > 0) tableExtended.footer = { rows: footer };
43075
+ let tableData = tableExtended;
43076
+ if (tableFormat === "table") {
43077
+ if (this.isLossyAsBasic(tableExtended)) {
43078
+ onWarning?.(
43079
+ "Converting an HTML table to [.table] loses rowspan/colspan/scope and multi-section structure; use --tableFormat table-extended to preserve them."
43080
+ );
43081
+ }
43082
+ tableData = convertExtendedToBasicTableFormat(tableExtended);
43083
+ }
43084
+ const bit = {
43085
+ type: tableFormat,
43086
+ format: "bitmark++",
43087
+ table: tableData
43088
+ };
43089
+ if (caption) bit.caption = caption;
43090
+ return bit;
43091
+ }
43092
+ rowToCells(tr) {
43093
+ const cells = [];
43094
+ for (const cell of childElements(tr, CELL_TAGS)) {
43095
+ cells.push(this.cellToJson(cell));
43096
+ }
43097
+ return { cells };
43098
+ }
43099
+ cellToJson(cell) {
43100
+ const json = {
43101
+ content: this.blockNodes(cell.children)
43102
+ };
43103
+ if (cell.name === "th") json.title = true;
43104
+ const rowspan = intAttr(cell.attrs.rowspan);
43105
+ if (rowspan != null && rowspan >= 2) json.rowspan = rowspan;
43106
+ const colspan = intAttr(cell.attrs.colspan);
43107
+ if (colspan != null && colspan >= 2) json.colspan = colspan;
43108
+ const scope = cell.attrs.scope?.toLowerCase();
43109
+ if (scope && VALID_SCOPES.has(scope)) {
43110
+ json.scope = scope;
43111
+ }
43112
+ const width = this.widthFromCell(cell);
43113
+ if (width != null) json.colwidth = width;
43114
+ return json;
43115
+ }
43116
+ widthFromCell(cell) {
43117
+ const attrWidth = intAttr(cell.attrs.width);
43118
+ if (attrWidth != null && attrWidth > 0) return attrWidth;
43119
+ const style = cell.attrs.style;
43120
+ if (style) {
43121
+ const m = style.match(/width\s*:\s*(\d+)\s*px/i);
43122
+ if (m) {
43123
+ const n = Number.parseInt(m[1], 10);
43124
+ if (Number.isInteger(n) && n > 0) return n;
43125
+ }
43126
+ }
43127
+ return void 0;
43128
+ }
43129
+ isLossyAsBasic(table) {
43130
+ if (table.footer) return true;
43131
+ if (table.header && table.header.rows.length > 1) return true;
43132
+ const sections = [table.header, table.body, table.footer];
43133
+ for (const section of sections) {
43134
+ if (!section) continue;
43135
+ for (const row of section.rows) {
43136
+ for (const cell of row.cells) {
43137
+ if (cell.rowspan || cell.colspan || cell.scope) return true;
43138
+ }
43139
+ }
43140
+ }
43141
+ return false;
43142
+ }
43143
+ // --- content conversion (HTML -> TextAst) ---------------------------------
43144
+ /**
43145
+ * Convert a cell/li's child nodes into block-level TextAst nodes (paragraphs, lists, images).
43146
+ */
43147
+ blockNodes(nodes) {
43148
+ const blocks = [];
43149
+ let inline = [];
43150
+ const flush = () => {
43151
+ const trimmed = this.trimInline(inline);
43152
+ inline = [];
43153
+ if (trimmed.length === 0) return;
43154
+ if (trimmed.length === 1 && trimmed[0].type === "imageInline") {
43155
+ blocks.push({ ...trimmed[0], type: "image" });
43156
+ } else {
43157
+ blocks.push({ type: "paragraph", content: trimmed, attrs: {} });
43158
+ }
43159
+ };
43160
+ for (const node of nodes) {
43161
+ if (!isElement(node)) {
43162
+ inline.push(...this.inlineText(node.value, []));
43163
+ continue;
43164
+ }
43165
+ const name = node.name;
43166
+ if (name === "p") {
43167
+ flush();
43168
+ const content = this.trimInline(this.inlineNodes(node.children, []));
43169
+ if (content.length > 0) {
43170
+ blocks.push({ type: "paragraph", content, attrs: {} });
43171
+ }
43172
+ } else if (this.isListTag(name)) {
43173
+ flush();
43174
+ const list = this.listNode(node);
43175
+ if (list) blocks.push(list);
43176
+ } else {
43177
+ inline.push(...this.inlineFromElement(node, []));
43178
+ }
43179
+ }
43180
+ flush();
43181
+ return blocks;
43182
+ }
43183
+ /** Convert child nodes to a flat list of inline TextNodes, applying the given marks. */
43184
+ inlineNodes(nodes, marks) {
43185
+ const out = [];
43186
+ for (const node of nodes) {
43187
+ if (!isElement(node)) {
43188
+ out.push(...this.inlineText(node.value, marks));
43189
+ } else {
43190
+ out.push(...this.inlineFromElement(node, marks));
43191
+ }
43192
+ }
43193
+ return out;
43194
+ }
43195
+ inlineFromElement(el, marks) {
43196
+ const name = el.name;
43197
+ if (name === "br") {
43198
+ return [{ type: "hardBreak" }];
43199
+ }
43200
+ if (name === "img") {
43201
+ return [this.imageNode(el, true)];
43202
+ }
43203
+ if (this.isMathTag(name)) {
43204
+ return [this.latexNode(el)];
43205
+ }
43206
+ const markType = MARK_TAGS[name];
43207
+ if (markType) {
43208
+ return this.inlineNodes(el.children, [...marks, { type: markType }]);
43209
+ }
43210
+ if (name === "a") {
43211
+ const linkMark = {
43212
+ type: "link",
43213
+ attrs: {
43214
+ href: el.attrs.href ?? "",
43215
+ ...el.attrs.target ? { target: el.attrs.target } : {}
43216
+ }
43217
+ };
43218
+ return this.inlineNodes(el.children, [...marks, linkMark]);
43219
+ }
43220
+ if (this.keepUnknownTags) {
43221
+ const open = this.serializeOpenTag(el);
43222
+ const close = `</${name}>`;
43223
+ return [
43224
+ ...this.inlineText(open, marks),
43225
+ ...this.inlineNodes(el.children, marks),
43226
+ ...this.inlineText(close, marks)
43227
+ ];
43228
+ }
43229
+ return this.inlineNodes(el.children, marks);
43230
+ }
43231
+ inlineText(raw, marks) {
43232
+ const text = decodeEntities(raw).replace(/\s+/g, " ");
43233
+ if (text === "") return [];
43234
+ const node = { text, type: "text" };
43235
+ if (marks.length > 0) node.marks = marks.map((m) => ({ ...m }));
43236
+ return [node];
43237
+ }
43238
+ serializeOpenTag(el) {
43239
+ const attrs = Object.entries(el.attrs).map(([k, v]) => v === "" ? ` ${k}` : ` ${k}="${v}"`).join("");
43240
+ return `<${el.name}${attrs}>`;
43241
+ }
43242
+ // --- lists ----------------------------------------------------------------
43243
+ isListTag(name) {
43244
+ return name === "ul" || name === "ol";
43245
+ }
43246
+ listNode(el) {
43247
+ const items = childElements(el, LI_TAGS);
43248
+ if (items.length === 0) return void 0;
43249
+ const isTask = el.name === "ul" && items.some((li) => {
43250
+ const firstEl = li.children.find(isElement);
43251
+ return firstEl?.name === "input" && firstEl.attrs.type?.toLowerCase() === "checkbox";
43252
+ });
43253
+ if (isTask) {
43254
+ return {
43255
+ type: "taskList",
43256
+ content: items.map((li) => this.taskItemNode(li))
43257
+ };
43258
+ }
43259
+ const type = this.listType(el);
43260
+ const node = {
43261
+ type,
43262
+ content: items.map((li) => this.listItemNode(li))
43263
+ };
43264
+ if (el.name === "ol") {
43265
+ const start = intAttr(el.attrs.start);
43266
+ if (start != null) {
43267
+ node.attrs = { start };
43268
+ }
43269
+ }
43270
+ return node;
43271
+ }
43272
+ listType(el) {
43273
+ if (el.name === "ol") {
43274
+ switch (el.attrs.type) {
43275
+ case "i":
43276
+ return "orderedListRomanLower";
43277
+ case "I":
43278
+ return "orderedListRoman";
43279
+ case "a":
43280
+ return "letteredListLower";
43281
+ case "A":
43282
+ return "letteredList";
43283
+ default:
43284
+ return "orderedList";
43285
+ }
43286
+ }
43287
+ const style = el.attrs.style ?? "";
43288
+ if (/list-style(-type)?\s*:\s*none/i.test(style)) return "noBulletList";
43289
+ return "bulletList";
43290
+ }
43291
+ listItemNode(li) {
43292
+ let content = this.blockNodes(li.children);
43293
+ if (content.length === 0) {
43294
+ content = [{ type: "paragraph", content: [], attrs: {} }];
43295
+ }
43296
+ return { type: "listItem", content };
43297
+ }
43298
+ taskItemNode(li) {
43299
+ const checkbox = li.children.find(
43300
+ (c) => isElement(c) && c.name === "input" && c.attrs.type?.toLowerCase() === "checkbox"
43301
+ );
43302
+ const checked = checkbox ? "checked" in checkbox.attrs : false;
43303
+ const rest = li.children.filter((c) => c !== checkbox);
43304
+ let content = this.blockNodes(rest);
43305
+ if (content.length === 0) {
43306
+ content = [{ type: "paragraph", content: [], attrs: {} }];
43307
+ }
43308
+ return { type: "taskItem", attrs: { checked }, content };
43309
+ }
43310
+ // --- images ---------------------------------------------------------------
43311
+ imageNode(el, inline) {
43312
+ const attrs = { src: el.attrs.src ?? "" };
43313
+ attrs.alt = el.attrs.alt ?? null;
43314
+ attrs.title = el.attrs.title ?? null;
43315
+ const width = intAttr(el.attrs.width);
43316
+ if (width != null) attrs.width = width;
43317
+ const height = intAttr(el.attrs.height);
43318
+ if (height != null) attrs.height = height;
43319
+ if (el.attrs.class) attrs.class = el.attrs.class;
43320
+ return { type: inline ? "imageInline" : "image", attrs };
43321
+ }
43322
+ // --- formulas -------------------------------------------------------------
43323
+ isMathTag(name) {
43324
+ return this.localName(name) === "math";
43325
+ }
43326
+ latexNode(el) {
43327
+ return {
43328
+ type: "latex",
43329
+ attrs: {
43330
+ formula: this.latexFromMath(el)
43331
+ }
43332
+ };
43333
+ }
43334
+ latexFromMath(el) {
43335
+ const alt = el.attrs.alttext ?? el.attrs.alt ?? el.attrs.title;
43336
+ if (alt != null) return decodeEntities(alt);
43337
+ const annotation = this.findLatexAnnotation(el);
43338
+ if (annotation) return this.textContent(annotation).trim();
43339
+ return this.textContent(el).trim();
43340
+ }
43341
+ findLatexAnnotation(el) {
43342
+ for (const child of el.children) {
43343
+ if (!isElement(child)) continue;
43344
+ const lowerEncoding = (child.attrs.encoding ?? "").toLowerCase();
43345
+ if (this.localName(child.name) === "annotation" && (/\btex\b/.test(lowerEncoding) || /\blatex\b/.test(lowerEncoding))) {
43346
+ return child;
43347
+ }
43348
+ const nested = this.findLatexAnnotation(child);
43349
+ if (nested) return nested;
43350
+ }
43351
+ return void 0;
43352
+ }
43353
+ textContent(el) {
43354
+ return el.children.map((child) => isElement(child) ? this.textContent(child) : decodeEntities(child.value)).join("").replace(/\s+/g, " ");
43355
+ }
43356
+ localName(name) {
43357
+ return name.includes(":") ? name.slice(name.indexOf(":") + 1) : name;
43358
+ }
43359
+ // --- whitespace -----------------------------------------------------------
43360
+ /** Trim leading/trailing whitespace from inline content (edges only). */
43361
+ trimInline(nodes) {
43362
+ const out = nodes.slice();
43363
+ const isWs = (n) => n.type === "text" && /^\s*$/.test(n.text ?? "");
43364
+ while (out.length > 0 && isWs(out[0])) out.shift();
43365
+ if (out.length > 0 && out[0].type === "text") {
43366
+ out[0] = { ...out[0], text: (out[0].text ?? "").replace(/^\s+/, "") };
43367
+ }
43368
+ while (out.length > 0 && isWs(out[out.length - 1])) out.pop();
43369
+ if (out.length > 0 && out[out.length - 1].type === "text") {
43370
+ const last = out.length - 1;
43371
+ out[last] = { ...out[last], text: (out[last].text ?? "").replace(/\s+$/, "") };
43372
+ }
43373
+ return out.filter((n) => !(n.type === "text" && n.text === ""));
43374
+ }
43375
+ };
43376
+
42282
43377
  // src/BitmarkParserGenerator.ts
42283
43378
  var Input = {
42284
43379
  /**
@@ -42915,7 +44010,10 @@ var BitmarkParserGenerator = class {
42915
44010
  outputFile: opts.outputFile,
42916
44011
  fileOptions: opts.fileOptions,
42917
44012
  jsonOptions: opts.jsonOptions,
42918
- bitmarkOptions: opts.bitmarkOptions
44013
+ bitmarkOptions: {
44014
+ ...opts.bitmarkOptions,
44015
+ ...opts.noBreakscaping ? { noBreakscaping: true } : {}
44016
+ }
42919
44017
  });
42920
44018
  }
42921
44019
  const outputFormat = opts.outputFormat ?? "html";
@@ -43218,728 +44316,6 @@ var BoundingBoxIndex = class _BoundingBoxIndex {
43218
44316
  }
43219
44317
  };
43220
44318
 
43221
- // src/generator/html/HtmlTableGenerator.ts
43222
- var MARK_TO_TAG = {
43223
- bold: "b",
43224
- italic: "i",
43225
- superscript: "sup",
43226
- subscript: "sub",
43227
- strike: "s",
43228
- del: "del",
43229
- ins: "ins",
43230
- underline: "u",
43231
- highlight: "mark",
43232
- code: "code"
43233
- };
43234
- var HtmlTableGenerator2 = class {
43235
- constructor() {
43236
- __publicField(this, "indentUnit", " ");
43237
- }
43238
- /**
43239
- * Generate HTML table fragments from a string or JSON value.
43240
- * @returns the concatenated `<table>` fragments, blank-line separated (empty string if none).
43241
- */
43242
- generate(input) {
43243
- let data = input;
43244
- if (typeof data === "string") {
43245
- try {
43246
- data = JSON.parse(data);
43247
- } catch {
43248
- return "";
43249
- }
43250
- }
43251
- const bits = this.collectBits(data);
43252
- const fragments = [];
43253
- for (const bit of bits) {
43254
- const html = this.renderTableBit(bit);
43255
- if (html) fragments.push(html);
43256
- }
43257
- return fragments.join("\n\n");
43258
- }
43259
- // --- bit collection -------------------------------------------------------
43260
- collectBits(data) {
43261
- const out = [];
43262
- const visit = (value) => {
43263
- if (value == null || typeof value !== "object") return;
43264
- if (Array.isArray(value)) {
43265
- value.forEach(visit);
43266
- return;
43267
- }
43268
- const obj = value;
43269
- if ("bit" in obj && obj.bit && typeof obj.bit === "object") {
43270
- out.push(obj.bit);
43271
- } else if ("type" in obj) {
43272
- out.push(obj);
43273
- }
43274
- };
43275
- visit(data);
43276
- return out;
43277
- }
43278
- // --- table rendering ------------------------------------------------------
43279
- renderTableBit(bit) {
43280
- const table = bit.table;
43281
- if (!table) return "";
43282
- if (bit.type !== "table" && bit.type !== "table-extended") return "";
43283
- const extended = this.toExtended(table);
43284
- const lines = [];
43285
- lines.push("<table>");
43286
- if (bit.caption != null) {
43287
- const caption = this.cellContentToHtml(this.asTextAst(bit.caption));
43288
- if (caption) lines.push(`${this.indentUnit}<caption>${caption}</caption>`);
43289
- }
43290
- this.renderSection(lines, "thead", extended.header, "header");
43291
- this.renderSection(lines, "tbody", extended.body, "body");
43292
- this.renderSection(lines, "tfoot", extended.footer, "footer");
43293
- lines.push("</table>");
43294
- return lines.join("\n");
43295
- }
43296
- toExtended(table) {
43297
- const t = table;
43298
- if (t.header || t.body || t.footer) return table;
43299
- return convertBasicToExtendedTableFormat(table);
43300
- }
43301
- renderSection(lines, tag, section, key) {
43302
- if (!section || !section.rows || section.rows.length === 0) return;
43303
- lines.push(`${this.indentUnit}<${tag}>`);
43304
- for (const row of section.rows) {
43305
- lines.push(`${this.indentUnit.repeat(2)}<tr>`);
43306
- for (const cell of row.cells ?? []) {
43307
- lines.push(`${this.indentUnit.repeat(3)}${this.renderCell(cell, key)}`);
43308
- }
43309
- lines.push(`${this.indentUnit.repeat(2)}</tr>`);
43310
- }
43311
- lines.push(`${this.indentUnit}</${tag}>`);
43312
- }
43313
- renderCell(cell, _key) {
43314
- const tag = cell.title === true ? "th" : "td";
43315
- const attrs = [];
43316
- if (cell.rowspan && cell.rowspan > 1) attrs.push(`rowspan="${cell.rowspan}"`);
43317
- if (cell.colspan && cell.colspan > 1) attrs.push(`colspan="${cell.colspan}"`);
43318
- if (cell.scope) attrs.push(`scope="${cell.scope}"`);
43319
- if (cell.colwidth && cell.colwidth > 0) attrs.push(`width="${cell.colwidth}"`);
43320
- const open = attrs.length > 0 ? `<${tag} ${attrs.join(" ")}>` : `<${tag}>`;
43321
- return `${open}${this.cellContentToHtml(this.asTextAst(cell.content))}</${tag}>`;
43322
- }
43323
- // --- cell content (TextAst -> HTML) ---------------------------------------
43324
- asTextAst(content) {
43325
- if (content == null) return [];
43326
- if (typeof content === "string") return [{ type: "text", text: content }];
43327
- return content;
43328
- }
43329
- cellContentToHtml(blocks) {
43330
- if (blocks.length === 0) return "";
43331
- if (blocks.length === 1 && blocks[0].type === "paragraph") {
43332
- return this.inlineToHtml(blocks[0].content ?? []);
43333
- }
43334
- return blocks.map((b) => this.blockToHtml(b)).join("");
43335
- }
43336
- blockToHtml(node) {
43337
- switch (node.type) {
43338
- case "paragraph":
43339
- return `<p>${this.inlineToHtml(node.content ?? [])}</p>`;
43340
- case "bulletList":
43341
- case "noBulletList":
43342
- case "orderedList":
43343
- case "orderedListRoman":
43344
- case "orderedListRomanLower":
43345
- case "letteredList":
43346
- case "letteredListLower":
43347
- case "taskList":
43348
- return this.listToHtml(node);
43349
- case "image":
43350
- case "imageInline":
43351
- return this.imageToHtml(node);
43352
- default:
43353
- return this.inlineToHtml([node]);
43354
- }
43355
- }
43356
- inlineToHtml(nodes) {
43357
- return nodes.map((n) => this.inlineNodeToHtml(n)).join("");
43358
- }
43359
- inlineNodeToHtml(node) {
43360
- if (node.type === "hardBreak") return "<br>";
43361
- if (node.type === "image" || node.type === "imageInline") return this.imageToHtml(node);
43362
- if (node.type === "text") {
43363
- return this.wrapMarks(this.escapeText(node.text ?? ""), node.marks);
43364
- }
43365
- if (node.content) return this.inlineToHtml(node.content);
43366
- return this.escapeText(node.text ?? "");
43367
- }
43368
- wrapMarks(text, marks) {
43369
- if (!marks || marks.length === 0) return text;
43370
- let open = "";
43371
- let close = "";
43372
- for (const mark of marks) {
43373
- if (mark.type === "link") {
43374
- const href = mark.attrs?.href ?? "";
43375
- open += `<a href="${this.escapeAttr(href)}">`;
43376
- close = `</a>${close}`;
43377
- } else {
43378
- const tag = MARK_TO_TAG[mark.type];
43379
- if (tag) {
43380
- open += `<${tag}>`;
43381
- close = `</${tag}>${close}`;
43382
- }
43383
- }
43384
- }
43385
- return `${open}${text}${close}`;
43386
- }
43387
- // --- lists ----------------------------------------------------------------
43388
- listToHtml(node) {
43389
- const { tag, attrs } = this.listTag(node);
43390
- const items = (node.content ?? []).map((item) => this.listItemToHtml(item, node.type === "taskList")).join("");
43391
- return `<${tag}${attrs}>${items}</${tag}>`;
43392
- }
43393
- listTag(node) {
43394
- const start = node.attrs?.start;
43395
- const startAttr = typeof start === "number" && start !== 1 ? ` start="${start}"` : "";
43396
- switch (node.type) {
43397
- case "orderedList":
43398
- return { tag: "ol", attrs: startAttr };
43399
- case "orderedListRoman":
43400
- return { tag: "ol", attrs: ` type="I"${startAttr}` };
43401
- case "orderedListRomanLower":
43402
- return { tag: "ol", attrs: ` type="i"${startAttr}` };
43403
- case "letteredList":
43404
- return { tag: "ol", attrs: ` type="A"${startAttr}` };
43405
- case "letteredListLower":
43406
- return { tag: "ol", attrs: ` type="a"${startAttr}` };
43407
- case "noBulletList":
43408
- return { tag: "ul", attrs: ' style="list-style:none"' };
43409
- case "taskList":
43410
- case "bulletList":
43411
- default:
43412
- return { tag: "ul", attrs: "" };
43413
- }
43414
- }
43415
- listItemToHtml(item, task) {
43416
- const inner = (item.content ?? []).map((b) => {
43417
- if (b.type === "paragraph") return this.inlineToHtml(b.content ?? []);
43418
- return this.blockToHtml(b);
43419
- }).join("");
43420
- if (task) {
43421
- const checked = item.attrs?.checked ? " checked" : "";
43422
- return `<li><input type="checkbox"${checked}>${inner}</li>`;
43423
- }
43424
- return `<li>${inner}</li>`;
43425
- }
43426
- // --- images ---------------------------------------------------------------
43427
- imageToHtml(node) {
43428
- const attrs = node.attrs ?? {};
43429
- const parts = [];
43430
- const src = attrs.src;
43431
- parts.push(`src="${this.escapeAttr(typeof src === "string" ? src : "")}"`);
43432
- if (typeof attrs.alt === "string") parts.push(`alt="${this.escapeAttr(attrs.alt)}"`);
43433
- if (typeof attrs.title === "string") parts.push(`title="${this.escapeAttr(attrs.title)}"`);
43434
- if (attrs.width != null) parts.push(`width="${attrs.width}"`);
43435
- if (attrs.height != null) parts.push(`height="${attrs.height}"`);
43436
- if (typeof attrs.class === "string" && attrs.class) {
43437
- parts.push(`class="${this.escapeAttr(attrs.class)}"`);
43438
- }
43439
- return `<img ${parts.join(" ")}>`;
43440
- }
43441
- // --- escaping -------------------------------------------------------------
43442
- escapeText(text) {
43443
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
43444
- }
43445
- escapeAttr(text) {
43446
- return this.escapeText(text).replace(/"/g, "&quot;");
43447
- }
43448
- };
43449
-
43450
- // src/parser/html/HtmlDom.ts
43451
- var VOID_ELEMENTS = /* @__PURE__ */ new Set([
43452
- "area",
43453
- "base",
43454
- "br",
43455
- "col",
43456
- "embed",
43457
- "hr",
43458
- "img",
43459
- "input",
43460
- "link",
43461
- "meta",
43462
- "param",
43463
- "source",
43464
- "track",
43465
- "wbr"
43466
- ]);
43467
- var IMPLIED_CLOSE = {
43468
- li: /* @__PURE__ */ new Set(["li"]),
43469
- td: /* @__PURE__ */ new Set(["td", "th"]),
43470
- th: /* @__PURE__ */ new Set(["td", "th"]),
43471
- tr: /* @__PURE__ */ new Set(["td", "th", "tr"]),
43472
- thead: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
43473
- tbody: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
43474
- tfoot: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
43475
- p: /* @__PURE__ */ new Set(["p"]),
43476
- option: /* @__PURE__ */ new Set(["option"])
43477
- };
43478
- var TAG_RE = /<(\/)?([a-zA-Z][a-zA-Z0-9-]*)((?:\s+(?:"[^"]*"|'[^']*'|[^<>"'])*)?)(\/)?>/g;
43479
- var ATTR_RE = /([a-zA-Z_:][a-zA-Z0-9:._-]*)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s"'>]+))?/g;
43480
- function parseAttrs(raw) {
43481
- const attrs = {};
43482
- if (!raw) return attrs;
43483
- ATTR_RE.lastIndex = 0;
43484
- let m;
43485
- while ((m = ATTR_RE.exec(raw)) !== null) {
43486
- const name = m[1].toLowerCase();
43487
- let value = m[2] ?? "";
43488
- if (value.length >= 2 && (value[0] === '"' || value[0] === "'")) {
43489
- value = value.slice(1, -1);
43490
- }
43491
- attrs[name] = value;
43492
- }
43493
- return attrs;
43494
- }
43495
- function stripNonContent(html) {
43496
- 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, "");
43497
- }
43498
- function tokenize(html) {
43499
- const tokens = [];
43500
- const clean = stripNonContent(html);
43501
- TAG_RE.lastIndex = 0;
43502
- let lastIndex = 0;
43503
- let m;
43504
- while ((m = TAG_RE.exec(clean)) !== null) {
43505
- if (m.index > lastIndex) {
43506
- tokens.push({ kind: "text", text: clean.slice(lastIndex, m.index) });
43507
- }
43508
- lastIndex = TAG_RE.lastIndex;
43509
- const isClose = m[1] === "/";
43510
- const name = m[2].toLowerCase();
43511
- if (isClose) {
43512
- tokens.push({ kind: "close", name });
43513
- } else {
43514
- tokens.push({
43515
- kind: "open",
43516
- name,
43517
- attrs: parseAttrs(m[3]),
43518
- selfClose: m[4] === "/"
43519
- });
43520
- }
43521
- }
43522
- if (lastIndex < clean.length) {
43523
- tokens.push({ kind: "text", text: clean.slice(lastIndex) });
43524
- }
43525
- return tokens;
43526
- }
43527
- function parseHtml(html) {
43528
- const root = { type: "element", name: "#root", attrs: {}, children: [] };
43529
- const stack = [root];
43530
- const top = () => stack[stack.length - 1];
43531
- for (const token of tokenize(html)) {
43532
- if (token.kind === "text") {
43533
- if (token.text) top().children.push({ type: "text", value: token.text });
43534
- continue;
43535
- }
43536
- if (token.kind === "open") {
43537
- const name = token.name;
43538
- const closes = IMPLIED_CLOSE[name];
43539
- if (closes) {
43540
- while (stack.length > 1 && closes.has(top().name)) stack.pop();
43541
- }
43542
- const el = {
43543
- type: "element",
43544
- name,
43545
- attrs: token.attrs ?? {},
43546
- children: []
43547
- };
43548
- top().children.push(el);
43549
- if (!token.selfClose && !VOID_ELEMENTS.has(name)) {
43550
- stack.push(el);
43551
- }
43552
- continue;
43553
- }
43554
- for (let i = stack.length - 1; i > 0; i--) {
43555
- if (stack[i].name === token.name) {
43556
- stack.length = i;
43557
- break;
43558
- }
43559
- }
43560
- }
43561
- return root.children;
43562
- }
43563
- function childElements(el, names) {
43564
- return el.children.filter((c) => c.type === "element" && names.has(c.name));
43565
- }
43566
-
43567
- // src/parser/html/HtmlTableParser.ts
43568
- var MARK_TAGS = {
43569
- b: "bold",
43570
- strong: "bold",
43571
- i: "italic",
43572
- em: "italic",
43573
- sup: "superscript",
43574
- sub: "subscript",
43575
- s: "strike",
43576
- strike: "strike",
43577
- del: "del",
43578
- ins: "ins",
43579
- u: "underline",
43580
- mark: "highlight",
43581
- code: "code"
43582
- };
43583
- var SECTION_TAGS = /* @__PURE__ */ new Set(["thead", "tbody", "tfoot"]);
43584
- var ROW_TAGS = /* @__PURE__ */ new Set(["tr"]);
43585
- var CELL_TAGS = /* @__PURE__ */ new Set(["td", "th"]);
43586
- var LI_TAGS = /* @__PURE__ */ new Set(["li"]);
43587
- var VALID_SCOPES = /* @__PURE__ */ new Set(["row", "col", "rowgroup", "colgroup"]);
43588
- var NAMED_ENTITIES = {
43589
- amp: "&",
43590
- lt: "<",
43591
- gt: ">",
43592
- quot: '"',
43593
- apos: "'",
43594
- nbsp: "\xA0"
43595
- };
43596
- function decodeEntities(text) {
43597
- return text.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z][a-zA-Z0-9]*);/g, (whole, body) => {
43598
- if (body[0] === "#") {
43599
- const code = body[1] === "x" || body[1] === "X" ? Number.parseInt(body.slice(2), 16) : Number.parseInt(body.slice(1), 10);
43600
- if (Number.isFinite(code) && code >= 0 && code <= 1114111) {
43601
- try {
43602
- return String.fromCodePoint(code);
43603
- } catch {
43604
- return whole;
43605
- }
43606
- }
43607
- return whole;
43608
- }
43609
- return NAMED_ENTITIES[body] ?? whole;
43610
- });
43611
- }
43612
- function intAttr(value) {
43613
- if (value == null) return void 0;
43614
- const n = Number.parseInt(value, 10);
43615
- return Number.isInteger(n) ? n : void 0;
43616
- }
43617
- function isElement(node) {
43618
- return node.type === "element";
43619
- }
43620
- var HtmlTableParser2 = class {
43621
- constructor() {
43622
- __publicField(this, "keepUnknownTags", false);
43623
- }
43624
- /**
43625
- * Parse an HTML string and return one table bit per top-level `<table>`.
43626
- */
43627
- parse(html, options) {
43628
- this.keepUnknownTags = options?.keepUnknownTags ?? false;
43629
- const tableFormat = options?.tableFormat ?? "table-extended";
43630
- const onWarning = options?.onWarning;
43631
- const tables = this.collectTopLevelTables(parseHtml(html));
43632
- const bits = [];
43633
- for (const table of tables) {
43634
- const bit = this.tableToBit(table, tableFormat, onWarning);
43635
- if (bit) bits.push(bit);
43636
- }
43637
- return bits;
43638
- }
43639
- // --- table extraction -----------------------------------------------------
43640
- /** Collect every `<table>` element, NOT descending into nested tables. */
43641
- collectTopLevelTables(nodes) {
43642
- const tables = [];
43643
- const visit = (node) => {
43644
- if (!isElement(node)) return;
43645
- if (node.name === "table") {
43646
- tables.push(node);
43647
- return;
43648
- }
43649
- node.children.forEach(visit);
43650
- };
43651
- nodes.forEach(visit);
43652
- return tables;
43653
- }
43654
- tableToBit(table, tableFormat, onWarning) {
43655
- const header = [];
43656
- const body = [];
43657
- const footer = [];
43658
- let caption;
43659
- for (const child of table.children) {
43660
- if (!isElement(child)) continue;
43661
- if (child.name === "caption") {
43662
- const capContent = this.inlineNodes(child.children, []);
43663
- const trimmed = this.trimInline(capContent);
43664
- if (trimmed.length > 0) caption = trimmed;
43665
- } else if (SECTION_TAGS.has(child.name)) {
43666
- const target = child.name === "thead" ? header : child.name === "tfoot" ? footer : body;
43667
- for (const tr of childElements(child, ROW_TAGS)) {
43668
- target.push(this.rowToCells(tr));
43669
- }
43670
- } else if (ROW_TAGS.has(child.name)) {
43671
- body.push(this.rowToCells(child));
43672
- }
43673
- }
43674
- if (header.length === 0 && body.length === 0 && footer.length === 0) {
43675
- return void 0;
43676
- }
43677
- const tableExtended = {};
43678
- if (header.length > 0) tableExtended.header = { rows: header };
43679
- if (body.length > 0) tableExtended.body = { rows: body };
43680
- if (footer.length > 0) tableExtended.footer = { rows: footer };
43681
- let tableData = tableExtended;
43682
- if (tableFormat === "table") {
43683
- if (this.isLossyAsBasic(tableExtended)) {
43684
- onWarning?.(
43685
- "Converting an HTML table to [.table] loses rowspan/colspan/scope and multi-section structure; use --tableFormat table-extended to preserve them."
43686
- );
43687
- }
43688
- tableData = convertExtendedToBasicTableFormat(tableExtended);
43689
- }
43690
- const bit = {
43691
- type: tableFormat,
43692
- format: "bitmark++",
43693
- table: tableData
43694
- };
43695
- if (caption) bit.caption = caption;
43696
- return bit;
43697
- }
43698
- rowToCells(tr) {
43699
- const cells = [];
43700
- for (const cell of childElements(tr, CELL_TAGS)) {
43701
- cells.push(this.cellToJson(cell));
43702
- }
43703
- return { cells };
43704
- }
43705
- cellToJson(cell) {
43706
- const json = {
43707
- content: this.blockNodes(cell.children)
43708
- };
43709
- if (cell.name === "th") json.title = true;
43710
- const rowspan = intAttr(cell.attrs.rowspan);
43711
- if (rowspan != null && rowspan >= 2) json.rowspan = rowspan;
43712
- const colspan = intAttr(cell.attrs.colspan);
43713
- if (colspan != null && colspan >= 2) json.colspan = colspan;
43714
- const scope = cell.attrs.scope?.toLowerCase();
43715
- if (scope && VALID_SCOPES.has(scope)) {
43716
- json.scope = scope;
43717
- }
43718
- const width = this.widthFromCell(cell);
43719
- if (width != null) json.colwidth = width;
43720
- return json;
43721
- }
43722
- widthFromCell(cell) {
43723
- const attrWidth = intAttr(cell.attrs.width);
43724
- if (attrWidth != null && attrWidth > 0) return attrWidth;
43725
- const style = cell.attrs.style;
43726
- if (style) {
43727
- const m = style.match(/width\s*:\s*(\d+)\s*px/i);
43728
- if (m) {
43729
- const n = Number.parseInt(m[1], 10);
43730
- if (Number.isInteger(n) && n > 0) return n;
43731
- }
43732
- }
43733
- return void 0;
43734
- }
43735
- isLossyAsBasic(table) {
43736
- if (table.footer) return true;
43737
- if (table.header && table.header.rows.length > 1) return true;
43738
- const sections = [table.header, table.body, table.footer];
43739
- for (const section of sections) {
43740
- if (!section) continue;
43741
- for (const row of section.rows) {
43742
- for (const cell of row.cells) {
43743
- if (cell.rowspan || cell.colspan || cell.scope) return true;
43744
- }
43745
- }
43746
- }
43747
- return false;
43748
- }
43749
- // --- content conversion (HTML -> TextAst) ---------------------------------
43750
- /**
43751
- * Convert a cell/li's child nodes into block-level TextAst nodes (paragraphs, lists, images).
43752
- */
43753
- blockNodes(nodes) {
43754
- const blocks = [];
43755
- let inline = [];
43756
- const flush = () => {
43757
- const trimmed = this.trimInline(inline);
43758
- inline = [];
43759
- if (trimmed.length === 0) return;
43760
- if (trimmed.length === 1 && trimmed[0].type === "imageInline") {
43761
- blocks.push({ ...trimmed[0], type: "image" });
43762
- } else {
43763
- blocks.push({ type: "paragraph", content: trimmed, attrs: {} });
43764
- }
43765
- };
43766
- for (const node of nodes) {
43767
- if (!isElement(node)) {
43768
- inline.push(...this.inlineText(node.value, []));
43769
- continue;
43770
- }
43771
- const name = node.name;
43772
- if (name === "p") {
43773
- flush();
43774
- const content = this.trimInline(this.inlineNodes(node.children, []));
43775
- if (content.length > 0) {
43776
- blocks.push({ type: "paragraph", content, attrs: {} });
43777
- }
43778
- } else if (this.isListTag(name)) {
43779
- flush();
43780
- const list = this.listNode(node);
43781
- if (list) blocks.push(list);
43782
- } else {
43783
- inline.push(...this.inlineFromElement(node, []));
43784
- }
43785
- }
43786
- flush();
43787
- return blocks;
43788
- }
43789
- /** Convert child nodes to a flat list of inline TextNodes, applying the given marks. */
43790
- inlineNodes(nodes, marks) {
43791
- const out = [];
43792
- for (const node of nodes) {
43793
- if (!isElement(node)) {
43794
- out.push(...this.inlineText(node.value, marks));
43795
- } else {
43796
- out.push(...this.inlineFromElement(node, marks));
43797
- }
43798
- }
43799
- return out;
43800
- }
43801
- inlineFromElement(el, marks) {
43802
- const name = el.name;
43803
- if (name === "br") {
43804
- return [{ type: "hardBreak" }];
43805
- }
43806
- if (name === "img") {
43807
- return [this.imageNode(el, true)];
43808
- }
43809
- const markType = MARK_TAGS[name];
43810
- if (markType) {
43811
- return this.inlineNodes(el.children, [...marks, { type: markType }]);
43812
- }
43813
- if (name === "a") {
43814
- const linkMark = {
43815
- type: "link",
43816
- attrs: {
43817
- href: el.attrs.href ?? "",
43818
- ...el.attrs.target ? { target: el.attrs.target } : {}
43819
- }
43820
- };
43821
- return this.inlineNodes(el.children, [...marks, linkMark]);
43822
- }
43823
- if (this.keepUnknownTags) {
43824
- const open = this.serializeOpenTag(el);
43825
- const close = `</${name}>`;
43826
- return [
43827
- ...this.inlineText(open, marks),
43828
- ...this.inlineNodes(el.children, marks),
43829
- ...this.inlineText(close, marks)
43830
- ];
43831
- }
43832
- return this.inlineNodes(el.children, marks);
43833
- }
43834
- inlineText(raw, marks) {
43835
- const text = decodeEntities(raw).replace(/\s+/g, " ");
43836
- if (text === "") return [];
43837
- const node = { text, type: "text" };
43838
- if (marks.length > 0) node.marks = marks.map((m) => ({ ...m }));
43839
- return [node];
43840
- }
43841
- serializeOpenTag(el) {
43842
- const attrs = Object.entries(el.attrs).map(([k, v]) => v === "" ? ` ${k}` : ` ${k}="${v}"`).join("");
43843
- return `<${el.name}${attrs}>`;
43844
- }
43845
- // --- lists ----------------------------------------------------------------
43846
- isListTag(name) {
43847
- return name === "ul" || name === "ol";
43848
- }
43849
- listNode(el) {
43850
- const items = childElements(el, LI_TAGS);
43851
- if (items.length === 0) return void 0;
43852
- const isTask = el.name === "ul" && items.some((li) => {
43853
- const firstEl = li.children.find(isElement);
43854
- return firstEl?.name === "input" && firstEl.attrs.type?.toLowerCase() === "checkbox";
43855
- });
43856
- if (isTask) {
43857
- return {
43858
- type: "taskList",
43859
- content: items.map((li) => this.taskItemNode(li))
43860
- };
43861
- }
43862
- const type = this.listType(el);
43863
- const node = {
43864
- type,
43865
- content: items.map((li) => this.listItemNode(li))
43866
- };
43867
- if (el.name === "ol") {
43868
- const start = intAttr(el.attrs.start);
43869
- if (start != null) {
43870
- node.attrs = { start };
43871
- }
43872
- }
43873
- return node;
43874
- }
43875
- listType(el) {
43876
- if (el.name === "ol") {
43877
- switch (el.attrs.type) {
43878
- case "i":
43879
- return "orderedListRomanLower";
43880
- case "I":
43881
- return "orderedListRoman";
43882
- case "a":
43883
- return "letteredListLower";
43884
- case "A":
43885
- return "letteredList";
43886
- default:
43887
- return "orderedList";
43888
- }
43889
- }
43890
- const style = el.attrs.style ?? "";
43891
- if (/list-style(-type)?\s*:\s*none/i.test(style)) return "noBulletList";
43892
- return "bulletList";
43893
- }
43894
- listItemNode(li) {
43895
- let content = this.blockNodes(li.children);
43896
- if (content.length === 0) {
43897
- content = [{ type: "paragraph", content: [], attrs: {} }];
43898
- }
43899
- return { type: "listItem", content };
43900
- }
43901
- taskItemNode(li) {
43902
- const checkbox = li.children.find(
43903
- (c) => isElement(c) && c.name === "input" && c.attrs.type?.toLowerCase() === "checkbox"
43904
- );
43905
- const checked = checkbox ? "checked" in checkbox.attrs : false;
43906
- const rest = li.children.filter((c) => c !== checkbox);
43907
- let content = this.blockNodes(rest);
43908
- if (content.length === 0) {
43909
- content = [{ type: "paragraph", content: [], attrs: {} }];
43910
- }
43911
- return { type: "taskItem", attrs: { checked }, content };
43912
- }
43913
- // --- images ---------------------------------------------------------------
43914
- imageNode(el, inline) {
43915
- const attrs = { src: el.attrs.src ?? "" };
43916
- attrs.alt = el.attrs.alt ?? null;
43917
- attrs.title = el.attrs.title ?? null;
43918
- const width = intAttr(el.attrs.width);
43919
- if (width != null) attrs.width = width;
43920
- const height = intAttr(el.attrs.height);
43921
- if (height != null) attrs.height = height;
43922
- if (el.attrs.class) attrs.class = el.attrs.class;
43923
- return { type: inline ? "imageInline" : "image", attrs };
43924
- }
43925
- // --- whitespace -----------------------------------------------------------
43926
- /** Trim leading/trailing whitespace from inline content (edges only). */
43927
- trimInline(nodes) {
43928
- const out = nodes.slice();
43929
- const isWs = (n) => n.type === "text" && /^\s*$/.test(n.text ?? "");
43930
- while (out.length > 0 && isWs(out[0])) out.shift();
43931
- if (out.length > 0 && out[0].type === "text") {
43932
- out[0] = { ...out[0], text: (out[0].text ?? "").replace(/^\s+/, "") };
43933
- }
43934
- while (out.length > 0 && isWs(out[out.length - 1])) out.pop();
43935
- if (out.length > 0 && out[out.length - 1].type === "text") {
43936
- const last = out.length - 1;
43937
- out[last] = { ...out[last], text: (out[last].text ?? "").replace(/\s+$/, "") };
43938
- }
43939
- return out.filter((n) => !(n.type === "text" && n.text === ""));
43940
- }
43941
- };
43942
-
43943
44319
  // src/index.ts
43944
44320
  init();
43945
44321
  export {
@@ -43955,8 +44331,8 @@ export {
43955
44331
  BoundingBoxIndex,
43956
44332
  Builder,
43957
44333
  CardSetVersion,
43958
- HtmlTableGenerator2 as HtmlTableGenerator,
43959
- HtmlTableParser2 as HtmlTableParser,
44334
+ HtmlTableGenerator,
44335
+ HtmlTableParser,
43960
44336
  InfoFormat,
43961
44337
  InfoType,
43962
44338
  Input,