documonster 0.18.0 → 0.18.1

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.
Files changed (54) hide show
  1. package/README.md +1 -1
  2. package/README_zh.md +1 -1
  3. package/dist/esm/modules/excel/core/workbook-model.js +1 -0
  4. package/dist/esm/modules/excel/core/workbook.browser.js +1 -0
  5. package/dist/esm/modules/excel/xlsb/conditional-format.js +54 -10
  6. package/dist/esm/modules/excel/xlsb/dxf.js +928 -0
  7. package/dist/esm/modules/excel/xlsb/fill.js +12 -2
  8. package/dist/esm/modules/excel/xlsb/filter-criteria.js +15 -8
  9. package/dist/esm/modules/excel/xlsb/font.js +5 -4
  10. package/dist/esm/modules/excel/xlsb/read/package.js +6 -0
  11. package/dist/esm/modules/excel/xlsb/styles.js +30 -359
  12. package/dist/esm/modules/excel/xlsb/write/package.js +13 -1
  13. package/dist/esm/modules/excel/xlsb/write/worksheet.js +16 -1
  14. package/dist/esm/modules/excel/xlsx/xform/simple/boolean-xform.js +12 -1
  15. package/dist/esm/modules/excel/xlsx/xform/style/alignment-xform.js +52 -16
  16. package/dist/esm/modules/excel/xlsx/xform/style/border-xform.js +24 -2
  17. package/dist/esm/modules/excel/xlsx/xform/style/dxf-extensions.js +55 -0
  18. package/dist/esm/modules/excel/xlsx/xform/style/dxf-xform.js +121 -6
  19. package/dist/esm/modules/excel/xlsx/xform/style/fill-xform.js +17 -10
  20. package/dist/esm/modules/excel/xlsx/xform/style/font-xform.js +32 -8
  21. package/dist/esm/modules/excel/xlsx/xform/style/styles-xform.js +83 -8
  22. package/dist/esm/modules/excel/xlsx/xlsx.browser.js +10 -0
  23. package/dist/esm/utils/text-measure.js +1 -1
  24. package/dist/iife/documonster.archive.iife.min.js +1 -1
  25. package/dist/iife/documonster.csv.iife.min.js +1 -1
  26. package/dist/iife/documonster.draw.iife.min.js +2 -2
  27. package/dist/iife/documonster.excel.iife.min.js +53 -53
  28. package/dist/iife/documonster.formula.iife.min.js +1 -1
  29. package/dist/iife/documonster.markdown.iife.min.js +1 -1
  30. package/dist/iife/documonster.mermaid.iife.min.js +2 -2
  31. package/dist/iife/documonster.pdf.iife.min.js +2 -2
  32. package/dist/iife/documonster.stream.iife.min.js +1 -1
  33. package/dist/iife/documonster.word.iife.min.js +60 -60
  34. package/dist/iife/documonster.xml.iife.min.js +1 -1
  35. package/dist/types/modules/excel/core/workbook-core.d.ts +10 -1
  36. package/dist/types/modules/excel/core/workbook-model.d.ts +3 -1
  37. package/dist/types/modules/excel/types.d.ts +33 -4
  38. package/dist/types/modules/excel/xlsb/conditional-format.d.ts +20 -2
  39. package/dist/types/modules/excel/xlsb/dxf.d.ts +56 -0
  40. package/dist/types/modules/excel/xlsb/fill.d.ts +5 -1
  41. package/dist/types/modules/excel/xlsb/filter-criteria.d.ts +9 -1
  42. package/dist/types/modules/excel/xlsb/font.d.ts +22 -0
  43. package/dist/types/modules/excel/xlsb/styles.d.ts +2 -13
  44. package/dist/types/modules/excel/xlsb/write/worksheet.d.ts +2 -0
  45. package/dist/types/modules/excel/xlsx/xform/simple/boolean-xform.d.ts +15 -0
  46. package/dist/types/modules/excel/xlsx/xform/style/alignment-xform.d.ts +13 -1
  47. package/dist/types/modules/excel/xlsx/xform/style/border-xform.d.ts +11 -0
  48. package/dist/types/modules/excel/xlsx/xform/style/dxf-extensions.d.ts +29 -0
  49. package/dist/types/modules/excel/xlsx/xform/style/dxf-xform.d.ts +34 -1
  50. package/dist/types/modules/excel/xlsx/xform/style/fill-xform.d.ts +15 -3
  51. package/dist/types/modules/excel/xlsx/xform/style/font-xform.d.ts +6 -0
  52. package/dist/types/modules/excel/xlsx/xform/style/styles-xform.d.ts +23 -0
  53. package/dist/types/utils/text-measure.d.ts +2 -1
  54. package/package.json +17 -18
