reamkit 1.15.4 → 1.17.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.
Files changed (127) hide show
  1. package/dist/esm/core/bidi/segments.js +1 -2
  2. package/dist/esm/core/converter/facade.d.ts +5 -0
  3. package/dist/esm/core/converter/project.js +5 -1
  4. package/dist/esm/core/converter/ream.d.ts +6 -0
  5. package/dist/esm/core/converter/ream.js +34 -8
  6. package/dist/esm/core/document-model/index.d.ts +1 -1
  7. package/dist/esm/core/document-model/types.d.ts +659 -7
  8. package/dist/esm/core/drawingml/chart-geometry.d.ts +34 -10
  9. package/dist/esm/core/drawingml/chart-geometry.js +424 -92
  10. package/dist/esm/core/drawingml/chart-parser.js +301 -11
  11. package/dist/esm/core/drawingml/colors.d.ts +7 -7
  12. package/dist/esm/core/drawingml/colors.js +84 -18
  13. package/dist/esm/core/drawingml/preset-geometry.js +240 -6
  14. package/dist/esm/core/drawingml/shape-render.d.ts +12 -0
  15. package/dist/esm/core/drawingml/shape-render.js +116 -3
  16. package/dist/esm/core/drawingml/sparkline-geometry.js +6 -4
  17. package/dist/esm/core/drawingml/theme-parser.d.ts +51 -0
  18. package/dist/esm/core/drawingml/theme-parser.js +92 -1
  19. package/dist/esm/core/font/measure.d.ts +5 -0
  20. package/dist/esm/core/font/measure.js +21 -1
  21. package/dist/esm/core/font/ttf-subset.js +26 -1
  22. package/dist/esm/core/images.d.ts +2 -2
  23. package/dist/esm/core/images.js +353 -43
  24. package/dist/esm/core/indexed-colors.d.ts +11 -0
  25. package/dist/esm/core/indexed-colors.js +81 -0
  26. package/dist/esm/core/ir/flow.d.ts +23 -1
  27. package/dist/esm/core/ir/sheet.d.ts +61 -0
  28. package/dist/esm/{excel → core}/number-format.d.ts +37 -0
  29. package/dist/esm/core/number-format.js +800 -0
  30. package/dist/esm/core/numbering/apply.d.ts +5 -3
  31. package/dist/esm/core/numbering/apply.js +42 -11
  32. package/dist/esm/core/numbering/index.js +2 -0
  33. package/dist/esm/core/numbering/state.d.ts +13 -1
  34. package/dist/esm/core/numbering/state.js +256 -15
  35. package/dist/esm/core/opc/alternate-content.d.ts +13 -0
  36. package/dist/esm/core/opc/alternate-content.js +72 -0
  37. package/dist/esm/core/opc/core-properties.js +1 -0
  38. package/dist/esm/core/opc/package.d.ts +14 -1
  39. package/dist/esm/core/opc/package.js +43 -4
  40. package/dist/esm/core/opc/relationships.js +1 -0
  41. package/dist/esm/core/opc/xml-entities.d.ts +12 -0
  42. package/dist/esm/core/opc/xml-entities.js +91 -0
  43. package/dist/esm/core/po-helpers.js +16 -1
  44. package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
  45. package/dist/esm/core/spreadsheet-model/types.d.ts +137 -0
  46. package/dist/esm/core/style-cascade/resolver.js +66 -11
  47. package/dist/esm/core/style-cascade/table.js +35 -11
  48. package/dist/esm/core/style-cascade/types.d.ts +42 -1
  49. package/dist/esm/core/style-cascade/types.js +4 -0
  50. package/dist/esm/core/vector.d.ts +30 -0
  51. package/dist/esm/excel/activex-parser.js +1 -0
  52. package/dist/esm/excel/column-bands.d.ts +26 -1
  53. package/dist/esm/excel/column-bands.js +156 -20
  54. package/dist/esm/excel/comments-parser.js +5 -3
  55. package/dist/esm/excel/conditional-format.d.ts +25 -2
  56. package/dist/esm/excel/conditional-format.js +63 -19
  57. package/dist/esm/excel/escaped-text.d.ts +9 -0
  58. package/dist/esm/excel/escaped-text.js +20 -0
  59. package/dist/esm/excel/form-control-parser.js +1 -0
  60. package/dist/esm/excel/formula/dates.js +1 -1
  61. package/dist/esm/excel/header-footer.d.ts +9 -1
  62. package/dist/esm/excel/header-footer.js +162 -14
  63. package/dist/esm/excel/index.d.ts +1 -1
  64. package/dist/esm/excel/index.js +2 -2
  65. package/dist/esm/excel/pivot-table-parser.js +1 -0
  66. package/dist/esm/excel/print-model.d.ts +75 -0
  67. package/dist/esm/excel/print-model.js +899 -77
  68. package/dist/esm/excel/printer-settings.d.ts +16 -0
  69. package/dist/esm/excel/printer-settings.js +36 -0
  70. package/dist/esm/excel/rich-value.d.ts +13 -0
  71. package/dist/esm/excel/rich-value.js +120 -0
  72. package/dist/esm/excel/shared-strings-parser.js +11 -7
  73. package/dist/esm/excel/sheet-drawing.d.ts +11 -0
  74. package/dist/esm/excel/sheet-drawing.js +26 -3
  75. package/dist/esm/excel/sheet-shape-parser.d.ts +53 -1
  76. package/dist/esm/excel/sheet-shape-parser.js +461 -32
  77. package/dist/esm/excel/sheet-to-flow.d.ts +23 -2
  78. package/dist/esm/excel/sheet-to-flow.js +553 -36
  79. package/dist/esm/excel/slicer-parser.js +1 -0
  80. package/dist/esm/excel/styles-parser.d.ts +30 -2
  81. package/dist/esm/excel/styles-parser.js +177 -40
  82. package/dist/esm/excel/table-parser.js +1 -0
  83. package/dist/esm/excel/vml-drawing.d.ts +68 -0
  84. package/dist/esm/excel/vml-drawing.js +158 -0
  85. package/dist/esm/excel/workbook-parser.d.ts +5 -0
  86. package/dist/esm/excel/workbook-parser.js +5 -1
  87. package/dist/esm/excel/worksheet-parser.d.ts +2 -1
  88. package/dist/esm/excel/worksheet-parser.js +150 -61
  89. package/dist/esm/excel/xlsx-reader.js +242 -11
  90. package/dist/esm/excel/xlsx-to-pdf.js +12 -1
  91. package/dist/esm/html/html-writer.js +29 -6
  92. package/dist/esm/layout/page-doc.d.ts +87 -1
  93. package/dist/esm/layout/styled-layout.d.ts +46 -2
  94. package/dist/esm/layout/styled-layout.js +2345 -274
  95. package/dist/esm/pdf/cid-font.js +20 -9
  96. package/dist/esm/pdf/objects.d.ts +13 -0
  97. package/dist/esm/pdf/objects.js +18 -1
  98. package/dist/esm/pdf/shading.js +76 -6
  99. package/dist/esm/pdf/styled-page-emitter.js +355 -49
  100. package/dist/esm/pdf/text-page-renderer.js +1 -0
  101. package/dist/esm/pdf/vector-graphics.d.ts +31 -2
  102. package/dist/esm/pdf/vector-graphics.js +103 -3
  103. package/dist/esm/pptx/pptx-reader.js +2 -0
  104. package/dist/esm/pptx/slide-parser.d.ts +21 -4
  105. package/dist/esm/pptx/slide-parser.js +98 -24
  106. package/dist/esm/svg/svg-writer.js +23 -4
  107. package/dist/esm/word/document-parser.d.ts +96 -7
  108. package/dist/esm/word/document-parser.js +538 -116
  109. package/dist/esm/word/docx-reader.js +135 -43
  110. package/dist/esm/word/docx-writer.js +6 -1
  111. package/dist/esm/word/drawing-parser.d.ts +86 -5
  112. package/dist/esm/word/drawing-parser.js +1590 -54
  113. package/dist/esm/word/index.d.ts +4 -4
  114. package/dist/esm/word/numbering-parser.d.ts +2 -1
  115. package/dist/esm/word/numbering-parser.js +108 -21
  116. package/dist/esm/word/paragraph-properties.d.ts +11 -1
  117. package/dist/esm/word/paragraph-properties.js +219 -10
  118. package/dist/esm/word/run-properties.js +45 -1
  119. package/dist/esm/word/settings-parser.d.ts +24 -0
  120. package/dist/esm/word/settings-parser.js +32 -5
  121. package/dist/esm/word/shading.d.ts +11 -0
  122. package/dist/esm/word/shading.js +64 -0
  123. package/dist/esm/word/styles-parser.js +9 -2
  124. package/dist/esm/word/table-parser.d.ts +9 -1
  125. package/dist/esm/word/table-parser.js +182 -30
  126. package/package.json +7 -3
  127. package/dist/esm/excel/number-format.js +0 -476
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Resolve the entities an internal DTD subset declares and remove the subset,
3
+ * so what reaches the XML parser is a well-formed part with no `&name;` left
4
+ * to leak. Markup inside an entity value is escaped to text rather than
5
+ * spliced in — an entity that opens a tag is a document we will not build.
6
+ *
7
+ * Text with no `<!DOCTYPE` is returned unchanged, which is every real file.
8
+ *
9
+ * @param xml The decoded part, as read from the package.
10
+ * @returns The part with its internal subset resolved and stripped.
11
+ */
12
+ export declare function resolveInternalEntities(xml: string): string;
@@ -0,0 +1,91 @@
1
+ //#region src/core/opc/xml-entities.ts
2
+ /** Longest text any one declared entity may expand to. */
3
+ var MAX_EXPANSION = 65536;
4
+ /** Longest total the substitutions may add to one part. */
5
+ var MAX_TOTAL = 1048576;
6
+ var DOCTYPE = /<!DOCTYPE\s[^[>]*(?:\[[\s\S]*?\]\s*)?>/;
7
+ var ENTITY_DECL = /<!ENTITY\s+([^\s%<>&;]+)\s+(?:"([^"]*)"|'([^']*)')\s*>/g;
8
+ var REFERENCE = /&([^\s;&<>]+);/g;
9
+ /** The five entities XML predefines; a declaration never overrides them. */
10
+ var PREDEFINED = new Set([
11
+ "lt",
12
+ "gt",
13
+ "amp",
14
+ "apos",
15
+ "quot"
16
+ ]);
17
+ /** Escape resolved text so it re-enters the document as characters, not markup. */
18
+ function escape(text) {
19
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
20
+ }
21
+ /**
22
+ * Substitute every entity reference in `text` using `valueOf`, leaving the
23
+ * predefined and numeric references for the XML parser. Returns undefined once
24
+ * the result passes `cap` — the caller drops what it was building.
25
+ */
26
+ function substitute(text, cap, valueOf) {
27
+ if (!text.includes("&")) return text.length > cap ? void 0 : text;
28
+ let out = "";
29
+ let last = 0;
30
+ for (const m of text.matchAll(REFERENCE)) {
31
+ const name = m[1] ?? "";
32
+ out += text.slice(last, m.index);
33
+ last = m.index + m[0].length;
34
+ out += PREDEFINED.has(name) || name.startsWith("#") ? m[0] : valueOf(name);
35
+ if (out.length > cap) return void 0;
36
+ }
37
+ out += text.slice(last);
38
+ return out.length > cap ? void 0 : out;
39
+ }
40
+ /**
41
+ * Expand each declaration once, so a name referenced ten thousand times costs
42
+ * one expansion rather than ten thousand. A cycle, an undeclared name and a
43
+ * value that outgrows MAX_EXPANSION all resolve to the empty string: XML says
44
+ * such a document is in error, and drawing the reference's own spelling is the
45
+ * one answer that is certainly wrong.
46
+ */
47
+ function expander(declared) {
48
+ const done = /* @__PURE__ */ new Map();
49
+ const active = /* @__PURE__ */ new Set();
50
+ const valueOf = (name) => {
51
+ const memo = done.get(name);
52
+ if (memo !== void 0) return memo;
53
+ if (active.has(name)) return "";
54
+ const raw = declared.get(name);
55
+ if (raw === void 0) return "";
56
+ active.add(name);
57
+ const out = substitute(raw, MAX_EXPANSION, valueOf) ?? "";
58
+ active.delete(name);
59
+ done.set(name, out);
60
+ return out;
61
+ };
62
+ return valueOf;
63
+ }
64
+ /**
65
+ * Resolve the entities an internal DTD subset declares and remove the subset,
66
+ * so what reaches the XML parser is a well-formed part with no `&name;` left
67
+ * to leak. Markup inside an entity value is escaped to text rather than
68
+ * spliced in — an entity that opens a tag is a document we will not build.
69
+ *
70
+ * Text with no `<!DOCTYPE` is returned unchanged, which is every real file.
71
+ *
72
+ * @param xml The decoded part, as read from the package.
73
+ * @returns The part with its internal subset resolved and stripped.
74
+ */
75
+ function resolveInternalEntities(xml) {
76
+ if (!xml.includes("<!DOCTYPE")) return xml;
77
+ const doctype = DOCTYPE.exec(xml);
78
+ if (!doctype) return xml;
79
+ const declared = /* @__PURE__ */ new Map();
80
+ for (const decl of doctype[0].matchAll(ENTITY_DECL)) {
81
+ const name = decl[1];
82
+ if (name === void 0 || name.startsWith("%") || PREDEFINED.has(name)) continue;
83
+ if (!declared.has(name)) declared.set(name, decl[2] ?? decl[3] ?? "");
84
+ }
85
+ const body = xml.slice(0, doctype.index) + xml.slice(doctype.index + doctype[0].length);
86
+ if (!body.includes("&")) return body;
87
+ const valueOf = expander(declared);
88
+ return substitute(body, MAX_TOTAL, (name) => escape(valueOf(name))) ?? substitute(body, MAX_TOTAL, () => "") ?? body;
89
+ }
90
+ //#endregion
91
+ export { resolveInternalEntities };
@@ -65,7 +65,22 @@ function poIntAttr(node, name) {
65
65
  const v = poAttr(node, name);
66
66
  if (v === void 0) return void 0;
67
67
  const n = Number(v);
68
- return Number.isFinite(n) ? n : void 0;
68
+ if (Number.isFinite(n)) return n;
69
+ return universalMeasureTwips(v);
70
+ }
71
+ var MEASURE_TWIPS = new Map([
72
+ ["pt", 20],
73
+ ["pc", 240],
74
+ ["pi", 240],
75
+ ["in", 1440],
76
+ ["cm", 1440 / 2.54],
77
+ ["mm", 144 / 2.54]
78
+ ]);
79
+ function universalMeasureTwips(raw) {
80
+ const m = /^\s*(-?[0-9]+(?:\.[0-9]+)?)(pt|pc|pi|in|cm|mm)\s*$/iu.exec(raw);
81
+ if (!m) return void 0;
82
+ const per = MEASURE_TWIPS.get(m[2].toLowerCase());
83
+ return per === void 0 ? void 0 : Number(m[1]) * per;
69
84
  }
