@gmb/bitmark-parser-generator 5.26.0 → 5.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -610,6 +610,14 @@ var BitType = {
610
610
  smartStandardRemarkNonNormativeCollapsible: "smart-standard-remark-non-normative-collapsible",
611
611
  smartStandardRemarkNormative: "smart-standard-remark-normative",
612
612
  smartStandardRemarkNormativeCollapsible: "smart-standard-remark-normative-collapsible",
613
+ smartStandardRemarkTableExtendedImageNonNormative: "smart-standard-remark-table-extended-image-non-normative",
614
+ smartStandardRemarkTableExtendedImageNonNormativeCollapsible: "smart-standard-remark-table-extended-image-non-normative-collapsible",
615
+ smartStandardRemarkTableExtendedImageNormative: "smart-standard-remark-table-extended-image-normative",
616
+ smartStandardRemarkTableExtendedImageNormativeCollapsible: "smart-standard-remark-table-extended-image-normative-collapsible",
617
+ smartStandardRemarkTableExtendedNonNormative: "smart-standard-remark-table-extended-non-normative",
618
+ smartStandardRemarkTableExtendedNonNormativeCollapsible: "smart-standard-remark-table-extended-non-normative-collapsible",
619
+ smartStandardRemarkTableExtendedNormative: "smart-standard-remark-table-extended-normative",
620
+ smartStandardRemarkTableExtendedNormativeCollapsible: "smart-standard-remark-table-extended-normative-collapsible",
613
621
  smartStandardRemarkTableImageNonNormative: "smart-standard-remark-table-image-non-normative",
614
622
  smartStandardRemarkTableImageNonNormativeCollapsible: "smart-standard-remark-table-image-non-normative-collapsible",
615
623
  smartStandardRemarkTableImageNormative: "smart-standard-remark-table-image-normative",
@@ -618,6 +626,14 @@ var BitType = {
618
626
  smartStandardRemarkTableNonNormativeCollapsible: "smart-standard-remark-table-non-normative-collapsible",
619
627
  smartStandardRemarkTableNormative: "smart-standard-remark-table-normative",
620
628
  smartStandardRemarkTableNormativeCollapsible: "smart-standard-remark-table-normative-collapsible",
629
+ smartStandardTableExtendedImageNonNormative: "smart-standard-table-extended-image-non-normative",
630
+ smartStandardTableExtendedImageNonNormativeCollapsible: "smart-standard-table-extended-image-non-normative-collapsible",
631
+ smartStandardTableExtendedImageNormative: "smart-standard-table-extended-image-normative",
632
+ smartStandardTableExtendedImageNormativeCollapsible: "smart-standard-table-extended-image-normative-collapsible",
633
+ smartStandardTableExtendedNonNormative: "smart-standard-table-extended-non-normative",
634
+ smartStandardTableExtendedNonNormativeCollapsible: "smart-standard-table-extended-non-normative-collapsible",
635
+ smartStandardTableExtendedNormative: "smart-standard-table-extended-normative",
636
+ smartStandardTableExtendedNormativeCollapsible: "smart-standard-table-extended-normative-collapsible",
621
637
  smartStandardTableImageNonNormative: "smart-standard-table-image-non-normative",
622
638
  smartStandardTableImageNonNormativeCollapsible: "smart-standard-table-image-non-normative-collapsible",
623
639
  smartStandardTableImageNormative: "smart-standard-table-image-normative",
@@ -640,10 +656,18 @@ var BitType = {
640
656
  standardNoteNormative: "standard-note-normative",
641
657
  standardRemarkNonNormative: "standard-remark-non-normative",
642
658
  standardRemarkNormative: "standard-remark-normative",
659
+ standardRemarkTableExtendedImageNonNormative: "standard-remark-table-extended-image-non-normative",
660
+ standardRemarkTableExtendedImageNormative: "standard-remark-table-extended-image-normative",
661
+ standardRemarkTableExtendedNonNormative: "standard-remark-table-extended-non-normative",
662
+ standardRemarkTableExtendedNormative: "standard-remark-table-extended-normative",
643
663
  standardRemarkTableImageNonNormative: "standard-remark-table-image-non-normative",
644
664
  standardRemarkTableImageNormative: "standard-remark-table-image-normative",
645
665
  standardRemarkTableNonNormative: "standard-remark-table-non-normative",
646
666
  standardRemarkTableNormative: "standard-remark-table-normative",
667
+ standardTableExtendedImageNonNormative: "standard-table-extended-image-non-normative",
668
+ standardTableExtendedImageNormative: "standard-table-extended-image-normative",
669
+ standardTableExtendedNonNormative: "standard-table-extended-non-normative",
670
+ standardTableExtendedNormative: "standard-table-extended-normative",
647
671
  standardTableImageNonNormative: "standard-table-image-non-normative",
648
672
  standardTableImageNormative: "standard-table-image-normative",
649
673
  standardTableNonNormative: "standard-table-non-normative",
@@ -870,6 +894,10 @@ var AbstractTagConfig = class {
870
894
  // New JSON-pattern jsonKey (export-only)
871
895
  __publicField(this, "hasExportJsonKey");
872
896
  // True iff exportJsonKey was explicitly set
897
+ __publicField(this, "htmlKey");
898
+ // HTML key-pattern (export-only)
899
+ __publicField(this, "hasHtmlKey");
900
+ // True iff htmlKey was explicitly set
873
901
  __publicField(this, "deprecated");
874
902
  this.type = params.type;
875
903
  this.configKey = params.configKey;
@@ -880,6 +908,8 @@ var AbstractTagConfig = class {
880
908
  this.jsonKey = params.jsonKey;
881
909
  this.exportJsonKey = params.exportJsonKey;
882
910
  this.hasExportJsonKey = params.hasExportJsonKey;
911
+ this.htmlKey = params.htmlKey;
912
+ this.hasHtmlKey = params.hasHtmlKey;
883
913
  this.deprecated = params.deprecated;
884
914
  }
885
915
  };
@@ -1001,7 +1031,7 @@ var ResourceTagConfig = class extends AbstractTagConfig {
1001
1031
  // src/model/config/CardVariantConfig.ts
1002
1032
  var CardVariantConfig = class {
1003
1033
  // Body text format. Default: bitmark++
1004
- constructor(tags2, bodyAllowed, bodyRequired, repeatCount, jsonKey, exportJsonKey, hasExportJsonKey = false, format) {
1034
+ constructor(tags2, bodyAllowed, bodyRequired, repeatCount, jsonKey, exportJsonKey, hasExportJsonKey = false, format, htmlKey, hasHtmlKey = false) {
1005
1035
  __publicField(this, "tags");
1006
1036
  __publicField(this, "bodyAllowed");
1007
1037
  // Default: true
@@ -1015,6 +1045,9 @@ var CardVariantConfig = class {
1015
1045
  __publicField(this, "exportJsonKey");
1016
1046
  // New JSON-pattern jsonKey
1017
1047
  __publicField(this, "hasExportJsonKey");
1048
+ __publicField(this, "htmlKey");
1049
+ // HTML key-pattern
1050
+ __publicField(this, "hasHtmlKey");
1018
1051
  __publicField(this, "format");
1019
1052
  this.tags = tags2;
1020
1053
  this.bodyAllowed = bodyAllowed == null ? true : bodyAllowed;
@@ -1023,6 +1056,8 @@ var CardVariantConfig = class {
1023
1056
  this.jsonKey = jsonKey;
1024
1057
  this.exportJsonKey = exportJsonKey;
1025
1058
  this.hasExportJsonKey = hasExportJsonKey;
1059
+ this.htmlKey = htmlKey;
1060
+ this.hasHtmlKey = hasHtmlKey;
1026
1061
  this.format = format;
1027
1062
  }
1028
1063
  toString(options) {
@@ -1047,18 +1082,22 @@ ${tag.toString(opts)}`;
1047
1082
 
1048
1083
  // src/model/config/CardSideConfig.ts
1049
1084
  var CardSideConfig = class {
1050
- constructor(name, repeat, variants, jsonKey, exportJsonKey, hasExportJsonKey = false) {
1085
+ constructor(name, repeat, variants, jsonKey, exportJsonKey, hasExportJsonKey = false, htmlKey, hasHtmlKey = false) {
1051
1086
  __publicField(this, "name");
1052
1087
  __publicField(this, "repeat");
1053
1088
  __publicField(this, "jsonKey");
1054
1089
  __publicField(this, "exportJsonKey");
1055
1090
  __publicField(this, "hasExportJsonKey");
1091
+ __publicField(this, "htmlKey");
1092
+ __publicField(this, "hasHtmlKey");
1056
1093
  __publicField(this, "variants");
1057
1094
  this.name = name;
1058
1095
  this.repeat = repeat;
1059
1096
  this.jsonKey = jsonKey;
1060
1097
  this.exportJsonKey = exportJsonKey;
1061
1098
  this.hasExportJsonKey = hasExportJsonKey;
1099
+ this.htmlKey = htmlKey;
1100
+ this.hasHtmlKey = hasHtmlKey;
1062
1101
  this.variants = variants;
1063
1102
  }
1064
1103
  toString(options) {
@@ -1080,17 +1119,21 @@ var CardSideConfig = class {
1080
1119
 
1081
1120
  // src/model/config/CardSetConfig.ts
1082
1121
  var CardSetConfig = class {
1083
- constructor(configKey, jsonKey, exportJsonKey, hasExportJsonKey, sections, sides) {
1122
+ constructor(configKey, jsonKey, exportJsonKey, hasExportJsonKey, sections, sides, htmlKey = void 0, hasHtmlKey = false) {
1084
1123
  __publicField(this, "configKey");
1085
1124
  __publicField(this, "jsonKey");
1086
1125
  __publicField(this, "exportJsonKey");
1087
1126
  __publicField(this, "hasExportJsonKey");
1127
+ __publicField(this, "htmlKey");
1128
+ __publicField(this, "hasHtmlKey");
1088
1129
  __publicField(this, "sections");
1089
1130
  __publicField(this, "sides");
1090
1131
  this.configKey = configKey;
1091
1132
  this.jsonKey = jsonKey;
1092
1133
  this.exportJsonKey = exportJsonKey;
1093
1134
  this.hasExportJsonKey = hasExportJsonKey;
1135
+ this.htmlKey = htmlKey;
1136
+ this.hasHtmlKey = hasHtmlKey;
1094
1137
  this.sections = sections;
1095
1138
  this.sides = sides;
1096
1139
  }
@@ -3770,6 +3813,16 @@ var CARDSETS = {
3770
3813
  [CardSetConfigKey.table]: {
3771
3814
  jsonKey: null,
3772
3815
  exportJsonKey: null,
3816
+ // PLAN-109 / HTML.md §8 — idiomatic HTML mapping. The classic (non-extended)
3817
+ // table produces the same `<table>`/`<thead>`/`<tbody>`/`<tfoot>` structure as
3818
+ // table-extended, so the structural htmlKeys mirror that cardSet. NOTE: the
3819
+ // JSON side routes the FIRST header card → `columns` (header) and SUBSEQUENT
3820
+ // header cards → `data` (body); HTML uses a uniform `<thead>` for the whole
3821
+ // `table-header` section, so a multi-card header (e.g. a second header card
3822
+ // that JSON sends to `data`) renders as additional `<thead>` rows rather than
3823
+ // moving to `<tbody>`. Per-card header/body splitting needs engine-level
3824
+ // routing not yet expressible in the pattern vocabulary — see PLAN-109.
3825
+ htmlKey: { "@el": "table", "@children": "$" },
3773
3826
  sections: {
3774
3827
  "table-header": {
3775
3828
  // First header card's row of cells → `columns`. Subsequent header
@@ -3788,25 +3841,36 @@ var CARDSETS = {
3788
3841
  },
3789
3842
  { "@cardIndex=0": { "@bit": { table: { columns: "$" } } } },
3790
3843
  { "@bit": { table: { data: ["$"] } } }
3791
- ]
3844
+ ],
3845
+ // Header section → `<thead>` rows of `<th>`; `@tableColWidth` bubbles a
3846
+ // `width` attr onto the enclosing `<th>` (HTML-C2).
3847
+ htmlKey: { "@el": "thead", "@children": { "@el": "tr", "@children": "$" } },
3848
+ sideHtmlKey: { "@el": "th", "@children": "$" }
3792
3849
  },
3793
3850
  "table-body": {
3794
3851
  // Batched emission: `$` is the entire 2D array of body card rows.
3795
3852
  // This is the default section (no qualifier → cards land here).
3796
3853
  jsonKey: "table.data",
3797
3854
  exportJsonKey: { "@bit": { table: { data: "$" } } },
3855
+ htmlKey: { "@el": "tbody", "@children": { "@el": "tr", "@children": "$" } },
3798
3856
  isDefault: true
3799
3857
  },
3800
3858
  "table-footer": {
3801
3859
  // Batched emission: `$` is the entire 2D array of footer rows.
3802
3860
  jsonKey: "table.data",
3803
- exportJsonKey: { "@bit": { table: { data: "$" } } }
3861
+ exportJsonKey: { "@bit": { table: { data: "$" } } },
3862
+ // Footer cells route to `data` (not `columns`), so they are `<td>` (no
3863
+ // sideHtmlKey override — the cell side default applies).
3864
+ htmlKey: { "@el": "tfoot", "@children": { "@el": "tr", "@children": "$" } }
3804
3865
  }
3805
3866
  },
3806
3867
  sides: [
3807
3868
  {
3808
3869
  name: "cell",
3809
3870
  repeat: true,
3871
+ // Default (body/footer) cell → `<td>`; the header section overrides to
3872
+ // `<th>` via its sideHtmlKey (HTML.md §8).
3873
+ htmlKey: { "@el": "td", "@children": "$" },
3810
3874
  variants: [
3811
3875
  {
3812
3876
  jsonKey: null,
@@ -3823,6 +3887,8 @@ var CARDSETS = {
3823
3887
  },
3824
3888
  {
3825
3889
  key: ConfigKey.property_tableCellType,
3890
+ // HTML.md §8: first-match predicate selecting `<th>` vs `<td>`.
3891
+ htmlKey: [{ "@value=th": { "@el": "th" } }, { "@absent": { "@el": "td" } }],
3826
3892
  description: "Table cell type (th/td).",
3827
3893
  format: TagFormat.plainText
3828
3894
  },
@@ -3845,6 +3911,9 @@ var CARDSETS = {
3845
3911
  key: ConfigKey.property_tableColWidth,
3846
3912
  jsonKey: "^table.columnWidths[{s}]",
3847
3913
  exportJsonKey: { "@bit": { table: { columnWidths: { $s: "$" } } } },
3914
+ // HTML.md §8 + HTML-C2: contribute a `width` attribute onto the
3915
+ // enclosing cell element (`<th>`/`<td>`).
3916
+ htmlKey: { "@el": { "@attr": { width: "$" } } },
3848
3917
  description: "Width for the column.",
3849
3918
  format: TagFormat.number
3850
3919
  }
@@ -3860,6 +3929,12 @@ var CARDSETS = {
3860
3929
  //
3861
3930
  [CardSetConfigKey.tableExtended]: {
3862
3931
  jsonKey: null,
3932
+ // PLAN-109 / HTML.md §8 — idiomatic HTML mapping for the extended table.
3933
+ // The card-set container is the `<table>` element; each section is a
3934
+ // table section element (`<thead>`/`<tbody>`/`<tfoot>`) whose children are
3935
+ // `<tr>` rows, and each cell side is a `<td>` (body) or `<th>` (header /
3936
+ // footer, via the section sideHtmlKey override).
3937
+ htmlKey: { "@el": "table", "@children": "$" },
3863
3938
  sections: {
3864
3939
  "table-header": {
3865
3940
  jsonKey: "table.header.rows",
@@ -3879,19 +3954,29 @@ var CARDSETS = {
3879
3954
  },
3880
3955
  { table: { header: { rows: ["$"] } } }
3881
3956
  ],
3957
+ htmlKey: { "@el": "thead", "@children": { "@el": "tr", "@children": "$" } },
3882
3958
  sideJsonKey: "cells[{s}]|set(title=true)",
3883
- sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } }
3959
+ sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } },
3960
+ // Header cells are `<th>`. The `width` attribute is contributed by the
3961
+ // `@tableColWidth` tag, which bubbles it onto the enclosing `<th>`
3962
+ // (HTML-C2) — so it is not repeated here.
3963
+ sideHtmlKey: { "@el": "th", "@children": "$" }
3884
3964
  },
3885
3965
  "table-body": {
3886
3966
  jsonKey: "table.body.rows",
3887
3967
  exportJsonKey: { table: { body: { rows: "$" } } },
3968
+ htmlKey: { "@el": "tbody", "@children": { "@el": "tr", "@children": "$" } },
3888
3969
  isDefault: true
3889
3970
  },
3890
3971
  "table-footer": {
3891
3972
  jsonKey: "table.footer.rows",
3892
3973
  exportJsonKey: { table: { footer: { rows: "$" } } },
3974
+ htmlKey: { "@el": "tfoot", "@children": { "@el": "tr", "@children": "$" } },
3893
3975
  sideJsonKey: "cells[{s}]|set(title=true)",
3894
- sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } }
3976
+ sideExportJsonKey: { cells: { $s: { title: true, $: "$" } } },
3977
+ // Footer cells render as `<th>` (mirrors the header `title: true`
3978
+ // mapping); §8 lists only the header side, so this parallels it.
3979
+ sideHtmlKey: { "@el": "th", "@children": "$" }
3895
3980
  }
3896
3981
  },
3897
3982
  sides: [
@@ -3900,6 +3985,9 @@ var CARDSETS = {
3900
3985
  repeat: true,
3901
3986
  jsonKey: "cells[{s}]",
3902
3987
  exportJsonKey: { cells: { $s: "$" } },
3988
+ // Default (body) cell → `<td>`; the header/footer sections override the
3989
+ // side to `<th>` via their sideHtmlKey (HTML.md §8).
3990
+ htmlKey: { "@el": "td", "@children": "$" },
3903
3991
  variants: [
3904
3992
  {
3905
3993
  jsonKey: "content",
@@ -3923,6 +4011,9 @@ var CARDSETS = {
3923
4011
  key: ConfigKey.property_tableCellType,
3924
4012
  jsonKey: "title|bool(th)",
3925
4013
  exportJsonKey: [{ "@value=th": { title: true } }],
4014
+ // HTML.md §8: same first-match predicate machinery selecting
4015
+ // `<th>` vs `<td>` instead of `title:true` vs nothing.
4016
+ htmlKey: [{ "@value=th": { "@el": "th" } }, { "@absent": { "@el": "td" } }],
3926
4017
  description: "Table cell type (th/td).",
3927
4018
  format: TagFormat.plainText
3928
4019
  },
@@ -3952,6 +4043,9 @@ var CARDSETS = {
3952
4043
  // PLAN-080: write to the cell's `colwidth` field.
3953
4044
  jsonKey: "colwidth",
3954
4045
  exportJsonKey: { colwidth: "$" },
4046
+ // HTML.md §8 + HTML-C2: contribute a `width` attribute onto the
4047
+ // enclosing cell element (`<th>`/`<td>`).
4048
+ htmlKey: { "@el": { "@attr": { width: "$" } } },
3955
4049
  description: "Width for the column.",
3956
4050
  format: TagFormat.number
3957
4051
  }
@@ -6880,7 +6974,9 @@ var ConfigHydrator = class {
6880
6974
  variantsOfSide,
6881
6975
  _side.jsonKey,
6882
6976
  _side.exportJsonKey,
6883
- Object.prototype.hasOwnProperty.call(_side, "exportJsonKey")
6977
+ Object.prototype.hasOwnProperty.call(_side, "exportJsonKey"),
6978
+ _side.htmlKey,
6979
+ Object.prototype.hasOwnProperty.call(_side, "htmlKey")
6884
6980
  );
6885
6981
  sides.push(sideConfig);
6886
6982
  }
@@ -6890,7 +6986,9 @@ var ConfigHydrator = class {
6890
6986
  _cardSetConfig.exportJsonKey,
6891
6987
  Object.prototype.hasOwnProperty.call(_cardSetConfig, "exportJsonKey"),
6892
6988
  this.hydrateCardSections(_cardSetConfig.sections),
6893
- sides
6989
+ sides,
6990
+ _cardSetConfig.htmlKey,
6991
+ Object.prototype.hasOwnProperty.call(_cardSetConfig, "htmlKey")
6894
6992
  );
6895
6993
  return cardSetConfig;
6896
6994
  }
@@ -6902,10 +7000,14 @@ var ConfigHydrator = class {
6902
7000
  jsonKey: v.jsonKey,
6903
7001
  exportJsonKey: v.exportJsonKey,
6904
7002
  hasExportJsonKey: Object.prototype.hasOwnProperty.call(v, "exportJsonKey"),
7003
+ htmlKey: v.htmlKey,
7004
+ hasHtmlKey: Object.prototype.hasOwnProperty.call(v, "htmlKey"),
6905
7005
  isDefault: v.isDefault,
6906
7006
  sideJsonKey: v.sideJsonKey,
6907
7007
  sideExportJsonKey: v.sideExportJsonKey,
6908
7008
  hasSideExportJsonKey: Object.prototype.hasOwnProperty.call(v, "sideExportJsonKey"),
7009
+ sideHtmlKey: v.sideHtmlKey,
7010
+ hasSideHtmlKey: Object.prototype.hasOwnProperty.call(v, "sideHtmlKey"),
6909
7011
  // PLAN-085: cardinality fields pass through; defaults applied
6910
7012
  // downstream by the config consumer (Rust treats `0` / undefined
6911
7013
  // as unbounded).
@@ -6923,7 +7025,8 @@ var ConfigHydrator = class {
6923
7025
  chain: _chain,
6924
7026
  deprecated,
6925
7027
  jsonKey,
6926
- exportJsonKey
7028
+ exportJsonKey,
7029
+ htmlKey
6927
7030
  } = _tag;
6928
7031
  const configKey = (0, import_superenum15.Enum)(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
6929
7032
  if (!configKey) throw new Error(`No tag key found for config key '${configKey}'`);
@@ -6942,6 +7045,8 @@ var ConfigHydrator = class {
6942
7045
  jsonKey,
6943
7046
  exportJsonKey,
6944
7047
  hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
7048
+ htmlKey,
7049
+ hasHtmlKey: Object.prototype.hasOwnProperty.call(_tag, "htmlKey"),
6945
7050
  deprecated
6946
7051
  });
6947
7052
  return {
@@ -6961,7 +7066,8 @@ var ConfigHydrator = class {
6961
7066
  values,
6962
7067
  defaultValue,
6963
7068
  jsonKey,
6964
- exportJsonKey
7069
+ exportJsonKey,
7070
+ htmlKey
6965
7071
  } = _tag;
6966
7072
  const configKey = (0, import_superenum15.Enum)(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
6967
7073
  if (!configKey) throw new Error(`No property key found for config key '${configKey}'`);
@@ -6979,6 +7085,8 @@ var ConfigHydrator = class {
6979
7085
  jsonKey,
6980
7086
  exportJsonKey,
6981
7087
  hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
7088
+ htmlKey,
7089
+ hasHtmlKey: Object.prototype.hasOwnProperty.call(_tag, "htmlKey"),
6982
7090
  format,
6983
7091
  values,
6984
7092
  defaultValue,
@@ -6998,7 +7106,8 @@ var ConfigHydrator = class {
6998
7106
  chain: _chain,
6999
7107
  deprecated,
7000
7108
  jsonKey,
7001
- exportJsonKey
7109
+ exportJsonKey,
7110
+ htmlKey
7002
7111
  } = _tag;
7003
7112
  const configKey = (0, import_superenum15.Enum)(ConfigKey).fromValue(_configKey) || ConfigKey._unknown;
7004
7113
  if (!configKey) throw new Error(`No resource key found for config key '${configKey}'`);
@@ -7016,6 +7125,8 @@ var ConfigHydrator = class {
7016
7125
  jsonKey,
7017
7126
  exportJsonKey,
7018
7127
  hasExportJsonKey: Object.prototype.hasOwnProperty.call(_tag, "exportJsonKey"),
7128
+ htmlKey,
7129
+ hasHtmlKey: Object.prototype.hasOwnProperty.call(_tag, "htmlKey"),
7019
7130
  deprecated
7020
7131
  });
7021
7132
  return {
@@ -7054,6 +7165,7 @@ var ConfigHydrator = class {
7054
7165
  repeatCount,
7055
7166
  jsonKey,
7056
7167
  exportJsonKey,
7168
+ htmlKey,
7057
7169
  format
7058
7170
  } = _variant;
7059
7171
  const tags2 = this.hydrateTagsConfig(_tags);
@@ -7065,7 +7177,9 @@ var ConfigHydrator = class {
7065
7177
  jsonKey,
7066
7178
  exportJsonKey,
7067
7179
  Object.prototype.hasOwnProperty.call(_variant, "exportJsonKey"),
7068
- format
7180
+ format,
7181
+ htmlKey,
7182
+ Object.prototype.hasOwnProperty.call(_variant, "htmlKey")
7069
7183
  );
7070
7184
  return cardSetConfig;
7071
7185
  }
@@ -10198,11 +10312,6 @@ var BITS = {
10198
10312
  baseBitType: BitType._standard,
10199
10313
  description: "Extractor rule bit, used to define extraction rules with reference images and instructions",
10200
10314
  tags: [
10201
- {
10202
- exportJsonKey: { title: "$" },
10203
- key: ConfigKey.tag_title,
10204
- description: "The name of the extraction rule"
10205
- },
10206
10315
  {
10207
10316
  key: ConfigKey.group_resourceBitTags,
10208
10317
  description: "Resource bit tags for extraction rule images"
@@ -10881,6 +10990,26 @@ var BITS = {
10881
10990
  baseBitType: BitType.tableImage,
10882
10991
  description: "Standard non-normative remark table image bit, used to create non-normative remark images in tables in articles or books"
10883
10992
  },
10993
+ [BitType.standardTableExtendedImageNormative]: {
10994
+ since: "1.16.0",
10995
+ baseBitType: BitType.tableExtendedImage,
10996
+ description: "Standard normative extended table image bit, used to create normative extended images in tables in articles or books"
10997
+ },
10998
+ [BitType.standardTableExtendedImageNonNormative]: {
10999
+ since: "1.16.0",
11000
+ baseBitType: BitType.tableExtendedImage,
11001
+ description: "Standard non-normative extended table image bit, used to create non-normative extended images in tables in articles or books"
11002
+ },
11003
+ [BitType.standardRemarkTableExtendedImageNormative]: {
11004
+ since: "1.17.0",
11005
+ baseBitType: BitType.tableExtendedImage,
11006
+ description: "Standard normative remark extended table image bit, used to create normative remark extended images in tables in articles or books"
11007
+ },
11008
+ [BitType.standardRemarkTableExtendedImageNonNormative]: {
11009
+ since: "1.17.0",
11010
+ baseBitType: BitType.tableExtendedImage,
11011
+ description: "Standard non-normative remark extended table image bit, used to create non-normative remark extended images in tables in articles or books"
11012
+ },
10884
11013
  [BitType.smartStandardTableImageNormative]: {
10885
11014
  since: "1.28.0",
10886
11015
  baseBitType: BitType.standardTableImageNormative,
@@ -10901,6 +11030,26 @@ var BITS = {
10901
11030
  baseBitType: BitType.standardRemarkTableImageNonNormative,
10902
11031
  description: "Smart standard non-normative remark table image bit, used to create smart standard non-normative remark images in tables in articles or books"
10903
11032
  },
11033
+ [BitType.smartStandardTableExtendedImageNormative]: {
11034
+ since: "1.28.0",
11035
+ baseBitType: BitType.standardTableExtendedImageNormative,
11036
+ description: "Smart standard normative extended table image bit, used to create smart standard normative extended images in tables in articles or books"
11037
+ },
11038
+ [BitType.smartStandardTableExtendedImageNonNormative]: {
11039
+ since: "1.28.0",
11040
+ baseBitType: BitType.standardTableExtendedImageNonNormative,
11041
+ description: "Smart standard non-normative extended table image bit, used to create smart standard non-normative extended images in tables in articles or books"
11042
+ },
11043
+ [BitType.smartStandardRemarkTableExtendedImageNormative]: {
11044
+ since: "1.28.0",
11045
+ baseBitType: BitType.standardRemarkTableExtendedImageNormative,
11046
+ description: "Smart standard normative remark extended table image bit, used to create smart standard normative remark extended images in tables in articles or books"
11047
+ },
11048
+ [BitType.smartStandardRemarkTableExtendedImageNonNormative]: {
11049
+ since: "1.28.0",
11050
+ baseBitType: BitType.standardRemarkTableExtendedImageNonNormative,
11051
+ 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"
11052
+ },
10904
11053
  [BitType.smartStandardTableImageNormativeCollapsible]: {
10905
11054
  since: "1.28.0",
10906
11055
  baseBitType: BitType.smartStandardTableImageNormative,
@@ -10921,6 +11070,26 @@ var BITS = {
10921
11070
  baseBitType: BitType.smartStandardRemarkTableImageNonNormative,
10922
11071
  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"
10923
11072
  },
11073
+ [BitType.smartStandardTableExtendedImageNormativeCollapsible]: {
11074
+ since: "1.28.0",
11075
+ baseBitType: BitType.smartStandardTableExtendedImageNormative,
11076
+ description: "Collapsible smart standard normative extended table image bit, used to create collapsible smart standard normative extended images in tables in articles or books"
11077
+ },
11078
+ [BitType.smartStandardTableExtendedImageNonNormativeCollapsible]: {
11079
+ since: "1.28.0",
11080
+ baseBitType: BitType.smartStandardTableExtendedImageNonNormative,
11081
+ 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"
11082
+ },
11083
+ [BitType.smartStandardRemarkTableExtendedImageNormativeCollapsible]: {
11084
+ since: "1.28.0",
11085
+ baseBitType: BitType.smartStandardRemarkTableExtendedImageNormative,
11086
+ 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"
11087
+ },
11088
+ [BitType.smartStandardRemarkTableExtendedImageNonNormativeCollapsible]: {
11089
+ since: "1.28.0",
11090
+ baseBitType: BitType.smartStandardRemarkTableExtendedImageNonNormative,
11091
+ 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"
11092
+ },
10924
11093
  [BitType.imageLink]: {
10925
11094
  since: "1.3.0",
10926
11095
  baseBitType: BitType._standard,
@@ -12597,6 +12766,26 @@ var BITS = {
12597
12766
  baseBitType: BitType.table,
12598
12767
  description: "Standard non-normative remark table bit, used to create standard non-normative remark tables in articles or books"
12599
12768
  },
12769
+ [BitType.standardTableExtendedNormative]: {
12770
+ since: "1.16.0",
12771
+ baseBitType: BitType.tableExtended,
12772
+ description: "Standard normative extended table bit, used to create standard normative extended tables in articles or books"
12773
+ },
12774
+ [BitType.standardTableExtendedNonNormative]: {
12775
+ since: "1.16.0",
12776
+ baseBitType: BitType.tableExtended,
12777
+ description: "Standard non-normative extended table bit, used to create standard non-normative extended tables in articles or books"
12778
+ },
12779
+ [BitType.standardRemarkTableExtendedNormative]: {
12780
+ since: "1.17.0",
12781
+ baseBitType: BitType.tableExtended,
12782
+ description: "Standard normative remark extended table bit, used to create standard normative remark extended tables in articles or books"
12783
+ },
12784
+ [BitType.standardRemarkTableExtendedNonNormative]: {
12785
+ since: "1.17.0",
12786
+ baseBitType: BitType.tableExtended,
12787
+ description: "Standard non-normative remark extended table bit, used to create standard non-normative remark extended tables in articles or books"
12788
+ },
12600
12789
  [BitType.smartStandardTableNormative]: {
12601
12790
  since: "1.28.0",
12602
12791
  baseBitType: BitType.standardTableNormative,
@@ -12617,6 +12806,26 @@ var BITS = {
12617
12806
  baseBitType: BitType.standardRemarkTableNonNormative,
12618
12807
  description: "Smart standard non-normative remark table bit, used to create smart standard non-normative remark tables in articles or books"
12619
12808
  },
12809
+ [BitType.smartStandardTableExtendedNormative]: {
12810
+ since: "1.28.0",
12811
+ baseBitType: BitType.standardTableExtendedNormative,
12812
+ description: "Smart standard normative extended table bit, used to create smart standard normative extended tables in articles or books"
12813
+ },
12814
+ [BitType.smartStandardTableExtendedNonNormative]: {
12815
+ since: "1.28.0",
12816
+ baseBitType: BitType.standardTableExtendedNonNormative,
12817
+ description: "Smart standard non-normative extended table bit, used to create smart standard non-normative extended tables in articles or books"
12818
+ },
12819
+ [BitType.smartStandardRemarkTableExtendedNormative]: {
12820
+ since: "1.28.0",
12821
+ baseBitType: BitType.standardRemarkTableExtendedNormative,
12822
+ description: "Smart standard normative remark extended table bit, used to create smart standard normative remark extended tables in articles or books"
12823
+ },
12824
+ [BitType.smartStandardRemarkTableExtendedNonNormative]: {
12825
+ since: "1.28.0",
12826
+ baseBitType: BitType.standardRemarkTableExtendedNonNormative,
12827
+ description: "Smart standard non-normative remark extended table bit, used to create smart standard non-normative remark extended tables in articles or books"
12828
+ },
12620
12829
  [BitType.smartStandardTableNormativeCollapsible]: {
12621
12830
  since: "1.28.0",
12622
12831
  baseBitType: BitType.smartStandardTableNormative,
@@ -12637,6 +12846,26 @@ var BITS = {
12637
12846
  baseBitType: BitType.smartStandardRemarkTableNonNormative,
12638
12847
  description: "Collapsible smart standard non-normative remark table bit, used to create collapsible smart standard non-normative remark tables in articles or books"
12639
12848
  },
12849
+ [BitType.smartStandardTableExtendedNormativeCollapsible]: {
12850
+ since: "1.28.0",
12851
+ baseBitType: BitType.smartStandardTableExtendedNormative,
12852
+ description: "Collapsible smart standard normative extended table bit, used to create collapsible smart standard normative extended tables in articles or books"
12853
+ },
12854
+ [BitType.smartStandardTableExtendedNonNormativeCollapsible]: {
12855
+ since: "1.28.0",
12856
+ baseBitType: BitType.smartStandardTableExtendedNonNormative,
12857
+ description: "Collapsible smart standard non-normative extended table bit, used to create collapsible smart standard non-normative extended tables in articles or books"
12858
+ },
12859
+ [BitType.smartStandardRemarkTableExtendedNormativeCollapsible]: {
12860
+ since: "1.28.0",
12861
+ baseBitType: BitType.smartStandardRemarkTableExtendedNormative,
12862
+ description: "Collapsible smart standard normative remark extended table bit, used to create collapsible smart standard normative remark extended tables in articles or books"
12863
+ },
12864
+ [BitType.smartStandardRemarkTableExtendedNonNormativeCollapsible]: {
12865
+ since: "1.28.0",
12866
+ baseBitType: BitType.smartStandardRemarkTableExtendedNonNormative,
12867
+ 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"
12868
+ },
12640
12869
  [BitType.parameters]: {
12641
12870
  since: "1.18.0",
12642
12871
  baseBitType: BitType.table,
@@ -13578,6 +13807,8 @@ var Config = class {
13578
13807
  jsonKey: tag.jsonKey,
13579
13808
  exportJsonKey: tag.exportJsonKey,
13580
13809
  hasExportJsonKey: tag.hasExportJsonKey,
13810
+ htmlKey: tag.htmlKey,
13811
+ hasHtmlKey: tag.hasHtmlKey,
13581
13812
  deprecated: tag.deprecated
13582
13813
  });
13583
13814
  finalResourceTags[k] = newTag;
@@ -13682,7 +13913,7 @@ var instance2 = new Config();
13682
13913
  // src/generated/package_info.ts
13683
13914
  var PACKAGE_INFO = {
13684
13915
  "name": "@gmb/bitmark-parser-generator",
13685
- "version": "5.26.0",
13916
+ "version": "5.27.0",
13686
13917
  "author": "Get More Brain Ltd",
13687
13918
  "license": "ISC",
13688
13919
  "description": "A bitmark parser and generator using Peggy.js"
@@ -33038,6 +33269,235 @@ var BitmarkStringGenerator = class {
33038
33269
  }
33039
33270
  };
33040
33271
 
33272
+ // src/generator/html/HtmlTableGenerator.ts
33273
+ var MARK_TO_TAG = {
33274
+ bold: "b",
33275
+ italic: "i",
33276
+ superscript: "sup",
33277
+ subscript: "sub",
33278
+ strike: "s",
33279
+ del: "del",
33280
+ ins: "ins",
33281
+ underline: "u",
33282
+ highlight: "mark",
33283
+ code: "code"
33284
+ };
33285
+ var HtmlTableGenerator = class {
33286
+ constructor() {
33287
+ __publicField(this, "indentUnit", " ");
33288
+ }
33289
+ /**
33290
+ * Generate HTML table fragments from a string or JSON value.
33291
+ * @returns the concatenated `<table>` fragments, blank-line separated (empty string if none).
33292
+ */
33293
+ generate(input) {
33294
+ let data = input;
33295
+ if (typeof data === "string") {
33296
+ try {
33297
+ data = JSON.parse(data);
33298
+ } catch {
33299
+ return "";
33300
+ }
33301
+ }
33302
+ const bits = this.collectBits(data);
33303
+ const fragments = [];
33304
+ for (const bit of bits) {
33305
+ const html = this.renderTableBit(bit);
33306
+ if (html) fragments.push(html);
33307
+ }
33308
+ return fragments.join("\n\n");
33309
+ }
33310
+ // --- bit collection -------------------------------------------------------
33311
+ collectBits(data) {
33312
+ const out = [];
33313
+ const visit = (value) => {
33314
+ if (value == null || typeof value !== "object") return;
33315
+ if (Array.isArray(value)) {
33316
+ value.forEach(visit);
33317
+ return;
33318
+ }
33319
+ const obj = value;
33320
+ if ("bit" in obj && obj.bit && typeof obj.bit === "object") {
33321
+ out.push(obj.bit);
33322
+ } else if ("type" in obj) {
33323
+ out.push(obj);
33324
+ }
33325
+ };
33326
+ visit(data);
33327
+ return out;
33328
+ }
33329
+ // --- table rendering ------------------------------------------------------
33330
+ renderTableBit(bit) {
33331
+ const table = bit.table;
33332
+ if (!table) return "";
33333
+ if (bit.type !== "table" && bit.type !== "table-extended") return "";
33334
+ const extended = this.toExtended(table);
33335
+ const lines = [];
33336
+ lines.push("<table>");
33337
+ if (bit.caption != null) {
33338
+ const caption = this.cellContentToHtml(this.asTextAst(bit.caption));
33339
+ if (caption) lines.push(`${this.indentUnit}<caption>${caption}</caption>`);
33340
+ }
33341
+ this.renderSection(lines, "thead", extended.header, "header");
33342
+ this.renderSection(lines, "tbody", extended.body, "body");
33343
+ this.renderSection(lines, "tfoot", extended.footer, "footer");
33344
+ lines.push("</table>");
33345
+ return lines.join("\n");
33346
+ }
33347
+ toExtended(table) {
33348
+ const t = table;
33349
+ if (t.header || t.body || t.footer) return table;
33350
+ return convertBasicToExtendedTableFormat(table);
33351
+ }
33352
+ renderSection(lines, tag, section, key) {
33353
+ if (!section || !section.rows || section.rows.length === 0) return;
33354
+ lines.push(`${this.indentUnit}<${tag}>`);
33355
+ for (const row of section.rows) {
33356
+ lines.push(`${this.indentUnit.repeat(2)}<tr>`);
33357
+ for (const cell of row.cells ?? []) {
33358
+ lines.push(`${this.indentUnit.repeat(3)}${this.renderCell(cell, key)}`);
33359
+ }
33360
+ lines.push(`${this.indentUnit.repeat(2)}</tr>`);
33361
+ }
33362
+ lines.push(`${this.indentUnit}</${tag}>`);
33363
+ }
33364
+ renderCell(cell, _key) {
33365
+ const tag = cell.title === true ? "th" : "td";
33366
+ const attrs = [];
33367
+ if (cell.rowspan && cell.rowspan > 1) attrs.push(`rowspan="${cell.rowspan}"`);
33368
+ if (cell.colspan && cell.colspan > 1) attrs.push(`colspan="${cell.colspan}"`);
33369
+ if (cell.scope) attrs.push(`scope="${cell.scope}"`);
33370
+ if (cell.colwidth && cell.colwidth > 0) attrs.push(`width="${cell.colwidth}"`);
33371
+ const open = attrs.length > 0 ? `<${tag} ${attrs.join(" ")}>` : `<${tag}>`;
33372
+ return `${open}${this.cellContentToHtml(this.asTextAst(cell.content))}</${tag}>`;
33373
+ }
33374
+ // --- cell content (TextAst -> HTML) ---------------------------------------
33375
+ asTextAst(content) {
33376
+ if (content == null) return [];
33377
+ if (typeof content === "string") return [{ type: "text", text: content }];
33378
+ return content;
33379
+ }
33380
+ cellContentToHtml(blocks) {
33381
+ if (blocks.length === 0) return "";
33382
+ if (blocks.length === 1 && blocks[0].type === "paragraph") {
33383
+ return this.inlineToHtml(blocks[0].content ?? []);
33384
+ }
33385
+ return blocks.map((b) => this.blockToHtml(b)).join("");
33386
+ }
33387
+ blockToHtml(node) {
33388
+ switch (node.type) {
33389
+ case "paragraph":
33390
+ return `<p>${this.inlineToHtml(node.content ?? [])}</p>`;
33391
+ case "bulletList":
33392
+ case "noBulletList":
33393
+ case "orderedList":
33394
+ case "orderedListRoman":
33395
+ case "orderedListRomanLower":
33396
+ case "letteredList":
33397
+ case "letteredListLower":
33398
+ case "taskList":
33399
+ return this.listToHtml(node);
33400
+ case "image":
33401
+ case "imageInline":
33402
+ return this.imageToHtml(node);
33403
+ default:
33404
+ return this.inlineToHtml([node]);
33405
+ }
33406
+ }
33407
+ inlineToHtml(nodes) {
33408
+ return nodes.map((n) => this.inlineNodeToHtml(n)).join("");
33409
+ }
33410
+ inlineNodeToHtml(node) {
33411
+ if (node.type === "hardBreak") return "<br>";
33412
+ if (node.type === "image" || node.type === "imageInline") return this.imageToHtml(node);
33413
+ if (node.type === "text") {
33414
+ return this.wrapMarks(this.escapeText(node.text ?? ""), node.marks);
33415
+ }
33416
+ if (node.content) return this.inlineToHtml(node.content);
33417
+ return this.escapeText(node.text ?? "");
33418
+ }
33419
+ wrapMarks(text, marks) {
33420
+ if (!marks || marks.length === 0) return text;
33421
+ let open = "";
33422
+ let close = "";
33423
+ for (const mark of marks) {
33424
+ if (mark.type === "link") {
33425
+ const href = mark.attrs?.href ?? "";
33426
+ open += `<a href="${this.escapeAttr(href)}">`;
33427
+ close = `</a>${close}`;
33428
+ } else {
33429
+ const tag = MARK_TO_TAG[mark.type];
33430
+ if (tag) {
33431
+ open += `<${tag}>`;
33432
+ close = `</${tag}>${close}`;
33433
+ }
33434
+ }
33435
+ }
33436
+ return `${open}${text}${close}`;
33437
+ }
33438
+ // --- lists ----------------------------------------------------------------
33439
+ listToHtml(node) {
33440
+ const { tag, attrs } = this.listTag(node);
33441
+ const items = (node.content ?? []).map((item) => this.listItemToHtml(item, node.type === "taskList")).join("");
33442
+ return `<${tag}${attrs}>${items}</${tag}>`;
33443
+ }
33444
+ listTag(node) {
33445
+ const start = node.attrs?.start;
33446
+ const startAttr = typeof start === "number" && start !== 1 ? ` start="${start}"` : "";
33447
+ switch (node.type) {
33448
+ case "orderedList":
33449
+ return { tag: "ol", attrs: startAttr };
33450
+ case "orderedListRoman":
33451
+ return { tag: "ol", attrs: ` type="I"${startAttr}` };
33452
+ case "orderedListRomanLower":
33453
+ return { tag: "ol", attrs: ` type="i"${startAttr}` };
33454
+ case "letteredList":
33455
+ return { tag: "ol", attrs: ` type="A"${startAttr}` };
33456
+ case "letteredListLower":
33457
+ return { tag: "ol", attrs: ` type="a"${startAttr}` };
33458
+ case "noBulletList":
33459
+ return { tag: "ul", attrs: ' style="list-style:none"' };
33460
+ case "taskList":
33461
+ case "bulletList":
33462
+ default:
33463
+ return { tag: "ul", attrs: "" };
33464
+ }
33465
+ }
33466
+ listItemToHtml(item, task) {
33467
+ const inner = (item.content ?? []).map((b) => {
33468
+ if (b.type === "paragraph") return this.inlineToHtml(b.content ?? []);
33469
+ return this.blockToHtml(b);
33470
+ }).join("");
33471
+ if (task) {
33472
+ const checked = item.attrs?.checked ? " checked" : "";
33473
+ return `<li><input type="checkbox"${checked}>${inner}</li>`;
33474
+ }
33475
+ return `<li>${inner}</li>`;
33476
+ }
33477
+ // --- images ---------------------------------------------------------------
33478
+ imageToHtml(node) {
33479
+ const attrs = node.attrs ?? {};
33480
+ const parts = [];
33481
+ const src = attrs.src;
33482
+ parts.push(`src="${this.escapeAttr(typeof src === "string" ? src : "")}"`);
33483
+ if (typeof attrs.alt === "string") parts.push(`alt="${this.escapeAttr(attrs.alt)}"`);
33484
+ if (typeof attrs.title === "string") parts.push(`title="${this.escapeAttr(attrs.title)}"`);
33485
+ if (attrs.width != null) parts.push(`width="${attrs.width}"`);
33486
+ if (attrs.height != null) parts.push(`height="${attrs.height}"`);
33487
+ if (typeof attrs.class === "string" && attrs.class) {
33488
+ parts.push(`class="${this.escapeAttr(attrs.class)}"`);
33489
+ }
33490
+ return `<img ${parts.join(" ")}>`;
33491
+ }
33492
+ // --- escaping -------------------------------------------------------------
33493
+ escapeText(text) {
33494
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
33495
+ }
33496
+ escapeAttr(text) {
33497
+ return this.escapeText(text).replace(/"/g, "&quot;");
33498
+ }
33499
+ };
33500
+
33041
33501
  // src/generator/json/JsonGenerator.ts
33042
33502
  var import_superenum33 = require("@ncoderz/superenum");
33043
33503
  var MOVE_BODY_RECURSION_LIMIT = 5e3;
@@ -37983,6 +38443,8 @@ function propertyContentProcessor(context, contentDepth, tagsConfig, content, ta
37983
38443
  jsonKey: void 0,
37984
38444
  exportJsonKey: void 0,
37985
38445
  hasExportJsonKey: false,
38446
+ htmlKey: void 0,
38447
+ hasHtmlKey: false,
37986
38448
  format: TagFormat.bitmarkText,
37987
38449
  values: void 0,
37988
38450
  defaultValue: void 0,
@@ -42380,6 +42842,499 @@ var BitmarkParser = class {
42380
42842
  }
42381
42843
  };
42382
42844
 
42845
+ // src/parser/html/HtmlDom.ts
42846
+ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
42847
+ "area",
42848
+ "base",
42849
+ "br",
42850
+ "col",
42851
+ "embed",
42852
+ "hr",
42853
+ "img",
42854
+ "input",
42855
+ "link",
42856
+ "meta",
42857
+ "param",
42858
+ "source",
42859
+ "track",
42860
+ "wbr"
42861
+ ]);
42862
+ var IMPLIED_CLOSE = {
42863
+ li: /* @__PURE__ */ new Set(["li"]),
42864
+ td: /* @__PURE__ */ new Set(["td", "th"]),
42865
+ th: /* @__PURE__ */ new Set(["td", "th"]),
42866
+ tr: /* @__PURE__ */ new Set(["td", "th", "tr"]),
42867
+ thead: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
42868
+ tbody: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
42869
+ tfoot: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
42870
+ p: /* @__PURE__ */ new Set(["p"]),
42871
+ option: /* @__PURE__ */ new Set(["option"])
42872
+ };
42873
+ var TAG_RE = /<(\/)?([a-zA-Z][a-zA-Z0-9-]*)((?:\s+(?:"[^"]*"|'[^']*'|[^<>"'])*)?)(\/)?>/g;
42874
+ var ATTR_RE = /([a-zA-Z_:][a-zA-Z0-9:._-]*)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s"'>]+))?/g;
42875
+ function parseAttrs(raw) {
42876
+ const attrs = {};
42877
+ if (!raw) return attrs;
42878
+ ATTR_RE.lastIndex = 0;
42879
+ let m;
42880
+ while ((m = ATTR_RE.exec(raw)) !== null) {
42881
+ const name = m[1].toLowerCase();
42882
+ let value = m[2] ?? "";
42883
+ if (value.length >= 2 && (value[0] === '"' || value[0] === "'")) {
42884
+ value = value.slice(1, -1);
42885
+ }
42886
+ attrs[name] = value;
42887
+ }
42888
+ return attrs;
42889
+ }
42890
+ function stripNonContent(html) {
42891
+ 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, "");
42892
+ }
42893
+ function tokenize(html) {
42894
+ const tokens = [];
42895
+ const clean = stripNonContent(html);
42896
+ TAG_RE.lastIndex = 0;
42897
+ let lastIndex = 0;
42898
+ let m;
42899
+ while ((m = TAG_RE.exec(clean)) !== null) {
42900
+ if (m.index > lastIndex) {
42901
+ tokens.push({ kind: "text", text: clean.slice(lastIndex, m.index) });
42902
+ }
42903
+ lastIndex = TAG_RE.lastIndex;
42904
+ const isClose = m[1] === "/";
42905
+ const name = m[2].toLowerCase();
42906
+ if (isClose) {
42907
+ tokens.push({ kind: "close", name });
42908
+ } else {
42909
+ tokens.push({
42910
+ kind: "open",
42911
+ name,
42912
+ attrs: parseAttrs(m[3]),
42913
+ selfClose: m[4] === "/"
42914
+ });
42915
+ }
42916
+ }
42917
+ if (lastIndex < clean.length) {
42918
+ tokens.push({ kind: "text", text: clean.slice(lastIndex) });
42919
+ }
42920
+ return tokens;
42921
+ }
42922
+ function parseHtml(html) {
42923
+ const root = { type: "element", name: "#root", attrs: {}, children: [] };
42924
+ const stack = [root];
42925
+ const top = () => stack[stack.length - 1];
42926
+ for (const token of tokenize(html)) {
42927
+ if (token.kind === "text") {
42928
+ if (token.text) top().children.push({ type: "text", value: token.text });
42929
+ continue;
42930
+ }
42931
+ if (token.kind === "open") {
42932
+ const name = token.name;
42933
+ const closes = IMPLIED_CLOSE[name];
42934
+ if (closes) {
42935
+ while (stack.length > 1 && closes.has(top().name)) stack.pop();
42936
+ }
42937
+ const el = {
42938
+ type: "element",
42939
+ name,
42940
+ attrs: token.attrs ?? {},
42941
+ children: []
42942
+ };
42943
+ top().children.push(el);
42944
+ if (!token.selfClose && !VOID_ELEMENTS.has(name)) {
42945
+ stack.push(el);
42946
+ }
42947
+ continue;
42948
+ }
42949
+ for (let i = stack.length - 1; i > 0; i--) {
42950
+ if (stack[i].name === token.name) {
42951
+ stack.length = i;
42952
+ break;
42953
+ }
42954
+ }
42955
+ }
42956
+ return root.children;
42957
+ }
42958
+ function childElements(el, names) {
42959
+ return el.children.filter((c) => c.type === "element" && names.has(c.name));
42960
+ }
42961
+
42962
+ // src/parser/html/HtmlTableParser.ts
42963
+ var MARK_TAGS = {
42964
+ b: "bold",
42965
+ strong: "bold",
42966
+ i: "italic",
42967
+ em: "italic",
42968
+ sup: "superscript",
42969
+ sub: "subscript",
42970
+ s: "strike",
42971
+ strike: "strike",
42972
+ del: "del",
42973
+ ins: "ins",
42974
+ u: "underline",
42975
+ mark: "highlight",
42976
+ code: "code"
42977
+ };
42978
+ var SECTION_TAGS = /* @__PURE__ */ new Set(["thead", "tbody", "tfoot"]);
42979
+ var ROW_TAGS = /* @__PURE__ */ new Set(["tr"]);
42980
+ var CELL_TAGS = /* @__PURE__ */ new Set(["td", "th"]);
42981
+ var LI_TAGS = /* @__PURE__ */ new Set(["li"]);
42982
+ var VALID_SCOPES = /* @__PURE__ */ new Set(["row", "col", "rowgroup", "colgroup"]);
42983
+ var NAMED_ENTITIES = {
42984
+ amp: "&",
42985
+ lt: "<",
42986
+ gt: ">",
42987
+ quot: '"',
42988
+ apos: "'",
42989
+ nbsp: "\xA0"
42990
+ };
42991
+ function decodeEntities(text) {
42992
+ return text.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z][a-zA-Z0-9]*);/g, (whole, body) => {
42993
+ if (body[0] === "#") {
42994
+ const code = body[1] === "x" || body[1] === "X" ? Number.parseInt(body.slice(2), 16) : Number.parseInt(body.slice(1), 10);
42995
+ if (Number.isFinite(code) && code >= 0 && code <= 1114111) {
42996
+ try {
42997
+ return String.fromCodePoint(code);
42998
+ } catch {
42999
+ return whole;
43000
+ }
43001
+ }
43002
+ return whole;
43003
+ }
43004
+ return NAMED_ENTITIES[body] ?? whole;
43005
+ });
43006
+ }
43007
+ function intAttr(value) {
43008
+ if (value == null) return void 0;
43009
+ const n = Number.parseInt(value, 10);
43010
+ return Number.isInteger(n) ? n : void 0;
43011
+ }
43012
+ function isElement(node) {
43013
+ return node.type === "element";
43014
+ }
43015
+ var HtmlTableParser = class {
43016
+ constructor() {
43017
+ __publicField(this, "keepUnknownTags", false);
43018
+ }
43019
+ /**
43020
+ * Parse an HTML string and return one table bit per top-level `<table>`.
43021
+ */
43022
+ parse(html, options) {
43023
+ this.keepUnknownTags = options?.keepUnknownTags ?? false;
43024
+ const tableFormat = options?.tableFormat ?? "table-extended";
43025
+ const onWarning = options?.onWarning;
43026
+ const tables = this.collectTopLevelTables(parseHtml(html));
43027
+ const bits = [];
43028
+ for (const table of tables) {
43029
+ const bit = this.tableToBit(table, tableFormat, onWarning);
43030
+ if (bit) bits.push(bit);
43031
+ }
43032
+ return bits;
43033
+ }
43034
+ // --- table extraction -----------------------------------------------------
43035
+ /** Collect every `<table>` element, NOT descending into nested tables. */
43036
+ collectTopLevelTables(nodes) {
43037
+ const tables = [];
43038
+ const visit = (node) => {
43039
+ if (!isElement(node)) return;
43040
+ if (node.name === "table") {
43041
+ tables.push(node);
43042
+ return;
43043
+ }
43044
+ node.children.forEach(visit);
43045
+ };
43046
+ nodes.forEach(visit);
43047
+ return tables;
43048
+ }
43049
+ tableToBit(table, tableFormat, onWarning) {
43050
+ const header = [];
43051
+ const body = [];
43052
+ const footer = [];
43053
+ let caption;
43054
+ for (const child of table.children) {
43055
+ if (!isElement(child)) continue;
43056
+ if (child.name === "caption") {
43057
+ const capContent = this.inlineNodes(child.children, []);
43058
+ const trimmed = this.trimInline(capContent);
43059
+ if (trimmed.length > 0) caption = trimmed;
43060
+ } else if (SECTION_TAGS.has(child.name)) {
43061
+ const target = child.name === "thead" ? header : child.name === "tfoot" ? footer : body;
43062
+ for (const tr of childElements(child, ROW_TAGS)) {
43063
+ target.push(this.rowToCells(tr));
43064
+ }
43065
+ } else if (ROW_TAGS.has(child.name)) {
43066
+ body.push(this.rowToCells(child));
43067
+ }
43068
+ }
43069
+ if (header.length === 0 && body.length === 0 && footer.length === 0) {
43070
+ return void 0;
43071
+ }
43072
+ const tableExtended = {};
43073
+ if (header.length > 0) tableExtended.header = { rows: header };
43074
+ if (body.length > 0) tableExtended.body = { rows: body };
43075
+ if (footer.length > 0) tableExtended.footer = { rows: footer };
43076
+ let tableData = tableExtended;
43077
+ if (tableFormat === "table") {
43078
+ if (this.isLossyAsBasic(tableExtended)) {
43079
+ onWarning?.(
43080
+ "Converting an HTML table to [.table] loses rowspan/colspan/scope and multi-section structure; use --tableFormat table-extended to preserve them."
43081
+ );
43082
+ }
43083
+ tableData = convertExtendedToBasicTableFormat(tableExtended);
43084
+ }
43085
+ const bit = {
43086
+ type: tableFormat,
43087
+ format: "bitmark++",
43088
+ table: tableData
43089
+ };
43090
+ if (caption) bit.caption = caption;
43091
+ return bit;
43092
+ }
43093
+ rowToCells(tr) {
43094
+ const cells = [];
43095
+ for (const cell of childElements(tr, CELL_TAGS)) {
43096
+ cells.push(this.cellToJson(cell));
43097
+ }
43098
+ return { cells };
43099
+ }
43100
+ cellToJson(cell) {
43101
+ const json = {
43102
+ content: this.blockNodes(cell.children)
43103
+ };
43104
+ if (cell.name === "th") json.title = true;
43105
+ const rowspan = intAttr(cell.attrs.rowspan);
43106
+ if (rowspan != null && rowspan >= 2) json.rowspan = rowspan;
43107
+ const colspan = intAttr(cell.attrs.colspan);
43108
+ if (colspan != null && colspan >= 2) json.colspan = colspan;
43109
+ const scope = cell.attrs.scope?.toLowerCase();
43110
+ if (scope && VALID_SCOPES.has(scope)) {
43111
+ json.scope = scope;
43112
+ }
43113
+ const width = this.widthFromCell(cell);
43114
+ if (width != null) json.colwidth = width;
43115
+ return json;
43116
+ }
43117
+ widthFromCell(cell) {
43118
+ const attrWidth = intAttr(cell.attrs.width);
43119
+ if (attrWidth != null && attrWidth > 0) return attrWidth;
43120
+ const style = cell.attrs.style;
43121
+ if (style) {
43122
+ const m = style.match(/width\s*:\s*(\d+)\s*px/i);
43123
+ if (m) {
43124
+ const n = Number.parseInt(m[1], 10);
43125
+ if (Number.isInteger(n) && n > 0) return n;
43126
+ }
43127
+ }
43128
+ return void 0;
43129
+ }
43130
+ isLossyAsBasic(table) {
43131
+ if (table.footer) return true;
43132
+ if (table.header && table.header.rows.length > 1) return true;
43133
+ const sections = [table.header, table.body, table.footer];
43134
+ for (const section of sections) {
43135
+ if (!section) continue;
43136
+ for (const row of section.rows) {
43137
+ for (const cell of row.cells) {
43138
+ if (cell.rowspan || cell.colspan || cell.scope) return true;
43139
+ }
43140
+ }
43141
+ }
43142
+ return false;
43143
+ }
43144
+ // --- content conversion (HTML -> TextAst) ---------------------------------
43145
+ /**
43146
+ * Convert a cell/li's child nodes into block-level TextAst nodes (paragraphs, lists, images).
43147
+ */
43148
+ blockNodes(nodes) {
43149
+ const blocks = [];
43150
+ let inline = [];
43151
+ const flush = () => {
43152
+ const trimmed = this.trimInline(inline);
43153
+ inline = [];
43154
+ if (trimmed.length === 0) return;
43155
+ if (trimmed.length === 1 && trimmed[0].type === "imageInline") {
43156
+ blocks.push({ ...trimmed[0], type: "image" });
43157
+ } else {
43158
+ blocks.push({ type: "paragraph", content: trimmed, attrs: {} });
43159
+ }
43160
+ };
43161
+ for (const node of nodes) {
43162
+ if (!isElement(node)) {
43163
+ inline.push(...this.inlineText(node.value, []));
43164
+ continue;
43165
+ }
43166
+ const name = node.name;
43167
+ if (name === "p") {
43168
+ flush();
43169
+ const content = this.trimInline(this.inlineNodes(node.children, []));
43170
+ if (content.length > 0) {
43171
+ blocks.push({ type: "paragraph", content, attrs: {} });
43172
+ }
43173
+ } else if (this.isListTag(name)) {
43174
+ flush();
43175
+ const list = this.listNode(node);
43176
+ if (list) blocks.push(list);
43177
+ } else {
43178
+ inline.push(...this.inlineFromElement(node, []));
43179
+ }
43180
+ }
43181
+ flush();
43182
+ return blocks;
43183
+ }
43184
+ /** Convert child nodes to a flat list of inline TextNodes, applying the given marks. */
43185
+ inlineNodes(nodes, marks) {
43186
+ const out = [];
43187
+ for (const node of nodes) {
43188
+ if (!isElement(node)) {
43189
+ out.push(...this.inlineText(node.value, marks));
43190
+ } else {
43191
+ out.push(...this.inlineFromElement(node, marks));
43192
+ }
43193
+ }
43194
+ return out;
43195
+ }
43196
+ inlineFromElement(el, marks) {
43197
+ const name = el.name;
43198
+ if (name === "br") {
43199
+ return [{ type: "hardBreak" }];
43200
+ }
43201
+ if (name === "img") {
43202
+ return [this.imageNode(el, true)];
43203
+ }
43204
+ const markType = MARK_TAGS[name];
43205
+ if (markType) {
43206
+ return this.inlineNodes(el.children, [...marks, { type: markType }]);
43207
+ }
43208
+ if (name === "a") {
43209
+ const linkMark = {
43210
+ type: "link",
43211
+ attrs: {
43212
+ href: el.attrs.href ?? "",
43213
+ ...el.attrs.target ? { target: el.attrs.target } : {}
43214
+ }
43215
+ };
43216
+ return this.inlineNodes(el.children, [...marks, linkMark]);
43217
+ }
43218
+ if (this.keepUnknownTags) {
43219
+ const open = this.serializeOpenTag(el);
43220
+ const close = `</${name}>`;
43221
+ return [
43222
+ ...this.inlineText(open, marks),
43223
+ ...this.inlineNodes(el.children, marks),
43224
+ ...this.inlineText(close, marks)
43225
+ ];
43226
+ }
43227
+ return this.inlineNodes(el.children, marks);
43228
+ }
43229
+ inlineText(raw, marks) {
43230
+ const text = decodeEntities(raw).replace(/\s+/g, " ");
43231
+ if (text === "") return [];
43232
+ const node = { text, type: "text" };
43233
+ if (marks.length > 0) node.marks = marks.map((m) => ({ ...m }));
43234
+ return [node];
43235
+ }
43236
+ serializeOpenTag(el) {
43237
+ const attrs = Object.entries(el.attrs).map(([k, v]) => v === "" ? ` ${k}` : ` ${k}="${v}"`).join("");
43238
+ return `<${el.name}${attrs}>`;
43239
+ }
43240
+ // --- lists ----------------------------------------------------------------
43241
+ isListTag(name) {
43242
+ return name === "ul" || name === "ol";
43243
+ }
43244
+ listNode(el) {
43245
+ const items = childElements(el, LI_TAGS);
43246
+ if (items.length === 0) return void 0;
43247
+ const isTask = el.name === "ul" && items.some((li) => {
43248
+ const firstEl = li.children.find(isElement);
43249
+ return firstEl?.name === "input" && firstEl.attrs.type?.toLowerCase() === "checkbox";
43250
+ });
43251
+ if (isTask) {
43252
+ return {
43253
+ type: "taskList",
43254
+ content: items.map((li) => this.taskItemNode(li))
43255
+ };
43256
+ }
43257
+ const type = this.listType(el);
43258
+ const node = {
43259
+ type,
43260
+ content: items.map((li) => this.listItemNode(li))
43261
+ };
43262
+ if (el.name === "ol") {
43263
+ const start = intAttr(el.attrs.start);
43264
+ if (start != null) {
43265
+ node.attrs = { start };
43266
+ }
43267
+ }
43268
+ return node;
43269
+ }
43270
+ listType(el) {
43271
+ if (el.name === "ol") {
43272
+ switch (el.attrs.type) {
43273
+ case "i":
43274
+ return "orderedListRomanLower";
43275
+ case "I":
43276
+ return "orderedListRoman";
43277
+ case "a":
43278
+ return "letteredListLower";
43279
+ case "A":
43280
+ return "letteredList";
43281
+ default:
43282
+ return "orderedList";
43283
+ }
43284
+ }
43285
+ const style = el.attrs.style ?? "";
43286
+ if (/list-style(-type)?\s*:\s*none/i.test(style)) return "noBulletList";
43287
+ return "bulletList";
43288
+ }
43289
+ listItemNode(li) {
43290
+ let content = this.blockNodes(li.children);
43291
+ if (content.length === 0) {
43292
+ content = [{ type: "paragraph", content: [], attrs: {} }];
43293
+ }
43294
+ return { type: "listItem", content };
43295
+ }
43296
+ taskItemNode(li) {
43297
+ const checkbox = li.children.find(
43298
+ (c) => isElement(c) && c.name === "input" && c.attrs.type?.toLowerCase() === "checkbox"
43299
+ );
43300
+ const checked = checkbox ? "checked" in checkbox.attrs : false;
43301
+ const rest = li.children.filter((c) => c !== checkbox);
43302
+ let content = this.blockNodes(rest);
43303
+ if (content.length === 0) {
43304
+ content = [{ type: "paragraph", content: [], attrs: {} }];
43305
+ }
43306
+ return { type: "taskItem", attrs: { checked }, content };
43307
+ }
43308
+ // --- images ---------------------------------------------------------------
43309
+ imageNode(el, inline) {
43310
+ const attrs = { src: el.attrs.src ?? "" };
43311
+ attrs.alt = el.attrs.alt ?? null;
43312
+ attrs.title = el.attrs.title ?? null;
43313
+ const width = intAttr(el.attrs.width);
43314
+ if (width != null) attrs.width = width;
43315
+ const height = intAttr(el.attrs.height);
43316
+ if (height != null) attrs.height = height;
43317
+ if (el.attrs.class) attrs.class = el.attrs.class;
43318
+ return { type: inline ? "imageInline" : "image", attrs };
43319
+ }
43320
+ // --- whitespace -----------------------------------------------------------
43321
+ /** Trim leading/trailing whitespace from inline content (edges only). */
43322
+ trimInline(nodes) {
43323
+ const out = nodes.slice();
43324
+ const isWs = (n) => n.type === "text" && /^\s*$/.test(n.text ?? "");
43325
+ while (out.length > 0 && isWs(out[0])) out.shift();
43326
+ if (out.length > 0 && out[0].type === "text") {
43327
+ out[0] = { ...out[0], text: (out[0].text ?? "").replace(/^\s+/, "") };
43328
+ }
43329
+ while (out.length > 0 && isWs(out[out.length - 1])) out.pop();
43330
+ if (out.length > 0 && out[out.length - 1].type === "text") {
43331
+ const last = out.length - 1;
43332
+ out[last] = { ...out[last], text: (out[last].text ?? "").replace(/\s+$/, "") };
43333
+ }
43334
+ return out.filter((n) => !(n.type === "text" && n.text === ""));
43335
+ }
43336
+ };
43337
+
42383
43338
  // src/BitmarkParserGenerator.ts
42384
43339
  var import_node_path4 = __toESM(require("path"), 1);
42385
43340
  var import_fs_extra4 = __toESM(require("fs-extra"), 1);
@@ -42657,248 +43612,19 @@ var BitmarkFileGenerator = class {
42657
43612
  *
42658
43613
  * @param ast bitmark AST
42659
43614
  */
42660
- async generate(ast) {
42661
- return this.generator.generate(ast);
42662
- }
42663
- /**
42664
- * Generate bitmark markup from bitmark AST as a file synchronously
42665
- *
42666
- * @param ast bitmark AST
42667
- */
42668
- generateSync(_ast) {
42669
- if (this.async) {
42670
- throw new Error("Sync operation not supported");
42671
- }
42672
- this.generator.generateSync(_ast);
42673
- }
42674
- };
42675
-
42676
- // src/generator/html/HtmlTableGenerator.ts
42677
- var MARK_TO_TAG = {
42678
- bold: "b",
42679
- italic: "i",
42680
- superscript: "sup",
42681
- subscript: "sub",
42682
- strike: "s",
42683
- del: "del",
42684
- ins: "ins",
42685
- underline: "u",
42686
- highlight: "mark",
42687
- code: "code"
42688
- };
42689
- var HtmlTableGenerator = class {
42690
- constructor() {
42691
- __publicField(this, "indentUnit", " ");
42692
- }
42693
- /**
42694
- * Generate HTML table fragments from a string or JSON value.
42695
- * @returns the concatenated `<table>` fragments, blank-line separated (empty string if none).
42696
- */
42697
- generate(input) {
42698
- let data = input;
42699
- if (typeof data === "string") {
42700
- try {
42701
- data = JSON.parse(data);
42702
- } catch {
42703
- return "";
42704
- }
42705
- }
42706
- const bits = this.collectBits(data);
42707
- const fragments = [];
42708
- for (const bit of bits) {
42709
- const html = this.renderTableBit(bit);
42710
- if (html) fragments.push(html);
42711
- }
42712
- return fragments.join("\n\n");
42713
- }
42714
- // --- bit collection -------------------------------------------------------
42715
- collectBits(data) {
42716
- const out = [];
42717
- const visit = (value) => {
42718
- if (value == null || typeof value !== "object") return;
42719
- if (Array.isArray(value)) {
42720
- value.forEach(visit);
42721
- return;
42722
- }
42723
- const obj = value;
42724
- if ("bit" in obj && obj.bit && typeof obj.bit === "object") {
42725
- out.push(obj.bit);
42726
- } else if ("type" in obj) {
42727
- out.push(obj);
42728
- }
42729
- };
42730
- visit(data);
42731
- return out;
42732
- }
42733
- // --- table rendering ------------------------------------------------------
42734
- renderTableBit(bit) {
42735
- const table = bit.table;
42736
- if (!table) return "";
42737
- if (bit.type !== "table" && bit.type !== "table-extended") return "";
42738
- const extended = this.toExtended(table);
42739
- const lines = [];
42740
- lines.push("<table>");
42741
- if (bit.caption != null) {
42742
- const caption = this.cellContentToHtml(this.asTextAst(bit.caption));
42743
- if (caption) lines.push(`${this.indentUnit}<caption>${caption}</caption>`);
42744
- }
42745
- this.renderSection(lines, "thead", extended.header, "header");
42746
- this.renderSection(lines, "tbody", extended.body, "body");
42747
- this.renderSection(lines, "tfoot", extended.footer, "footer");
42748
- lines.push("</table>");
42749
- return lines.join("\n");
42750
- }
42751
- toExtended(table) {
42752
- const t = table;
42753
- if (t.header || t.body || t.footer) return table;
42754
- return convertBasicToExtendedTableFormat(table);
42755
- }
42756
- renderSection(lines, tag, section, key) {
42757
- if (!section || !section.rows || section.rows.length === 0) return;
42758
- lines.push(`${this.indentUnit}<${tag}>`);
42759
- for (const row of section.rows) {
42760
- lines.push(`${this.indentUnit.repeat(2)}<tr>`);
42761
- for (const cell of row.cells ?? []) {
42762
- lines.push(`${this.indentUnit.repeat(3)}${this.renderCell(cell, key)}`);
42763
- }
42764
- lines.push(`${this.indentUnit.repeat(2)}</tr>`);
42765
- }
42766
- lines.push(`${this.indentUnit}</${tag}>`);
42767
- }
42768
- renderCell(cell, _key) {
42769
- const tag = cell.title === true ? "th" : "td";
42770
- const attrs = [];
42771
- if (cell.rowspan && cell.rowspan > 1) attrs.push(`rowspan="${cell.rowspan}"`);
42772
- if (cell.colspan && cell.colspan > 1) attrs.push(`colspan="${cell.colspan}"`);
42773
- if (cell.scope) attrs.push(`scope="${cell.scope}"`);
42774
- if (cell.colwidth && cell.colwidth > 0) attrs.push(`width="${cell.colwidth}"`);
42775
- const open = attrs.length > 0 ? `<${tag} ${attrs.join(" ")}>` : `<${tag}>`;
42776
- return `${open}${this.cellContentToHtml(this.asTextAst(cell.content))}</${tag}>`;
42777
- }
42778
- // --- cell content (TextAst -> HTML) ---------------------------------------
42779
- asTextAst(content) {
42780
- if (content == null) return [];
42781
- if (typeof content === "string") return [{ type: "text", text: content }];
42782
- return content;
42783
- }
42784
- cellContentToHtml(blocks) {
42785
- if (blocks.length === 0) return "";
42786
- if (blocks.length === 1 && blocks[0].type === "paragraph") {
42787
- return this.inlineToHtml(blocks[0].content ?? []);
42788
- }
42789
- return blocks.map((b) => this.blockToHtml(b)).join("");
42790
- }
42791
- blockToHtml(node) {
42792
- switch (node.type) {
42793
- case "paragraph":
42794
- return `<p>${this.inlineToHtml(node.content ?? [])}</p>`;
42795
- case "bulletList":
42796
- case "noBulletList":
42797
- case "orderedList":
42798
- case "orderedListRoman":
42799
- case "orderedListRomanLower":
42800
- case "letteredList":
42801
- case "letteredListLower":
42802
- case "taskList":
42803
- return this.listToHtml(node);
42804
- case "image":
42805
- case "imageInline":
42806
- return this.imageToHtml(node);
42807
- default:
42808
- return this.inlineToHtml([node]);
42809
- }
42810
- }
42811
- inlineToHtml(nodes) {
42812
- return nodes.map((n) => this.inlineNodeToHtml(n)).join("");
42813
- }
42814
- inlineNodeToHtml(node) {
42815
- if (node.type === "hardBreak") return "<br>";
42816
- if (node.type === "image" || node.type === "imageInline") return this.imageToHtml(node);
42817
- if (node.type === "text") {
42818
- return this.wrapMarks(this.escapeText(node.text ?? ""), node.marks);
42819
- }
42820
- if (node.content) return this.inlineToHtml(node.content);
42821
- return this.escapeText(node.text ?? "");
42822
- }
42823
- wrapMarks(text, marks) {
42824
- if (!marks || marks.length === 0) return text;
42825
- let open = "";
42826
- let close = "";
42827
- for (const mark of marks) {
42828
- if (mark.type === "link") {
42829
- const href = mark.attrs?.href ?? "";
42830
- open += `<a href="${this.escapeAttr(href)}">`;
42831
- close = `</a>${close}`;
42832
- } else {
42833
- const tag = MARK_TO_TAG[mark.type];
42834
- if (tag) {
42835
- open += `<${tag}>`;
42836
- close = `</${tag}>${close}`;
42837
- }
42838
- }
42839
- }
42840
- return `${open}${text}${close}`;
42841
- }
42842
- // --- lists ----------------------------------------------------------------
42843
- listToHtml(node) {
42844
- const { tag, attrs } = this.listTag(node);
42845
- const items = (node.content ?? []).map((item) => this.listItemToHtml(item, node.type === "taskList")).join("");
42846
- return `<${tag}${attrs}>${items}</${tag}>`;
42847
- }
42848
- listTag(node) {
42849
- const start = node.attrs?.start;
42850
- const startAttr = typeof start === "number" && start !== 1 ? ` start="${start}"` : "";
42851
- switch (node.type) {
42852
- case "orderedList":
42853
- return { tag: "ol", attrs: startAttr };
42854
- case "orderedListRoman":
42855
- return { tag: "ol", attrs: ` type="I"${startAttr}` };
42856
- case "orderedListRomanLower":
42857
- return { tag: "ol", attrs: ` type="i"${startAttr}` };
42858
- case "letteredList":
42859
- return { tag: "ol", attrs: ` type="A"${startAttr}` };
42860
- case "letteredListLower":
42861
- return { tag: "ol", attrs: ` type="a"${startAttr}` };
42862
- case "noBulletList":
42863
- return { tag: "ul", attrs: ' style="list-style:none"' };
42864
- case "taskList":
42865
- case "bulletList":
42866
- default:
42867
- return { tag: "ul", attrs: "" };
42868
- }
42869
- }
42870
- listItemToHtml(item, task) {
42871
- const inner = (item.content ?? []).map((b) => {
42872
- if (b.type === "paragraph") return this.inlineToHtml(b.content ?? []);
42873
- return this.blockToHtml(b);
42874
- }).join("");
42875
- if (task) {
42876
- const checked = item.attrs?.checked ? " checked" : "";
42877
- return `<li><input type="checkbox"${checked}>${inner}</li>`;
42878
- }
42879
- return `<li>${inner}</li>`;
42880
- }
42881
- // --- images ---------------------------------------------------------------
42882
- imageToHtml(node) {
42883
- const attrs = node.attrs ?? {};
42884
- const parts = [];
42885
- const src = attrs.src;
42886
- parts.push(`src="${this.escapeAttr(typeof src === "string" ? src : "")}"`);
42887
- if (typeof attrs.alt === "string") parts.push(`alt="${this.escapeAttr(attrs.alt)}"`);
42888
- if (typeof attrs.title === "string") parts.push(`title="${this.escapeAttr(attrs.title)}"`);
42889
- if (attrs.width != null) parts.push(`width="${attrs.width}"`);
42890
- if (attrs.height != null) parts.push(`height="${attrs.height}"`);
42891
- if (typeof attrs.class === "string" && attrs.class) {
42892
- parts.push(`class="${this.escapeAttr(attrs.class)}"`);
42893
- }
42894
- return `<img ${parts.join(" ")}>`;
42895
- }
42896
- // --- escaping -------------------------------------------------------------
42897
- escapeText(text) {
42898
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
43615
+ async generate(ast) {
43616
+ return this.generator.generate(ast);
42899
43617
  }
42900
- escapeAttr(text) {
42901
- return this.escapeText(text).replace(/"/g, "&quot;");
43618
+ /**
43619
+ * Generate bitmark markup from bitmark AST as a file synchronously
43620
+ *
43621
+ * @param ast bitmark AST
43622
+ */
43623
+ generateSync(_ast) {
43624
+ if (this.async) {
43625
+ throw new Error("Sync operation not supported");
43626
+ }
43627
+ this.generator.generateSync(_ast);
42902
43628
  }
42903
43629
  };
42904
43630
 
@@ -43325,6 +44051,7 @@ var ConfigBuilder = class {
43325
44051
  k = stringUtils.camelToKebab(k);
43326
44052
  const resolvedGroups = resolveGroupReferences(k);
43327
44053
  const hasOuterExport = Object.prototype.hasOwnProperty.call(tag, "exportJsonKey");
44054
+ const hasOuterHtml = Object.prototype.hasOwnProperty.call(tag, "htmlKey");
43328
44055
  if (!hasOuterExport && tag.jsonKey != null) {
43329
44056
  const headingPath = [...pathStack, `tags.${tag.key}`].join(" / ");
43330
44057
  exportJsonKeyErrors.push(
@@ -43334,6 +44061,8 @@ var ConfigBuilder = class {
43334
44061
  for (const ref of resolvedGroups) {
43335
44062
  const exportJsonKeyChosen = hasOuterExport ? tag.exportJsonKey : ref.exportJsonKey;
43336
44063
  const hasExportChosen = hasOuterExport || !!ref.hasExportJsonKey;
44064
+ const htmlKeyChosen = hasOuterHtml ? tag.htmlKey : ref.htmlKey;
44065
+ const hasHtmlChosen = hasOuterHtml || !!ref.hasHtmlKey;
43337
44066
  const min = tag.minCount != null ? tag.minCount : ref.min;
43338
44067
  const max = tag.maxCount != null ? tag.maxCount : ref.max;
43339
44068
  const description = tag.description ? tag.description : ref.description;
@@ -43341,6 +44070,7 @@ var ConfigBuilder = class {
43341
44070
  type: "group",
43342
44071
  key: ref.key,
43343
44072
  ...hasExportChosen ? { jsonKey: exportJsonKeyChosen } : {},
44073
+ ...hasHtmlChosen ? { htmlKey: htmlKeyChosen } : {},
43344
44074
  ...min != null ? { min } : {},
43345
44075
  ...max != null ? { max } : {},
43346
44076
  ...description ? { description } : {}
@@ -43369,10 +44099,13 @@ var ConfigBuilder = class {
43369
44099
  );
43370
44100
  exportJsonKeyField = {};
43371
44101
  }
44102
+ const hasHtml = Object.prototype.hasOwnProperty.call(tag, "htmlKey");
44103
+ const htmlKeyField = hasHtml ? { htmlKey: tag.htmlKey } : {};
43372
44104
  const t = {
43373
44105
  type: "tag",
43374
44106
  key: tagName,
43375
44107
  ...exportJsonKeyField,
44108
+ ...htmlKeyField,
43376
44109
  format,
43377
44110
  default: tag.defaultValue ?? null,
43378
44111
  ...tag.nullable ? { nullable: true } : {},
@@ -43395,6 +44128,13 @@ var ConfigBuilder = class {
43395
44128
  );
43396
44129
  return {};
43397
44130
  };
44131
+ const cardHtmlKeyField = (container, htmlExportKey) => {
44132
+ const c = container;
44133
+ if (Object.prototype.hasOwnProperty.call(c, htmlExportKey)) {
44134
+ return { htmlKey: c[htmlExportKey] };
44135
+ }
44136
+ return {};
44137
+ };
43398
44138
  const serializeCardSet = (cardSetKey) => {
43399
44139
  const variantBodyFormat = (variant) => variant.format ?? TextFormat.bitmarkText;
43400
44140
  const cardSetConfig = CARDSETS[cardSetKey];
@@ -43425,6 +44165,7 @@ var ConfigBuilder = class {
43425
44165
  }
43426
44166
  return {
43427
44167
  ...cardJsonKeyField(variant, "jsonKey", "exportJsonKey", variantPath),
44168
+ ...cardHtmlKeyField(variant, "htmlKey"),
43428
44169
  format: variantBodyFormat(variant),
43429
44170
  tags: variantTags,
43430
44171
  repeatCount: variant.repeatCount ?? 1,
@@ -43436,6 +44177,7 @@ var ConfigBuilder = class {
43436
44177
  name: side.name,
43437
44178
  ...side.repeat ? { repeat: side.repeat } : {},
43438
44179
  ...cardJsonKeyField(side, "jsonKey", "exportJsonKey", sidePath),
44180
+ ...cardHtmlKeyField(side, "htmlKey"),
43439
44181
  variants
43440
44182
  };
43441
44183
  });
@@ -43443,20 +44185,23 @@ var ConfigBuilder = class {
43443
44185
  const cards = Object.entries(cardSetConfig.sections).map(([sectionName, section]) => {
43444
44186
  const sectionPath = `cardSets.${normalizedKey} / cards.${sectionName}`;
43445
44187
  const hasSideExport = Object.prototype.hasOwnProperty.call(section, "sideExportJsonKey");
44188
+ const hasSideHtml = Object.prototype.hasOwnProperty.call(section, "sideHtmlKey");
43446
44189
  let cardSides = sides;
43447
- if (hasSideExport || section.sideJsonKey != null) {
44190
+ if (hasSideExport || section.sideJsonKey != null || hasSideHtml) {
43448
44191
  const sideOverride = cardJsonKeyField(
43449
44192
  section,
43450
44193
  "sideJsonKey",
43451
44194
  "sideExportJsonKey",
43452
44195
  `${sectionPath} / sides.*`
43453
44196
  );
43454
- cardSides = sides.map((s) => ({ ...s, ...sideOverride }));
44197
+ const sideHtmlOverride = cardHtmlKeyField(section, "sideHtmlKey");
44198
+ cardSides = sides.map((s) => ({ ...s, ...sideOverride, ...sideHtmlOverride }));
43455
44199
  }
43456
44200
  return {
43457
44201
  name: sectionName,
43458
44202
  ...section.isDefault ? { isDefault: true } : {},
43459
44203
  ...cardJsonKeyField(section, "jsonKey", "exportJsonKey", sectionPath),
44204
+ ...cardHtmlKeyField(section, "htmlKey"),
43460
44205
  // PLAN-085: per-section cardinality. Emit only when non-default
43461
44206
  // (treat `0` / undefined as "unbounded — omit").
43462
44207
  ...section.minCount != null && section.minCount !== 0 ? { min: section.minCount } : {},
@@ -43464,7 +44209,7 @@ var ConfigBuilder = class {
43464
44209
  sides: cardSides
43465
44210
  };
43466
44211
  });
43467
- return { name: normalizedKey, cards };
44212
+ return { name: normalizedKey, ...cardHtmlKeyField(cardSetConfig, "htmlKey"), cards };
43468
44213
  }
43469
44214
  const cardSetPath = `cardSets.${normalizedKey} / cards.default`;
43470
44215
  return {
@@ -43474,6 +44219,7 @@ var ConfigBuilder = class {
43474
44219
  name: "default",
43475
44220
  isDefault: true,
43476
44221
  ...cardJsonKeyField(cardSetConfig, "jsonKey", "exportJsonKey", cardSetPath),
44222
+ ...cardHtmlKeyField(cardSetConfig, "htmlKey"),
43477
44223
  sides
43478
44224
  }
43479
44225
  ]
@@ -43513,6 +44259,10 @@ var ConfigBuilder = class {
43513
44259
  ref.exportJsonKey = t.jsonKey;
43514
44260
  ref.hasExportJsonKey = true;
43515
44261
  }
44262
+ if (Object.prototype.hasOwnProperty.call(t, "htmlKey")) {
44263
+ ref.htmlKey = t.htmlKey;
44264
+ ref.hasHtmlKey = true;
44265
+ }
43516
44266
  replacements.push(ref);
43517
44267
  }
43518
44268
  squashedGroups.set(groupKey, replacements);
@@ -43547,6 +44297,7 @@ var ConfigBuilder = class {
43547
44297
  type: "group",
43548
44298
  key: ref.key,
43549
44299
  ...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
44300
+ ...ref.hasHtmlKey ? { htmlKey: ref.htmlKey } : {},
43550
44301
  ...ref.min != null ? { min: ref.min } : {},
43551
44302
  ...ref.max != null ? { max: ref.max } : {},
43552
44303
  ...ref.description ? { description: ref.description } : {}
@@ -43560,6 +44311,7 @@ var ConfigBuilder = class {
43560
44311
  type: "group",
43561
44312
  key: ref.key,
43562
44313
  ...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
44314
+ ...ref.hasHtmlKey ? { htmlKey: ref.htmlKey } : {},
43563
44315
  ...ref.min != null ? { min: ref.min } : {},
43564
44316
  ...ref.max != null ? { max: ref.max } : {},
43565
44317
  ...ref.description ? { description: ref.description } : {}
@@ -43689,6 +44441,7 @@ var ConfigBuilder = class {
43689
44441
  type: "group",
43690
44442
  key: ref.key,
43691
44443
  ...ref.hasExportJsonKey ? { jsonKey: ref.exportJsonKey } : {},
44444
+ ...ref.hasHtmlKey ? { htmlKey: ref.htmlKey } : {},
43692
44445
  ...ref.min != null ? { min: ref.min } : {},
43693
44446
  ...ref.max != null ? { max: ref.max } : {},
43694
44447
  ...ref.description ? { description: ref.description } : {}
@@ -43878,499 +44631,6 @@ var ConfigBuilder = class {
43878
44631
  }
43879
44632
  };
43880
44633
 
43881
- // src/parser/html/HtmlDom.ts
43882
- var VOID_ELEMENTS = /* @__PURE__ */ new Set([
43883
- "area",
43884
- "base",
43885
- "br",
43886
- "col",
43887
- "embed",
43888
- "hr",
43889
- "img",
43890
- "input",
43891
- "link",
43892
- "meta",
43893
- "param",
43894
- "source",
43895
- "track",
43896
- "wbr"
43897
- ]);
43898
- var IMPLIED_CLOSE = {
43899
- li: /* @__PURE__ */ new Set(["li"]),
43900
- td: /* @__PURE__ */ new Set(["td", "th"]),
43901
- th: /* @__PURE__ */ new Set(["td", "th"]),
43902
- tr: /* @__PURE__ */ new Set(["td", "th", "tr"]),
43903
- thead: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
43904
- tbody: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
43905
- tfoot: /* @__PURE__ */ new Set(["td", "th", "tr", "thead", "tbody", "tfoot"]),
43906
- p: /* @__PURE__ */ new Set(["p"]),
43907
- option: /* @__PURE__ */ new Set(["option"])
43908
- };
43909
- var TAG_RE = /<(\/)?([a-zA-Z][a-zA-Z0-9-]*)((?:\s+(?:"[^"]*"|'[^']*'|[^<>"'])*)?)(\/)?>/g;
43910
- var ATTR_RE = /([a-zA-Z_:][a-zA-Z0-9:._-]*)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s"'>]+))?/g;
43911
- function parseAttrs(raw) {
43912
- const attrs = {};
43913
- if (!raw) return attrs;
43914
- ATTR_RE.lastIndex = 0;
43915
- let m;
43916
- while ((m = ATTR_RE.exec(raw)) !== null) {
43917
- const name = m[1].toLowerCase();
43918
- let value = m[2] ?? "";
43919
- if (value.length >= 2 && (value[0] === '"' || value[0] === "'")) {
43920
- value = value.slice(1, -1);
43921
- }
43922
- attrs[name] = value;
43923
- }
43924
- return attrs;
43925
- }
43926
- function stripNonContent(html) {
43927
- 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, "");
43928
- }
43929
- function tokenize(html) {
43930
- const tokens = [];
43931
- const clean = stripNonContent(html);
43932
- TAG_RE.lastIndex = 0;
43933
- let lastIndex = 0;
43934
- let m;
43935
- while ((m = TAG_RE.exec(clean)) !== null) {
43936
- if (m.index > lastIndex) {
43937
- tokens.push({ kind: "text", text: clean.slice(lastIndex, m.index) });
43938
- }
43939
- lastIndex = TAG_RE.lastIndex;
43940
- const isClose = m[1] === "/";
43941
- const name = m[2].toLowerCase();
43942
- if (isClose) {
43943
- tokens.push({ kind: "close", name });
43944
- } else {
43945
- tokens.push({
43946
- kind: "open",
43947
- name,
43948
- attrs: parseAttrs(m[3]),
43949
- selfClose: m[4] === "/"
43950
- });
43951
- }
43952
- }
43953
- if (lastIndex < clean.length) {
43954
- tokens.push({ kind: "text", text: clean.slice(lastIndex) });
43955
- }
43956
- return tokens;
43957
- }
43958
- function parseHtml(html) {
43959
- const root = { type: "element", name: "#root", attrs: {}, children: [] };
43960
- const stack = [root];
43961
- const top = () => stack[stack.length - 1];
43962
- for (const token of tokenize(html)) {
43963
- if (token.kind === "text") {
43964
- if (token.text) top().children.push({ type: "text", value: token.text });
43965
- continue;
43966
- }
43967
- if (token.kind === "open") {
43968
- const name = token.name;
43969
- const closes = IMPLIED_CLOSE[name];
43970
- if (closes) {
43971
- while (stack.length > 1 && closes.has(top().name)) stack.pop();
43972
- }
43973
- const el = {
43974
- type: "element",
43975
- name,
43976
- attrs: token.attrs ?? {},
43977
- children: []
43978
- };
43979
- top().children.push(el);
43980
- if (!token.selfClose && !VOID_ELEMENTS.has(name)) {
43981
- stack.push(el);
43982
- }
43983
- continue;
43984
- }
43985
- for (let i = stack.length - 1; i > 0; i--) {
43986
- if (stack[i].name === token.name) {
43987
- stack.length = i;
43988
- break;
43989
- }
43990
- }
43991
- }
43992
- return root.children;
43993
- }
43994
- function childElements(el, names) {
43995
- return el.children.filter((c) => c.type === "element" && names.has(c.name));
43996
- }
43997
-
43998
- // src/parser/html/HtmlTableParser.ts
43999
- var MARK_TAGS = {
44000
- b: "bold",
44001
- strong: "bold",
44002
- i: "italic",
44003
- em: "italic",
44004
- sup: "superscript",
44005
- sub: "subscript",
44006
- s: "strike",
44007
- strike: "strike",
44008
- del: "del",
44009
- ins: "ins",
44010
- u: "underline",
44011
- mark: "highlight",
44012
- code: "code"
44013
- };
44014
- var SECTION_TAGS = /* @__PURE__ */ new Set(["thead", "tbody", "tfoot"]);
44015
- var ROW_TAGS = /* @__PURE__ */ new Set(["tr"]);
44016
- var CELL_TAGS = /* @__PURE__ */ new Set(["td", "th"]);
44017
- var LI_TAGS = /* @__PURE__ */ new Set(["li"]);
44018
- var VALID_SCOPES = /* @__PURE__ */ new Set(["row", "col", "rowgroup", "colgroup"]);
44019
- var NAMED_ENTITIES = {
44020
- amp: "&",
44021
- lt: "<",
44022
- gt: ">",
44023
- quot: '"',
44024
- apos: "'",
44025
- nbsp: "\xA0"
44026
- };
44027
- function decodeEntities(text) {
44028
- return text.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z][a-zA-Z0-9]*);/g, (whole, body) => {
44029
- if (body[0] === "#") {
44030
- const code = body[1] === "x" || body[1] === "X" ? Number.parseInt(body.slice(2), 16) : Number.parseInt(body.slice(1), 10);
44031
- if (Number.isFinite(code) && code >= 0 && code <= 1114111) {
44032
- try {
44033
- return String.fromCodePoint(code);
44034
- } catch {
44035
- return whole;
44036
- }
44037
- }
44038
- return whole;
44039
- }
44040
- return NAMED_ENTITIES[body] ?? whole;
44041
- });
44042
- }
44043
- function intAttr(value) {
44044
- if (value == null) return void 0;
44045
- const n = Number.parseInt(value, 10);
44046
- return Number.isInteger(n) ? n : void 0;
44047
- }
44048
- function isElement(node) {
44049
- return node.type === "element";
44050
- }
44051
- var HtmlTableParser = class {
44052
- constructor() {
44053
- __publicField(this, "keepUnknownTags", false);
44054
- }
44055
- /**
44056
- * Parse an HTML string and return one table bit per top-level `<table>`.
44057
- */
44058
- parse(html, options) {
44059
- this.keepUnknownTags = options?.keepUnknownTags ?? false;
44060
- const tableFormat = options?.tableFormat ?? "table-extended";
44061
- const onWarning = options?.onWarning;
44062
- const tables = this.collectTopLevelTables(parseHtml(html));
44063
- const bits = [];
44064
- for (const table of tables) {
44065
- const bit = this.tableToBit(table, tableFormat, onWarning);
44066
- if (bit) bits.push(bit);
44067
- }
44068
- return bits;
44069
- }
44070
- // --- table extraction -----------------------------------------------------
44071
- /** Collect every `<table>` element, NOT descending into nested tables. */
44072
- collectTopLevelTables(nodes) {
44073
- const tables = [];
44074
- const visit = (node) => {
44075
- if (!isElement(node)) return;
44076
- if (node.name === "table") {
44077
- tables.push(node);
44078
- return;
44079
- }
44080
- node.children.forEach(visit);
44081
- };
44082
- nodes.forEach(visit);
44083
- return tables;
44084
- }
44085
- tableToBit(table, tableFormat, onWarning) {
44086
- const header = [];
44087
- const body = [];
44088
- const footer = [];
44089
- let caption;
44090
- for (const child of table.children) {
44091
- if (!isElement(child)) continue;
44092
- if (child.name === "caption") {
44093
- const capContent = this.inlineNodes(child.children, []);
44094
- const trimmed = this.trimInline(capContent);
44095
- if (trimmed.length > 0) caption = trimmed;
44096
- } else if (SECTION_TAGS.has(child.name)) {
44097
- const target = child.name === "thead" ? header : child.name === "tfoot" ? footer : body;
44098
- for (const tr of childElements(child, ROW_TAGS)) {
44099
- target.push(this.rowToCells(tr));
44100
- }
44101
- } else if (ROW_TAGS.has(child.name)) {
44102
- body.push(this.rowToCells(child));
44103
- }
44104
- }
44105
- if (header.length === 0 && body.length === 0 && footer.length === 0) {
44106
- return void 0;
44107
- }
44108
- const tableExtended = {};
44109
- if (header.length > 0) tableExtended.header = { rows: header };
44110
- if (body.length > 0) tableExtended.body = { rows: body };
44111
- if (footer.length > 0) tableExtended.footer = { rows: footer };
44112
- let tableData = tableExtended;
44113
- if (tableFormat === "table") {
44114
- if (this.isLossyAsBasic(tableExtended)) {
44115
- onWarning?.(
44116
- "Converting an HTML table to [.table] loses rowspan/colspan/scope and multi-section structure; use --tableFormat table-extended to preserve them."
44117
- );
44118
- }
44119
- tableData = convertExtendedToBasicTableFormat(tableExtended);
44120
- }
44121
- const bit = {
44122
- type: tableFormat,
44123
- format: "bitmark++",
44124
- table: tableData
44125
- };
44126
- if (caption) bit.caption = caption;
44127
- return bit;
44128
- }
44129
- rowToCells(tr) {
44130
- const cells = [];
44131
- for (const cell of childElements(tr, CELL_TAGS)) {
44132
- cells.push(this.cellToJson(cell));
44133
- }
44134
- return { cells };
44135
- }
44136
- cellToJson(cell) {
44137
- const json = {
44138
- content: this.blockNodes(cell.children)
44139
- };
44140
- if (cell.name === "th") json.title = true;
44141
- const rowspan = intAttr(cell.attrs.rowspan);
44142
- if (rowspan != null && rowspan >= 2) json.rowspan = rowspan;
44143
- const colspan = intAttr(cell.attrs.colspan);
44144
- if (colspan != null && colspan >= 2) json.colspan = colspan;
44145
- const scope = cell.attrs.scope?.toLowerCase();
44146
- if (scope && VALID_SCOPES.has(scope)) {
44147
- json.scope = scope;
44148
- }
44149
- const width = this.widthFromCell(cell);
44150
- if (width != null) json.colwidth = width;
44151
- return json;
44152
- }
44153
- widthFromCell(cell) {
44154
- const attrWidth = intAttr(cell.attrs.width);
44155
- if (attrWidth != null && attrWidth > 0) return attrWidth;
44156
- const style = cell.attrs.style;
44157
- if (style) {
44158
- const m = style.match(/width\s*:\s*(\d+)\s*px/i);
44159
- if (m) {
44160
- const n = Number.parseInt(m[1], 10);
44161
- if (Number.isInteger(n) && n > 0) return n;
44162
- }
44163
- }
44164
- return void 0;
44165
- }
44166
- isLossyAsBasic(table) {
44167
- if (table.footer) return true;
44168
- if (table.header && table.header.rows.length > 1) return true;
44169
- const sections = [table.header, table.body, table.footer];
44170
- for (const section of sections) {
44171
- if (!section) continue;
44172
- for (const row of section.rows) {
44173
- for (const cell of row.cells) {
44174
- if (cell.rowspan || cell.colspan || cell.scope) return true;
44175
- }
44176
- }
44177
- }
44178
- return false;
44179
- }
44180
- // --- content conversion (HTML -> TextAst) ---------------------------------
44181
- /**
44182
- * Convert a cell/li's child nodes into block-level TextAst nodes (paragraphs, lists, images).
44183
- */
44184
- blockNodes(nodes) {
44185
- const blocks = [];
44186
- let inline = [];
44187
- const flush = () => {
44188
- const trimmed = this.trimInline(inline);
44189
- inline = [];
44190
- if (trimmed.length === 0) return;
44191
- if (trimmed.length === 1 && trimmed[0].type === "imageInline") {
44192
- blocks.push({ ...trimmed[0], type: "image" });
44193
- } else {
44194
- blocks.push({ type: "paragraph", content: trimmed, attrs: {} });
44195
- }
44196
- };
44197
- for (const node of nodes) {
44198
- if (!isElement(node)) {
44199
- inline.push(...this.inlineText(node.value, []));
44200
- continue;
44201
- }
44202
- const name = node.name;
44203
- if (name === "p") {
44204
- flush();
44205
- const content = this.trimInline(this.inlineNodes(node.children, []));
44206
- if (content.length > 0) {
44207
- blocks.push({ type: "paragraph", content, attrs: {} });
44208
- }
44209
- } else if (this.isListTag(name)) {
44210
- flush();
44211
- const list = this.listNode(node);
44212
- if (list) blocks.push(list);
44213
- } else {
44214
- inline.push(...this.inlineFromElement(node, []));
44215
- }
44216
- }
44217
- flush();
44218
- return blocks;
44219
- }
44220
- /** Convert child nodes to a flat list of inline TextNodes, applying the given marks. */
44221
- inlineNodes(nodes, marks) {
44222
- const out = [];
44223
- for (const node of nodes) {
44224
- if (!isElement(node)) {
44225
- out.push(...this.inlineText(node.value, marks));
44226
- } else {
44227
- out.push(...this.inlineFromElement(node, marks));
44228
- }
44229
- }
44230
- return out;
44231
- }
44232
- inlineFromElement(el, marks) {
44233
- const name = el.name;
44234
- if (name === "br") {
44235
- return [{ type: "hardBreak" }];
44236
- }
44237
- if (name === "img") {
44238
- return [this.imageNode(el, true)];
44239
- }
44240
- const markType = MARK_TAGS[name];
44241
- if (markType) {
44242
- return this.inlineNodes(el.children, [...marks, { type: markType }]);
44243
- }
44244
- if (name === "a") {
44245
- const linkMark = {
44246
- type: "link",
44247
- attrs: {
44248
- href: el.attrs.href ?? "",
44249
- ...el.attrs.target ? { target: el.attrs.target } : {}
44250
- }
44251
- };
44252
- return this.inlineNodes(el.children, [...marks, linkMark]);
44253
- }
44254
- if (this.keepUnknownTags) {
44255
- const open = this.serializeOpenTag(el);
44256
- const close = `</${name}>`;
44257
- return [
44258
- ...this.inlineText(open, marks),
44259
- ...this.inlineNodes(el.children, marks),
44260
- ...this.inlineText(close, marks)
44261
- ];
44262
- }
44263
- return this.inlineNodes(el.children, marks);
44264
- }
44265
- inlineText(raw, marks) {
44266
- const text = decodeEntities(raw).replace(/\s+/g, " ");
44267
- if (text === "") return [];
44268
- const node = { text, type: "text" };
44269
- if (marks.length > 0) node.marks = marks.map((m) => ({ ...m }));
44270
- return [node];
44271
- }
44272
- serializeOpenTag(el) {
44273
- const attrs = Object.entries(el.attrs).map(([k, v]) => v === "" ? ` ${k}` : ` ${k}="${v}"`).join("");
44274
- return `<${el.name}${attrs}>`;
44275
- }
44276
- // --- lists ----------------------------------------------------------------
44277
- isListTag(name) {
44278
- return name === "ul" || name === "ol";
44279
- }
44280
- listNode(el) {
44281
- const items = childElements(el, LI_TAGS);
44282
- if (items.length === 0) return void 0;
44283
- const isTask = el.name === "ul" && items.some((li) => {
44284
- const firstEl = li.children.find(isElement);
44285
- return firstEl?.name === "input" && firstEl.attrs.type?.toLowerCase() === "checkbox";
44286
- });
44287
- if (isTask) {
44288
- return {
44289
- type: "taskList",
44290
- content: items.map((li) => this.taskItemNode(li))
44291
- };
44292
- }
44293
- const type = this.listType(el);
44294
- const node = {
44295
- type,
44296
- content: items.map((li) => this.listItemNode(li))
44297
- };
44298
- if (el.name === "ol") {
44299
- const start = intAttr(el.attrs.start);
44300
- if (start != null) {
44301
- node.attrs = { start };
44302
- }
44303
- }
44304
- return node;
44305
- }
44306
- listType(el) {
44307
- if (el.name === "ol") {
44308
- switch (el.attrs.type) {
44309
- case "i":
44310
- return "orderedListRomanLower";
44311
- case "I":
44312
- return "orderedListRoman";
44313
- case "a":
44314
- return "letteredListLower";
44315
- case "A":
44316
- return "letteredList";
44317
- default:
44318
- return "orderedList";
44319
- }
44320
- }
44321
- const style = el.attrs.style ?? "";
44322
- if (/list-style(-type)?\s*:\s*none/i.test(style)) return "noBulletList";
44323
- return "bulletList";
44324
- }
44325
- listItemNode(li) {
44326
- let content = this.blockNodes(li.children);
44327
- if (content.length === 0) {
44328
- content = [{ type: "paragraph", content: [], attrs: {} }];
44329
- }
44330
- return { type: "listItem", content };
44331
- }
44332
- taskItemNode(li) {
44333
- const checkbox = li.children.find(
44334
- (c) => isElement(c) && c.name === "input" && c.attrs.type?.toLowerCase() === "checkbox"
44335
- );
44336
- const checked = checkbox ? "checked" in checkbox.attrs : false;
44337
- const rest = li.children.filter((c) => c !== checkbox);
44338
- let content = this.blockNodes(rest);
44339
- if (content.length === 0) {
44340
- content = [{ type: "paragraph", content: [], attrs: {} }];
44341
- }
44342
- return { type: "taskItem", attrs: { checked }, content };
44343
- }
44344
- // --- images ---------------------------------------------------------------
44345
- imageNode(el, inline) {
44346
- const attrs = { src: el.attrs.src ?? "" };
44347
- attrs.alt = el.attrs.alt ?? null;
44348
- attrs.title = el.attrs.title ?? null;
44349
- const width = intAttr(el.attrs.width);
44350
- if (width != null) attrs.width = width;
44351
- const height = intAttr(el.attrs.height);
44352
- if (height != null) attrs.height = height;
44353
- if (el.attrs.class) attrs.class = el.attrs.class;
44354
- return { type: inline ? "imageInline" : "image", attrs };
44355
- }
44356
- // --- whitespace -----------------------------------------------------------
44357
- /** Trim leading/trailing whitespace from inline content (edges only). */
44358
- trimInline(nodes) {
44359
- const out = nodes.slice();
44360
- const isWs = (n) => n.type === "text" && /^\s*$/.test(n.text ?? "");
44361
- while (out.length > 0 && isWs(out[0])) out.shift();
44362
- if (out.length > 0 && out[0].type === "text") {
44363
- out[0] = { ...out[0], text: (out[0].text ?? "").replace(/^\s+/, "") };
44364
- }
44365
- while (out.length > 0 && isWs(out[out.length - 1])) out.pop();
44366
- if (out.length > 0 && out[out.length - 1].type === "text") {
44367
- const last = out.length - 1;
44368
- out[last] = { ...out[last], text: (out[last].text ?? "").replace(/\s+$/, "") };
44369
- }
44370
- return out.filter((n) => !(n.type === "text" && n.text === ""));
44371
- }
44372
- };
44373
-
44374
44634
  // src/BitmarkParserGenerator.ts
44375
44635
  var Input = {
44376
44636
  /**