package/README.md CHANGED
@@ -211,7 +211,7 @@ const buffer = await Workbook.toBuffer(wb);
211
211
 
212
212
  ```html
213
213
  <!-- Script tag (no bundler) — one IIFE per module, each under the shared `Documonster` global -->
214
- <script src="https://unpkg.com/documonster@0.18.0/dist/iife/documonster.excel.iife.min.js"></script>
214
+ <script src="https://unpkg.com/documonster@0.18.1/dist/iife/documonster.excel.iife.min.js"></script>
215
215
  <script>
216
216
  const { Workbook, Cell } = Documonster.Excel;
217
217
  const wb = Workbook.create();
package/README_zh.md CHANGED
@@ -198,7 +198,7 @@ const buffer = await Workbook.toBuffer(wb);
198
198
 
199
199
  ```html
200
200
  <!-- Script 标签(无需打包工具)— 每个模块一个 IIFE,共享同一个 `Documonster` 全局 -->
201
- <script src="https://unpkg.com/documonster@0.18.0/dist/iife/documonster.excel.iife.min.js"></script>
201
+ <script src="https://unpkg.com/documonster@0.18.1/dist/iife/documonster.excel.iife.min.js"></script>
202
202
  <script>
203
203
  const { Workbook, Cell } = Documonster.Excel;
204
204
  const wb = Workbook.create();