70
85
  /** Shorthand for the `val` attribute (`@w:val`/…). */
71
86
  function poVal(node) {
@@ -1 +1 @@
1
- export type { CellType, WorksheetCell, ColumnWidth, MergedRange, RowHeight, XlsxPageMargins, XlsxPageSetup, XlsxPrintOptions, ParsedWorksheet, XlsxFont, XlsxFill, XlsxBorderStyleName, XlsxBorderEdge, XlsxBorder, XlsxHorizontalAlign, XlsxVerticalAlign, XlsxCellAlignment, XlsxCellXf, XlsxStyles, DefinedName, Dxf, CfOperator, CfRuleCellIs, CfvoType, Cfvo, CfRuleColorScale, CfRuleDataBar, CfRuleIconSet, CfRuleTop10, CfRuleAboveAverage, CfRuleDupUnique, CfRuleText, CfRuleExpression, CfRuleTimePeriod, TimePeriodKind, CfRule, ConditionalFormat, DataValidationType, DataValidation, HyperlinkRef, HeaderFooter, FormControlRef, OleObjectRef, SheetRichRun, SparklineKind, ParsedSparkline, ExcelTable, PivotTable, SheetPane, } from './types.js';
1
+ export type { CellType, WorksheetCell, ColumnStyle, ColumnWidth, MergedRange, RowHeight, RowStyle, XlsxPageMargins, XlsxPageSetup, XlsxPrintOptions, ParsedWorksheet, XlsxFont, XlsxFill, XlsxBorderStyleName, XlsxBorderEdge, XlsxBorder, XlsxHorizontalAlign, XlsxVerticalAlign, XlsxCellAlignment, XlsxCellXf, XlsxStyles, DefinedName, Dxf, CfOperator, CfRuleCellIs, CfvoType, Cfvo, CfRuleColorScale, CfRuleDataBar, CfRuleIconSet, CfRuleTop10, CfRuleAboveAverage, CfRuleDupUnique, CfRuleText, CfRuleExpression, CfRuleTimePeriod, TimePeriodKind, CfRule, ConditionalFormat, DataValidationType, DataValidation, HyperlinkRef, HeaderFooter, FormControlRef, OleObjectRef, SheetRichRun, SparklineKind, ParsedSparkline, ExcelTable, PivotTable, SheetPane, } from './types.js';
@@ -11,12 +11,40 @@ export interface WorksheetCell {
11
11
  readonly inlineText?: string;
12
12
  /** Index into the workbook's `cellXfs` (`xl/styles.xml`). 0 means default style. */
13
13
  readonly styleIndex?: number;
14
+ /**
15
+ * §18.3.1.4 `vm` — 1-based index into `xl/metadata.xml`'s `<valueMetadata>`.
16
+ * A cell whose value is a rich value stores a legacy error in `<v>` for
17
+ * readers that predate the feature, and points here for the real one.
18
+ */
19
+ readonly valueMetadataIndex?: number;
14
20
  }
15
21
  /** §18.3.1.13 `<col>` — a width (in character units) for the column span `min..max`. */
16
22
  export interface ColumnWidth {
17
23
  readonly min: number;
18
24
  readonly max: number;
19
25
  readonly widthChars: number;
26
+ /** §18.3.1.13 `hidden` — Excel and LibreOffice print neither the column nor its cells. */
27
+ readonly hidden?: boolean;
28
+ }
29
+ /**
30
+ * §18.3.1.13 `<col style>` / §18.3.1.73 `<row s customFormat>` — the style a
31
+ * cell takes when the file gives it none of its own.
32
+ *
33
+ * A spreadsheet formats whole columns and whole rows without writing a `<c>`
34
+ * for each one: 51710.xlsx paints its column A grey with a single `<col
35
+ * min="1" max="1" style="1"/>`, and 588 of its rows carry no A cell at all.
36
+ * The band is on the page in Excel and in LibreOffice, so the default has to
37
+ * reach the paint even where there is nothing to paint it on.
38
+ */
39
+ export interface ColumnStyle {
40
+ readonly min: number;
41
+ readonly max: number;
42
+ readonly styleIndex: number;
43
+ }
44
+ /** §18.3.1.73 — the style a row hands to its unwritten cells. */
45
+ export interface RowStyle {
46
+ readonly row: number;
47
+ readonly styleIndex: number;
20
48
  }
21
49
  /** §18.3.1.55 `<mergeCell>` — a merged cell rectangle (0-indexed, inclusive bounds). */
22
50
  export interface MergedRange {
@@ -34,6 +62,8 @@ export interface RowHeight {
34
62
  readonly row: number;
35
63
  readonly heightPt: number;
36
64
  readonly customHeight: boolean;
65
+ /** §18.3.1.73 `hidden` — the row is not printed at all. */
66
+ readonly hidden?: boolean;
37
67
  }
38
68
  /** ECMA-376 Part 1 §18.3.1.62 — `<pageMargins>`. All attributes are in inches. */
39
69
  export interface XlsxPageMargins {
@@ -59,6 +89,18 @@ export interface XlsxPageSetup {
59
89
  readonly fitToWidth?: number;
60
90
  /** Number of pages tall to fit to; default 1. */
61
91
  readonly fitToHeight?: number;
92
+ /**
93
+ * `r:id` of the sheet's `printerSettings` part. When `paperSize` is absent the
94
+ * paper is whatever that part's DEVMODE says, which is how Excel records the
95
+ * choice made in the print dialog rather than in the sheet.
96
+ */
97
+ readonly printerSettingsRelId?: string;
98
+ /**
99
+ * §18.3.1.63 `cellComments` — where the sheet's notes are printed:
100
+ * `none` (the default) prints none of them, `asDisplayed` prints them where
101
+ * they float, `atEnd` gathers them after the grid.
102
+ */
103
+ readonly cellComments?: 'none' | 'asDisplayed' | 'atEnd';
62
104
  }
63
105
  /**
64
106
  * ECMA-376 Part 1 §18.3.1.70 — `<printOptions>`. Controls what is rendered when
@@ -68,6 +110,11 @@ export interface XlsxPageSetup {
68
110
  */
69
111
  export interface XlsxPrintOptions {
70
112
  readonly gridLines?: boolean;
113
+ /**
114
+ * §18.3.1.70 `headings` — print the column letters across the top and the row
115
+ * numbers down the left, the way the sheet looks on screen. Off by default.
116
+ */
117
+ readonly headings?: boolean;
71
118
  readonly horizontalCentered?: boolean;
72
119
  readonly verticalCentered?: boolean;
73
120
  }
@@ -83,6 +130,10 @@ export interface ParsedWorksheet {
83
130
  readonly columns: ReadonlyArray<ColumnWidth>;
84
131
  readonly merges: ReadonlyArray<MergedRange>;
85
132
  readonly rowHeights: ReadonlyArray<RowHeight>;
133
+ /** §18.3.1.13 `<col style>` — the default style of a whole column span. */
134
+ readonly columnStyles?: ReadonlyArray<ColumnStyle>;
135
+ /** §18.3.1.73 `<row s customFormat="1">` — the default style of a whole row. */
136
+ readonly rowStyles?: ReadonlyArray<RowStyle>;
86
137
  /**
87
138
  * ECMA-376 §18.3.1.81 `<sheetFormatPr defaultRowHeight>` — the height, in
88
139
  * points, of every row that carries no `ht` of its own. A row in a
@@ -120,6 +171,12 @@ export interface ParsedWorksheet {
120
171
  readonly colBreaks?: ReadonlyArray<number>;
121
172
  /** §18.3.1.36 `<drawing r:id>` — the sheet's drawing part (charts/shapes). */
122
173
  readonly drawingRelId?: string;
174
+ /**
175
+ * §18.3.1.36 `<legacyDrawing r:id>` — the relationship to the sheet's VML
176
+ * drawing part. A form control put on the sheet by Excel's Forms toolbar is
177
+ * declared there and nowhere else.
178
+ */
179
+ readonly legacyDrawingRelId?: string;
123
180
  /** §18.3.1.18 `<conditionalFormatting>` — value-driven cell formats (E-SHEET SC1). */
124
181
  readonly conditionalFormats?: ReadonlyArray<ConditionalFormat>;
125
182
  /**
@@ -254,6 +311,8 @@ export interface XlsxFont {
254
311
  readonly bold?: boolean;
255
312
  readonly italic?: boolean;
256
313
  readonly underline?: boolean;
314
+ /** §18.8.37 `<strike/>` — the font is struck through. */
315
+ readonly strike?: boolean;
257
316
  readonly colorHex?: string;
258
317
  readonly name?: string;
259
318
  }
@@ -341,6 +400,18 @@ export interface XlsxStyles {
341
400
  export interface Dxf {
342
401
  readonly font?: XlsxFont;
343
402
  readonly fill?: XlsxFill;
403
+ /**
404
+ * §18.8.9 `<border>` inside a dxf — a rule may format a cell with nothing but
405
+ * an edge, and half the differential formats in a real workbook do exactly
406
+ * that (a rule under every year boundary, a box around a total).
407
+ */
408
+ readonly border?: XlsxBorder;
409
+ /**
410
+ * §18.8.9 `<numFmt formatCode>` — a rule may change how the VALUE reads, not
411
+ * just how the cell looks: two decimals where a threshold is crossed. Every
412
+ * dxf in new_cond_format_test.xlsx is one of these and nothing else.
413
+ */
414
+ readonly numberFormat?: string;
344
415
  }
345
416
  /**
346
417
  * ECMA-376 Part 1 §18.2.5 — `<definedName>`. A workbook-scoped (or sheet-scoped,
@@ -364,6 +435,12 @@ export interface CfRuleCellIs {
364
435
  readonly operator: CfOperator;
365
436
  readonly formulas: ReadonlyArray<string>;
366
437
  readonly dxfId: number;
438
+ /**
439
+ * The format itself, when the rule carries it instead of pointing at the
440
+ * workbook's table — the 2009 extension (`<x14:cfRule><x14:dxf>`) writes it
441
+ * inline, and `dxfId` names nothing there. Takes precedence when present.
442
+ */
443
+ readonly dxf?: Dxf;
367
444
  }
368
445
  /**
369
446
  * §18.3.1.11 ST_CfvoType — how a `<cfvo>` stop's threshold is derived.
@@ -406,6 +483,12 @@ export interface CfRuleDataBar {
406
483
  readonly colorHex: string;
407
484
  readonly minLength?: number;
408
485
  readonly maxLength?: number;
486
+ /**
487
+ * §18.3.1.28 `showValue` — false means the cell shows the BAR ONLY, with its
488
+ * number hidden. Excel's "Show Bar Only" checkbox; a dashboard uses it so the
489
+ * figure does not sit on top of its own gauge.
490
+ */
491
+ readonly showValue?: boolean;
409
492
  }
410
493
  /**
411
494
  * §18.3.1.49 `<cfRule type="iconSet">` — picks one glyph per cell from a named
@@ -432,6 +515,12 @@ export interface CfRuleTop10 {
432
515
  readonly percent: boolean;
433
516
  readonly bottom: boolean;
434
517
  readonly dxfId: number;
518
+ /**
519
+ * The format itself, when the rule carries it instead of pointing at the
520
+ * workbook's table — the 2009 extension (`<x14:cfRule><x14:dxf>`) writes it
521
+ * inline, and `dxfId` names nothing there. Takes precedence when present.
522
+ */
523
+ readonly dxf?: Dxf;
435
524
  }
436
525
  /**
437
526
  * §18.3.1.10 `<cfRule type="aboveAverage">` — cells above (default) or below the
@@ -445,6 +534,12 @@ export interface CfRuleAboveAverage {
445
534
  readonly equalAverage: boolean;
446
535
  readonly stdDev?: number;
447
536
  readonly dxfId: number;
537
+ /**
538
+ * The format itself, when the rule carries it instead of pointing at the
539
+ * workbook's table — the 2009 extension (`<x14:cfRule><x14:dxf>`) writes it
540
+ * inline, and `dxfId` names nothing there. Takes precedence when present.
541
+ */
542
+ readonly dxf?: Dxf;
448
543
  }
449
544
  /**
450
545
  * §18.3.1.10 `<cfRule type="duplicateValues" | "uniqueValues">` — cells whose
@@ -456,6 +551,12 @@ export interface CfRuleDupUnique {
456
551
  readonly type: 'duplicateValues' | 'uniqueValues';
457
552
  readonly priority: number;
458
553
  readonly dxfId: number;
554
+ /**
555
+ * The format itself, when the rule carries it instead of pointing at the
556
+ * workbook's table — the 2009 extension (`<x14:cfRule><x14:dxf>`) writes it
557
+ * inline, and `dxfId` names nothing there. Takes precedence when present.
558
+ */
559
+ readonly dxf?: Dxf;
459
560
  }
460
561
  /**
461
562
  * §18.3.1.10 `<cfRule type="containsText" | "notContainsText" | "beginsWith" |
@@ -468,6 +569,12 @@ export interface CfRuleText {
468
569
  readonly priority: number;
469
570
  readonly text: string;
470
571
  readonly dxfId: number;
572
+ /**
573
+ * The format itself, when the rule carries it instead of pointing at the
574
+ * workbook's table — the 2009 extension (`<x14:cfRule><x14:dxf>`) writes it
575
+ * inline, and `dxfId` names nothing there. Takes precedence when present.
576
+ */
577
+ readonly dxf?: Dxf;
471
578
  readonly formula?: string;