@@ -73,6 +73,7 @@ export function getWorkbookModel(wb) {
73
73
  calcProperties: wb.calcProperties,
74
74
  defaultFont: wb._defaultFont,
75
75
  cellStyles: wb._cellStyles ? [...wb._cellStyles.values()] : undefined,
76
+ dxfs: wb._dxfs,
76
77
  externalLinks: wb.externalLinks,
77
78
  chartEntries: wb._chartEntries,
78
79
  chartRels: wb._chartRels,
@@ -830,6 +830,7 @@ export function setWorkbookModel(wb, value) {
830
830
  wb._cellStyles = value.cellStyles
831
831
  ? new Map(value.cellStyles.map(cs => [cs.name, cs]))
832
832
  : undefined;
833
+ wb._dxfs = value.dxfs;
833
834
  // Restore chart entries
834
835
  wb._chartEntries = value.chartEntries || {};
835
836
  wb._chartRels = value.chartRels || {};
@@ -62,30 +62,69 @@ const CF_OPER = {
62
62
  /** `DXFId` meaning "no differential formatting". */
63
63
  const NO_DXF = 0xffffffff;
64
64
  /**
65
- * The `BrtBeginDXFs` collection: one entry per distinct rule style.
65
+ * The `BrtBeginDXFs` collection, and where each format lands in it.
66
66
  *
67
67
  * A `dxfId` is an index into this, so it has to be built across every sheet before any of them is written
68
68
  * — which is why this is a separate pass rather than something the sheet writer does. Deduplicated by
69
69
  * serialised form, because two rules with the same fill share one entry in Excel's own output.
70
+ *
71
+ * **The table the workbook was read with comes first** (`options.source`). Not every holder of a `dxfId` is
72
+ * modelled: a `<colorFilter>` is preserved as XML with the number it was read with, and `fromSource` is how
73
+ * that number is translated. A modelled rule read from the same file holds the very object its `dxfId`
74
+ * resolved to, so it is matched by identity before its serialised form is ever computed.
75
+ *
76
+ * **A format this writer cannot encode gets no index at all** (`options.describe`), rather than an index the
77
+ * styles writer then leaves out. Handing it an index and dropping it later moved every format after it down by
78
+ * one, so each later rule — and every preserved reference — pointed at its neighbour's formatting. A format that
79
+ * encodes only *in part* is kept, and what it lost is returned in `lost`, once per distinct format.
70
80
  */
71
- export function collectDxfs(blocks) {
81
+ export function collectDxfs(blocks, options = {}) {
82
+ const { source = [], describe = () => ({ writable: true, dropped: [] }) } = options;
72
83
  const styles = [];
84
+ const lost = [];
73
85
  const indexByKey = new Map();
86
+ const indexByIdentity = new Map();
87
+ const add = (style) => {
88
+ const known = indexByIdentity.get(style);
89
+ if (known !== undefined) {
90
+ return known;
91
+ }
92
+ const key = JSON.stringify(style);
93
+ let index = indexByKey.get(key);
94
+ if (index === undefined) {
95
+ const { writable, dropped } = describe(style);
96
+ index = writable ? styles.push(style) - 1 : NO_DXF;
97
+ if (writable && dropped.length > 0) {
98
+ lost.push(`differential format ${index}: ${dropped.join(", ")}`);
99
+ }
100
+ indexByKey.set(key, index);
101
+ }
102
+ indexByIdentity.set(style, index);
103
+ return index;
104
+ };
105
+ const sourceIndex = source.map(style => (style === undefined ? NO_DXF : add(style)));
74
106
  for (const block of blocks) {
75
107
  for (const rule of block.rules ?? []) {
76
- if (rule.style === undefined) {
77
- continue;
78
- }
79
- const key = JSON.stringify(rule.style);
80
- if (!indexByKey.has(key)) {
81
- indexByKey.set(key, styles.length);
82
- styles.push(rule.style);
108
+ if (rule.style !== undefined) {
109
+ add(rule.style);
83
110
  }
84
111
  }
85
112
  }
86
113
  return {
87
114
  styles,
88
- indexOf: style => style === undefined ? NO_DXF : (indexByKey.get(JSON.stringify(style)) ?? NO_DXF)
115
+ indexOf: style => style === undefined
116
+ ? NO_DXF
117
+ : (indexByIdentity.get(style) ?? indexByKey.get(JSON.stringify(style)) ?? NO_DXF),
118
+ fromSource: sourceId => {
119
+ // With no table read from a file there is nothing to translate from: a stated id can only mean the table
120
+ // being written, which is how the XLSX writer treats the same XML — it writes the number as it is.
121
+ if (source.length === 0) {
122
+ return sourceId < styles.length ? sourceId : undefined;
123
+ }
124
+ const index = sourceIndex[sourceId];
125
+ return index === undefined || index === NO_DXF ? undefined : index;
126
+ },
127
+ lost
89
128
  };
90
129
  }
91
130
  /**
@@ -112,6 +151,11 @@ export function conditionalFormattingRecords(blocks, dxf, context, resolvePriori
112
151
  }
113
152
  const encoded = (block.rules ?? [])
114
153
  .map(rule => {
154
+ // A style `BrtDXF` cannot express gets no `dxfId` (see `collectDxfs`): the rule is still written and
155
+ // still applies, but without its formatting — which is a loss, and was silent.
156
+ if (rule.style !== undefined && dxf.indexOf(rule.style) === NO_DXF) {
157
+ lost.push(`conditional formatting format on ${block.ref ?? "an unnamed range"}`);
158
+ }
115
159
  // The block's range travels with the rule, because a derived formula is written relative to the
116
160
  // range's top-left cell and a single rule does not carry the range itself.
117
161
  const payload = encodeRule({