472
579
  }
473
580
  /**
@@ -483,6 +590,12 @@ export interface CfRuleExpression {
483
590
  readonly priority: number;
484
591
  readonly formula: string;
485
592
  readonly dxfId: number;
593
+ /**
594
+ * The format itself, when the rule carries it instead of pointing at the
595
+ * workbook's table — the 2009 extension (`<x14:cfRule><x14:dxf>`) writes it
596
+ * inline, and `dxfId` names nothing there. Takes precedence when present.
597
+ */
598
+ readonly dxf?: Dxf;
486
599
  }
487
600
  /** §18.18.82 ST_TimePeriod — the clock-relative window a `timePeriod` rule tests. */
488
601
  export type TimePeriodKind = 'today' | 'yesterday' | 'tomorrow' | 'last7Days' | 'thisWeek' | 'lastWeek' | 'nextWeek' | 'thisMonth' | 'lastMonth' | 'nextMonth';
@@ -499,6 +612,12 @@ export interface CfRuleTimePeriod {
499
612
  readonly priority: number;
500
613
  readonly timePeriod: TimePeriodKind;
501
614
  readonly dxfId: number;
615
+ /**
616
+ * The format itself, when the rule carries it instead of pointing at the
617
+ * workbook's table — the 2009 extension (`<x14:cfRule><x14:dxf>`) writes it
618
+ * inline, and `dxfId` names nothing there. Takes precedence when present.
619
+ */
620
+ readonly dxf?: Dxf;
502
621
  readonly formula?: string;
503
622
  }
504
623
  /** One conditional-format rule (`<cfRule>`): the union over the supported `type`s. */
@@ -542,6 +661,18 @@ export interface HeaderFooter {
542
661
  export interface FormControlRef {
543
662
  readonly name?: string;
544
663
  readonly relId: string;
664
+ /**
665
+ * §18.3.1.19 `@shapeId` — the id of this control's shape in the sheet's legacy
666
+ * VML drawing. It is what tells an ActiveX control's VML shape apart from a
667
+ * Forms-toolbar control that has no `<control>` entry at all.
668
+ */
669
+ readonly shapeId?: string;
670
+ /**
671
+ * §18.3.1.20 `<controlPr print>` — Excel's "Print object" checkbox. It
672
+ * defaults to true, and a control that clears it is on screen only: neither
673
+ * Excel nor Calc puts it on the page.
674
+ */
675
+ readonly print?: boolean;
545
676
  }
546
677
  /**
547
678
  * §18.3.* `<oleObjects><oleObject progId r:id>` — an embedded OLE / ActiveX
@@ -567,6 +698,12 @@ export interface SheetRichRun {
567
698
  readonly bold?: boolean;
568
699
  readonly italic?: boolean;
569
700
  readonly underline?: boolean;
701
+ /**
702
+ * §18.8.37 `<strike/>` on the run — struck-through text inside a cell that is
703
+ * otherwise not. 58315.xlsx crosses out the middle of "320-338 350", which is
704
+ * the whole point of the cell.
705
+ */
706
+ readonly strike?: boolean;
570
707
  readonly colorHex?: string;
571
708
  readonly sizePt?: number;
572
709
  /** §18.4.2 `<vertAlign>` — superscript / subscript within the cell text. */
@@ -38,8 +38,10 @@ function resolveRunProperties(runDirect, paragraphDirect, sheet) {
38
38
  }
39
39
  function computeRunProperties(runDirect, paragraphDirect, sheet) {
40
40
  let acc = mergeRun(DEFAULT_RESOLVED_RUN, sheet.defaultRunProperties);
41
- if (paragraphDirect.styleId) {
42
- const chain = resolveStyleChain(paragraphDirect.styleId, sheet);
41
+ if (paragraphDirect.inheritedRun) acc = mergeRun(acc, paragraphDirect.inheritedRun);
42
+ const styleId = paragraphDirect.styleId ?? defaultParagraphStyleId(sheet);
43
+ if (styleId) {
44
+ const chain = resolveStyleChain(styleId, sheet);
43
45
  acc = mergeRun(acc, chain.rPr);
44
46
  }
45
47
  if (runDirect.styleId) {
@@ -71,12 +73,27 @@ function resolveParagraphProperties(paragraphDirect, sheet) {
71
73
  }
72
74
  function computeParagraphProperties(paragraphDirect, sheet) {
73
75
  let acc = mergePar(DEFAULT_RESOLVED_PARAGRAPH, sheet.defaultParagraphProperties);
74
- if (paragraphDirect.styleId) {
75
- const chain = resolveStyleChain(paragraphDirect.styleId, sheet);
76
+ if (paragraphDirect.tableStyle ?? paragraphDirect.inheritedRun) acc = mergePar(acc, {
77
+ ...paragraphDirect.tableStyle,
78
+ ...paragraphDirect.inheritedRun ? { runProperties: paragraphDirect.inheritedRun } : {}
79
+ });
80
+ const styleId = paragraphDirect.styleId ?? defaultParagraphStyleId(sheet);
81
+ if (styleId) {
82
+ const chain = resolveStyleChain(styleId, sheet);
76
83
  acc = mergePar(acc, chain.pPr);
77
84
  }
78
85
  return mergePar(acc, paragraphDirect);
79
86
  }
87
+ /** The id of the `w:default="1"` paragraph style, cached per sheet. */
88
+ var defaultParagraphStyleCache = /* @__PURE__ */ new WeakMap();
89
+ function defaultParagraphStyleId(sheet) {
90
+ const hit = defaultParagraphStyleCache.get(sheet);
91
+ if (hit !== void 0) return hit ?? void 0;
92
+ let found = null;
93
+ for (const style of sheet.styles.values()) if (style.type === "paragraph" && style.isDefault) found = style.id;
94
+ defaultParagraphStyleCache.set(sheet, found);
95
+ return found ?? void 0;
96
+ }
80
97
  function resolveStyleChain(styleId, sheet) {
81
98
  const chain = [];
82
99
  const visited = /* @__PURE__ */ new Set();
@@ -108,40 +125,72 @@ function mergeRun(base, override) {
108
125
  bold: override.bold ?? base.bold,
109
126
  italic: override.italic ?? base.italic,
110
127
  underline: override.underline ?? base.underline,
128
+ ...override.underlineColorHex ?? base.underlineColorHex ? { underlineColorHex: override.underlineColorHex ?? base.underlineColorHex } : {},
111
129
  strike: override.strike ?? base.strike,
130
+ caps: override.caps ?? base.caps,
131
+ smallCaps: override.smallCaps ?? base.smallCaps,
112
132
  fontSizePt: override.fontSizePt ?? base.fontSizePt,
113
133
  colorHex: override.colorHex ?? base.colorHex,
114
134
  fontFamily: override.fontFamily ?? base.fontFamily,
115
135
  verticalAlign: override.verticalAlign ?? base.verticalAlign,
116
136
  rtl: override.rtl ?? base.rtl,
117
- ...lang !== void 0 ? { lang } : {}
137
+ ...lang !== void 0 ? { lang } : {},
138
+ ...(override.shadingColorHex ?? base.shadingColorHex) !== void 0 ? { shadingColorHex: override.shadingColorHex ?? base.shadingColorHex } : {},
139
+ ...(override.letterSpacingPt ?? base.letterSpacingPt) !== void 0 ? { letterSpacingPt: override.letterSpacingPt ?? base.letterSpacingPt } : {}
118
140
  };
119
141
  }
120
142
  function mergePar(base, override) {
121
143
  const outlineLevel = override.outlineLevel ?? base.outlineLevel;
122
144
  const styleId = override.styleId ?? base.styleId;
123
- const numbering = override.numbering ?? base.numbering;
145
+ const numbering = override.numbering ?? (override.numberingLevel !== void 0 && base.numbering !== void 0 ? {
146
+ ...base.numbering,
147
+ ilvl: override.numberingLevel
148
+ } : base.numbering);
149
+ const runProperties = override.runProperties ?? base.runProperties;
150
+ const frame = override.frame ?? base.frame;
151
+ const sectionBreak = override.sectionBreak ?? base.sectionBreak;
152
+ const textDirection = override.textDirection ?? base.textDirection;
153
+ const snapToGrid = override.snapToGrid ?? base.snapToGrid;
124
154
  return {
125
155
  alignment: override.alignment ?? base.alignment,
126
- spacingBefore: override.spacingBefore ?? base.spacingBefore,
127
- spacingAfter: override.spacingAfter ?? base.spacingAfter,
156
+ spacingBefore: override.spacingBeforeAuto ?? override.spacingBefore ?? base.spacingBefore,
157
+ spacingAfter: override.spacingAfterAuto ?? override.spacingAfter ?? base.spacingAfter,
128
158
  spacingLine: override.spacingLine ?? base.spacingLine,
129
159
  spacingLineRule: override.spacingLineRule ?? base.spacingLineRule,
130
160
  indentLeft: override.indentLeft ?? base.indentLeft,
131
161
  indentRight: override.indentRight ?? base.indentRight,
132
162
  indentFirstLine: override.indentFirstLine ?? base.indentFirstLine,
133
163
  pageBreakBefore: override.pageBreakBefore ?? base.pageBreakBefore,
164
+ contextualSpacing: override.contextualSpacing ?? base.contextualSpacing,
165
+ tabs: override.tabs ?? base.tabs,
134
166
  bidi: override.bidi ?? base.bidi,
167
+ ...override.borders ?? base.borders ? { borders: override.borders ?? base.borders } : {},
168
+ ...override.shading ?? base.shading ? { shading: override.shading ?? base.shading } : {},
135
169
  ...outlineLevel !== void 0 ? { outlineLevel } : {},
136
170
  ...styleId !== void 0 ? { styleId } : {},
137
- ...numbering !== void 0 ? { numbering } : {}
171
+ ...numbering !== void 0 ? { numbering } : {},
172
+ ...runProperties !== void 0 ? { runProperties } : {},
173
+ ...frame !== void 0 ? { frame } : {},
174
+ ...sectionBreak !== void 0 ? { sectionBreak } : {},
175
+ ...textDirection !== void 0 ? { textDirection } : {},
176
+ ...snapToGrid !== void 0 ? { snapToGrid } : {}
138
177
  };
139
178
  }
140
179
  function mergeRunPartial(base, override) {
141
180
  return copyDefined(base, override);
142
181
  }
143
182
  function mergeParPartial(base, override) {
144
- return copyDefined(base, override);
183
+ const out = copyDefined(base, override);
184
+ if (override.numbering === void 0 && override.numberingLevel !== void 0) {
185
+ if (base.numbering !== void 0) return {
186
+ ...out,
187
+ numbering: {
188
+ ...base.numbering,
189
+ ilvl: override.numberingLevel
190
+ }
191
+ };
192
+ }
193
+ return out;
145
194
  }
146
195
  function copyDefined(base, override) {
147
196
  const out = { ...base };
@@ -188,7 +237,13 @@ function resolveBodyStyles(body, sheet) {
188
237
  const visit = (el) => {
189
238
  if (el.kind === "paragraph") visitParagraph(el.paragraph);
190
239
  else if (el.kind === "table") for (const row of el.table.rows) for (const cell of row.cells) for (const child of cell.content) visit(child);
191
- else if (el.kind === "shape" && el.shape.text) for (const child of el.shape.text.content) visit(child);
240
+ else if (el.kind === "shape") {
241
+ const shapeText = (sh) => {
242
+ for (const child of sh.text?.content ?? []) visit(child);
243
+ for (const member of sh.children ?? []) shapeText(member.shape);
244
+ };
245
+ shapeText(el.shape);
246
+ }
192
247
  };
193
248
  for (const el of body) visit(el);
194
249
  return body;
@@ -22,8 +22,10 @@ function applyTableStyle(table, sheet) {
22
22
  const folded = foldTableStyleChain(styleId, sheet);
23
23
  if (!folded) return;
24
24
  const tp = table.properties;
25
+ const directBorders = tp.borders;
25
26
  if (!tp.borders && folded.base.borders) tp.borders = folded.base.borders;
26
27
  if (!tp.defaultCellMargins && folded.base.cellMargins) tp.defaultCellMargins = folded.base.cellMargins;
28
+ if (tp.indentPt === void 0 && folded.base.indentPt !== void 0) tp.indentPt = folded.base.indentPt;
27
29
  const look = table.properties.look ?? {};
28
30
  const rows = table.rows;
29
31
  const colCount = Math.max(table.grid.length, ...rows.map((r) => r.cells.reduce((s, c) => s + (c.properties.colSpan ?? 1), 0)));
@@ -33,8 +35,8 @@ function applyTableStyle(table, sheet) {
33
35
  for (const cell of row.cells) {
34
36
  const span = cell.properties.colSpan ?? 1;
35
37
  const layer = cellLayer(folded, look, {
36
- firstRow: r === 0,
37
- lastRow: r === rows.length - 1,
38
+ firstRow: r === 0 || row.properties.conditional?.firstRow === true,
39
+ lastRow: r === rows.length - 1 || row.properties.conditional?.lastRow === true,
38
40
  firstCol: colStart === 0,
39
41
  lastCol: colStart + span >= colCount,
40
42
  rowBand: bandIndex(r, look.firstRow === true, folded.rowBandSize),
@@ -42,20 +44,34 @@ function applyTableStyle(table, sheet) {
42
44
  noHBand: look.noHBand === true,
43
45
  noVBand: look.noVBand === true
44
46
  });
47
+ const pos = {
48
+ firstRow: r === 0 || row.properties.conditional?.firstRow === true,
49
+ lastRow: r === rows.length - 1 || row.properties.conditional?.lastRow === true,
50
+ firstCol: colStart === 0,
51
+ lastCol: colStart + span >= colCount
52
+ };
45
53
  colStart += span;
46
54
  if (!layer) continue;
47
- applyLayerToCell(cell, layer);
55
+ applyLayerToCell(cell, layer, directBorders, pos);
48
56
  }
49
57
  }
50
58
  }
51
- function applyLayerToCell(tableCell, layer) {
59
+ function applyLayerToCell(tableCell, layer, directBorders, pos) {
52
60
  const cell = tableCell;
53
61
  if (layer.shading && !cell.properties.shading) cell.properties.shading = layer.shading;
54
62
  if (layer.cellMargins && !cell.properties.margins) cell.properties.margins = layer.cellMargins;
55
63
  if (layer.borders) {
56
64
  const own = cell.properties.borders ?? {};
65
+ const fromStyle = { ...layer.borders };
66
+ if (directBorders) {
67
+ const stated = (side, outer) => (outer ? directBorders[side] : directBorders[side === "top" || side === "bottom" ? "insideH" : "insideV"]) !== void 0;
68
+ if (stated("top", pos.firstRow)) delete fromStyle.top;
69
+ if (stated("bottom", pos.lastRow)) delete fromStyle.bottom;
70
+ if (stated("left", pos.firstCol)) delete fromStyle.left;
71
+ if (stated("right", pos.lastCol)) delete fromStyle.right;
72
+ }
57
73
  const merged = {
58
- ...layer.borders,
74
+ ...fromStyle,
59
75
  ...definedOnly(own)
60
76
  };
61
77
  cell.properties.borders = merged;
@@ -64,12 +80,18 @@ function applyLayerToCell(tableCell, layer) {
64
80
  if (el.kind !== "paragraph") continue;
65
81
  const p = el.paragraph;
66
82
  if (layer.paragraphProperties) p.properties = {
67
- ...layer.paragraphProperties,
68
- ...definedOnly(p.properties)
83
+ ...p.properties,
84
+ tableStyle: {
85
+ ...p.properties.tableStyle,
86
+ ...layer.paragraphProperties
87
+ }
69
88
  };
70
- if (layer.runProperties) for (const run of p.runs) run.properties = {
71
- ...layer.runProperties,
72
- ...definedOnly(run.properties)
89
+ if (layer.runProperties) p.properties = {
90
+ ...p.properties,
91
+ inheritedRun: {
92
+ ...p.properties.inheritedRun,
93
+ ...layer.runProperties
94
+ }
73
95
  };
74
96
  }
75
97
  }
@@ -79,7 +101,8 @@ function bandIndex(index, skipFirst, bandSize) {
79
101
  return Math.floor(adjusted / Math.max(1, bandSize));
80
102
  }
81
103
  function cellLayer(folded, look, pos) {
82
- const layers = [folded.base];
104
+ const { borders: _tableWide, ...withoutBorders } = folded.base;
105
+ const layers = [withoutBorders];
83
106
  const cond = (t) => folded.conditions.get(t);
84
107
  if (!pos.noVBand && pos.colBand >= 0) layers.push(pos.colBand % 2 === 0 ? cond("band1Vert") : cond("band2Vert"));
85
108
  if (!pos.noHBand && pos.rowBand >= 0) layers.push(pos.rowBand % 2 === 0 ? cond("band1Horz") : cond("band2Horz"));
@@ -145,6 +168,7 @@ function mergeLayer(base, override) {
145
168
  ...base.cellMargins,
146
169
  ...definedOnly(override.cellMargins ?? {})
147
170
  } } : {},
171
+ ...(override.indentPt ?? base.indentPt) !== void 0 ? { indentPt: override.indentPt ?? base.indentPt } : {},
148
172
  ...override.shading ?? base.shading ? { shading: override.shading ?? base.shading } : {},
149
173
  ...override.runProperties ?? base.runProperties ? { runProperties: {
150
174
  ...base.runProperties,