reamkit 1.15.3 → 1.16.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 (95) hide show
  1. package/dist/esm/core/converter/facade.d.ts +5 -0
  2. package/dist/esm/core/converter/ream.d.ts +6 -0
  3. package/dist/esm/core/converter/ream.js +34 -8
  4. package/dist/esm/core/document-model/index.d.ts +1 -1
  5. package/dist/esm/core/document-model/types.d.ts +187 -1
  6. package/dist/esm/core/drawingml/chart-geometry.d.ts +28 -0
  7. package/dist/esm/core/drawingml/chart-geometry.js +371 -88
  8. package/dist/esm/core/drawingml/chart-parser.js +262 -11
  9. package/dist/esm/core/drawingml/colors.d.ts +6 -6
  10. package/dist/esm/core/drawingml/colors.js +58 -18
  11. package/dist/esm/core/drawingml/preset-geometry.js +7 -6
  12. package/dist/esm/core/drawingml/sparkline-geometry.js +6 -4
  13. package/dist/esm/core/drawingml/theme-parser.d.ts +41 -0
  14. package/dist/esm/core/drawingml/theme-parser.js +74 -1
  15. package/dist/esm/core/font/ttf-subset.js +26 -1
  16. package/dist/esm/core/images.js +172 -43
  17. package/dist/esm/core/indexed-colors.d.ts +11 -0
  18. package/dist/esm/core/indexed-colors.js +81 -0
  19. package/dist/esm/core/ir/sheet.d.ts +67 -3
  20. package/dist/esm/{excel → core}/number-format.d.ts +37 -0
  21. package/dist/esm/core/number-format.js +800 -0
  22. package/dist/esm/core/opc/alternate-content.d.ts +13 -0
  23. package/dist/esm/core/opc/alternate-content.js +72 -0
  24. package/dist/esm/core/opc/core-properties.js +1 -0
  25. package/dist/esm/core/opc/package.d.ts +14 -1
  26. package/dist/esm/core/opc/package.js +43 -4
  27. package/dist/esm/core/opc/relationships.js +1 -0
  28. package/dist/esm/core/opc/xml-entities.d.ts +12 -0
  29. package/dist/esm/core/opc/xml-entities.js +91 -0
  30. package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
  31. package/dist/esm/core/spreadsheet-model/types.d.ts +137 -0
  32. package/dist/esm/core/vector.d.ts +13 -0
  33. package/dist/esm/excel/activex-parser.d.ts +9 -0
  34. package/dist/esm/excel/activex-parser.js +16 -1
  35. package/dist/esm/excel/column-bands.d.ts +26 -1
  36. package/dist/esm/excel/column-bands.js +156 -20
  37. package/dist/esm/excel/comments-parser.js +5 -3
  38. package/dist/esm/excel/conditional-format.d.ts +25 -2
  39. package/dist/esm/excel/conditional-format.js +63 -19
  40. package/dist/esm/excel/escaped-text.d.ts +9 -0
  41. package/dist/esm/excel/escaped-text.js +20 -0
  42. package/dist/esm/excel/form-control-parser.js +1 -0
  43. package/dist/esm/excel/formula/dates.js +1 -1
  44. package/dist/esm/excel/header-footer.d.ts +9 -1
  45. package/dist/esm/excel/header-footer.js +162 -14
  46. package/dist/esm/excel/index.d.ts +1 -1
  47. package/dist/esm/excel/index.js +2 -2
  48. package/dist/esm/excel/pivot-table-parser.js +1 -0
  49. package/dist/esm/excel/print-model.d.ts +75 -0
  50. package/dist/esm/excel/print-model.js +902 -77
  51. package/dist/esm/excel/printer-settings.d.ts +16 -0
  52. package/dist/esm/excel/printer-settings.js +36 -0
  53. package/dist/esm/excel/rich-value.d.ts +13 -0
  54. package/dist/esm/excel/rich-value.js +120 -0
  55. package/dist/esm/excel/shared-strings-parser.js +11 -7
  56. package/dist/esm/excel/sheet-drawing.d.ts +11 -0
  57. package/dist/esm/excel/sheet-drawing.js +26 -3
  58. package/dist/esm/excel/sheet-shape-parser.d.ts +53 -1
  59. package/dist/esm/excel/sheet-shape-parser.js +461 -32
  60. package/dist/esm/excel/sheet-to-flow.d.ts +23 -2
  61. package/dist/esm/excel/sheet-to-flow.js +551 -36
  62. package/dist/esm/excel/slicer-parser.js +1 -0
  63. package/dist/esm/excel/styles-parser.d.ts +30 -2
  64. package/dist/esm/excel/styles-parser.js +177 -40
  65. package/dist/esm/excel/table-parser.js +1 -0
  66. package/dist/esm/excel/vml-drawing.d.ts +68 -0
  67. package/dist/esm/excel/vml-drawing.js +158 -0
  68. package/dist/esm/excel/workbook-parser.d.ts +5 -0
  69. package/dist/esm/excel/workbook-parser.js +5 -1
  70. package/dist/esm/excel/worksheet-parser.d.ts +2 -1
  71. package/dist/esm/excel/worksheet-parser.js +149 -28
  72. package/dist/esm/excel/xlsx-reader.js +271 -33
  73. package/dist/esm/excel/xlsx-to-pdf.js +12 -1
  74. package/dist/esm/html/html-writer.js +11 -2
  75. package/dist/esm/layout/page-doc.d.ts +26 -0
  76. package/dist/esm/layout/styled-layout.d.ts +2 -0
  77. package/dist/esm/layout/styled-layout.js +493 -64
  78. package/dist/esm/pdf/cid-font.js +20 -9
  79. package/dist/esm/pdf/objects.d.ts +13 -0
  80. package/dist/esm/pdf/objects.js +18 -1
  81. package/dist/esm/pdf/styled-page-emitter.js +164 -32
  82. package/dist/esm/pdf/text-page-renderer.js +1 -0
  83. package/dist/esm/pdf/vector-graphics.d.ts +3 -1
  84. package/dist/esm/pdf/vector-graphics.js +19 -2
  85. package/dist/esm/pptx/pptx-reader.js +1 -0
  86. package/dist/esm/pptx/slide-parser.js +12 -1
  87. package/dist/esm/svg/svg-writer.js +23 -4
  88. package/dist/esm/word/document-parser.js +1 -0
  89. package/dist/esm/word/drawing-parser.d.ts +34 -1
  90. package/dist/esm/word/drawing-parser.js +52 -2
  91. package/dist/esm/word/numbering-parser.js +1 -0
  92. package/dist/esm/word/settings-parser.js +1 -0
  93. package/dist/esm/word/styles-parser.js +1 -0
  94. package/package.json +7 -3
  95. package/dist/esm/excel/number-format.js +0 -476
@@ -24,6 +24,11 @@ export interface ConvertOptions extends ConvertDocxOptions {
24
24
  * never the wall clock; omitted ⇒ those clock-relative rules no-op.
25
25
  */
26
26
  readonly now?: Date;
27
+ /**
28
+ * §18.3.1.34 `&F` — the workbook's file name, for a spreadsheet whose header
29
+ * or footer prints it. Absent, the code is dropped.
30
+ */
31
+ readonly fileName?: string;
27
32
  /**
28
33
  * Font resolution chain (ir-design §8). When set (and no caller `fonts`),
29
34
  * the facade resolves the default font set through these providers — e.g.
@@ -54,6 +54,12 @@ export interface ReamConvertOptions extends Omit<StyledRenderOptions, 'registry'
54
54
  * unchanged.
55
55
  */
56
56
  readonly now?: Date;
57
+ /**
58
+ * §18.3.1.34 `&F` — the workbook's file name, for a spreadsheet whose header
59
+ * or footer prints it. A byte-oriented reader cannot know it; supplied here,
60
+ * the code resolves, and omitted it is dropped exactly as before.
61
+ */
62
+ readonly fileName?: string;
57
63
  }
58
64
  /**
59
65
  * The object face of the library: parse a document once into the format-neutral
@@ -1,5 +1,6 @@
1
1
  import { fetchFontSet } from "../fonts/remote-fonts.js";
2
2
  import { FontRegistry } from "../font/font-registry.js";
3
+ import { createFontMeasure } from "../font/measure.js";
3
4
  import { ConversionLossError } from "../ir/loss.js";
4
5
  import { layoutStyledDocument } from "../../layout/styled-layout.js";
5
6
  import { signPdf } from "../../pdf/signature.js";
@@ -12,8 +13,14 @@ import { writeXlsx } from "../../excel/xlsx-writer.js";
12
13
  import { writeHtml } from "../../html/html-writer.js";
13
14
  import { writeSvg } from "../../svg/svg-writer.js";
14
15
  import { resolveDocxAutoFonts } from "../../word/docx-to-pdf.js";
16
+ import { isCfb, openCfb } from "../ole/cfb.js";
15
17
  import { DEFAULT_READERS, resolveFontsViaChain, toFlowDoc } from "./facade.js";
16
18
  //#region src/core/converter/ream.ts
19
+ /**
20
+ * The point size Excel's column-width unit is quoted at — its default theme
21
+ * font is 11 pt, and 8.43 of its digits are the documented 64 px column.
22
+ */
23
+ var DEFAULT_WORKBOOK_FONT_PT = 11;
17
24
  /** OOXML / legacy MIME types by reader id, for the PDF/A-3 embedded source file. */
18
25
  var SOURCE_MIME = {
19
26
  docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
@@ -71,7 +78,10 @@ var Ream = class Ream {
71
78
  static parse(bytes, options = {}) {
72
79
  const readers = options.readers ?? DEFAULT_READERS;
73
80
  const reader = readers.find((r) => r.sniff(bytes));
74
- if (!reader) throw new Error(`Unrecognized document format (readers: ${readers.map((r) => r.id).join(", ")})`);
81
+ if (!reader) {
82
+ if (isEncryptedOoxml(bytes)) throw new Error("Password-protected OOXML document (ECMA-376 §2.3 EncryptedPackage) — re-save it without a password");
83
+ throw new Error(`Unrecognized document format (readers: ${readers.map((r) => r.id).join(", ")})`);
84
+ }
75
85
  const { doc, losses } = reader.read(bytes, { password: options.password });
76
86
  const sheet = doc.kind === "sheet" ? doc : void 0;
77
87
  return new Ream(toFlowDoc(doc), sheet, losses, bytes, reader.id);
@@ -106,7 +116,10 @@ var Ream = class Ream {
106
116
  */
107
117
  async convertWithReport(to, options = {}) {
108
118
  const losses = [...this.losses];
109
- const flow = this.sheet && options.now ? projectSheetDoc(this.sheet, { now: options.now }) : this.flow;
119
+ const flow = this.sheet && (options.now || options.fileName) ? projectSheetDoc(this.sheet, {
120
+ ...options.now ? { now: options.now } : {},
121
+ ...options.fileName ? { fileName: options.fileName } : {}
122
+ }) : this.flow;
110
123
  if (to === "html") {
111
124
  const html = writeHtml(flow);
112
125
  losses.push(...html.losses);
@@ -137,10 +150,15 @@ var Ream = class Ream {
137
150
  }
138
151
  const { fonts, registriesByFamily } = await this.resolveFonts(options, losses);
139
152
  const registry = FontRegistry.fromBytes(fonts);
153
+ const paginated = this.sheet ? projectSheetDoc(this.sheet, {
154
+ ...options.now ? { now: options.now } : {},
155
+ ...options.fileName ? { fileName: options.fileName } : {},
156
+ digitWidthPt: createFontMeasure(registry.resolveByStyle(false, false).parsed).textWidthPt("0", DEFAULT_WORKBOOK_FONT_PT)
157
+ }) : flow;
140
158
  if (to === "svg") {
141
- const svg = writeSvg(layoutStyledDocument(flow.body, {
159
+ const svg = writeSvg(layoutStyledDocument(paginated.body, {
142
160
  registry,
143
- ...flowRenderOptions(flow)
161
+ ...flowRenderOptions(paginated)
144
162
  }));
145
163
  losses.push(...svg.losses);
146
164
  this.enforceStrict(options, losses);
@@ -150,8 +168,8 @@ var Ream = class Ream {
150
168
  };
151
169
  }
152
170
  const { fonts: _a, fontBytes: _b, fontFamily: _c, fontFetch: _d, fontProviders: _e, strict: _f, embedSource, signature, info: callerInfo, attachments: callerAttachments, ...renderOptions } = options;
153
- const info = flow.info || callerInfo ? {
154
- ...flow.info,
171
+ const info = paginated.info || callerInfo ? {
172
+ ...paginated.info,
155
173
  ...callerInfo
156
174
  } : void 0;
157
175
  const attachments = [...callerAttachments ?? []];
@@ -165,13 +183,13 @@ var Ream = class Ream {
165
183
  const styled = {
166
184
  registry,
167
185
  ...registriesByFamily ? { registriesByFamily } : {},
168
- ...flowRenderOptions(flow),
186
+ ...flowRenderOptions(paginated),
169
187
  ...info ? { info } : {},
170
188
  ...attachments.length > 0 ? { attachments } : {},
171
189
  ...signature ? { signaturePlaceholder: signature } : {},
172
190
  ...renderOptions
173
191
  };
174
- let pdf = styled.encrypt ? await renderStyledPdfEncrypted(flow.body, styled) : renderStyledPdf(flow.body, styled);
192
+ let pdf = styled.encrypt ? await renderStyledPdfEncrypted(paginated.body, styled) : renderStyledPdf(paginated.body, styled);
175
193
  if (signature) pdf = await signPdf(pdf, signature);
176
194
  this.enforceStrict(options, losses);
177
195
  return {
@@ -214,5 +232,13 @@ var Ream = class Ream {
214
232
  if (options.strict && losses.length > 0) throw new ConversionLossError(losses[0]);
215
233
  }
216
234
  };
235
+ function isEncryptedOoxml(bytes) {
236
+ if (!isCfb(bytes)) return false;
237
+ try {
238
+ return openCfb(bytes).hasStream("EncryptedPackage");
239
+ } catch {
240
+ return false;
241
+ }
242
+ }
217
243
  //#endregion
218
244
  export { Ream };
@@ -5,4 +5,4 @@
5
5
  *
6
6
  * @packageDocumentation
7
7
  */
8
- export type { AbstractNumbering, Alignment, Border, BorderStyle, BodyElement, Comment, CellBorders, CellMerge, DocumentInfo, CellMargins, CellProperties, CellShading, CellDataBar, CellIcon, CellIconShape, CellSparkline, Chart, ChartBlock, ChartDataPoint, ChartSeries, ChartType, CustomGeometry, CustomPathCmd, DocumentModel, FontFamilyMap, HeaderFooterReference, HeaderFooterType, ImageBlock, InlineImage, MathAccent, MathBar, MathDelimiter, MathEqArray, MathFraction, MathFunc, MathGroupChr, MathLimit, MathMatrix, MathNary, MathNode, MathRadical, MathRow, MathRun, MathScript, Numbering, NumberingFormat, NumberingInstance, NumberingLevel, NumberingReference, PageMargins, PageSize, Paragraph, ParagraphProperties, Run, RunProperties, RowProperties, Section, FloatAnchor, SectionColumns, SectionProperties, ShapeBlock, ShapeDash, ShapeFill, ShapeFillKind, ShapeGeometry, ShapeLine, ShapeTextBody, ShapeTransform, Style, StyleSheet, StyleType, Table, TableCell, TableLook, TableProperties, TableStyleCondition, TableStyleConditionType, TableStyleLayer, TableRow, UnderlineStyle, VerticalAlign, } from './types.js';
8
+ export type { AbstractNumbering, Alignment, Border, BorderStyle, BodyElement, Comment, CellBorders, CellMerge, DocumentInfo, CellMargins, CellProperties, CellShading, CellDataBar, CellIcon, CellIconShape, CellSparkline, Chart, ChartBlock, ChartDataPoint, ChartLineStyle, ChartMarker, ChartMarkerSymbol, ChartSeries, ChartType, CustomGeometry, CustomPathCmd, DocumentModel, FontFamilyMap, HeaderFooterReference, HeaderFooterType, ImageBlock, InlineImage, MathAccent, MathBar, MathDelimiter, MathEqArray, MathFraction, MathFunc, MathGroupChr, MathLimit, MathMatrix, MathNary, MathNode, MathRadical, MathRow, MathRun, MathScript, Numbering, NumberingFormat, NumberingInstance, NumberingLevel, NumberingReference, PageMargins, PageSize, Paragraph, ParagraphProperties, Run, RunProperties, RowProperties, Section, FloatAnchor, SectionColumns, SectionProperties, ShapeBlock, ShapeShadow, ShapeDash, ShapeFill, ShapeFillKind, ShapeGeometry, ShapeLine, ShapeTextBody, ShapeTransform, Style, StyleSheet, StyleType, Table, TableCell, TableLook, TableProperties, TableStyleCondition, TableStyleConditionType, TableStyleLayer, TableRow, UnderlineStyle, VerticalAlign, } from './types.js';
@@ -385,7 +385,7 @@ export interface StyleSheet {
385
385
  readonly styles: ReadonlyMap<string, Style>;
386
386
  }
387
387
  /** §17.18.2 ST_Border — a cell-border line style (the subset Ream renders). */
388
- export type BorderStyle = 'none' | 'single' | 'double' | 'thick' | 'dotted' | 'dashed';
388
+ export type BorderStyle = 'none' | 'single' | 'double' | 'thick' | 'dotted' | 'dashed' | 'dashDot' | 'dashDotDot';
389
389
  /** One border edge: its line style plus optional width and colour. */
390
390
  export interface Border {
391
391
  readonly style: BorderStyle;
@@ -428,6 +428,12 @@ export interface CellDataBar {
428
428
  readonly fraction: number;
429
429
  readonly colorHex: string;
430
430
  readonly startFraction?: number;
431
+ /**
432
+ * The bar runs LEFT from the axis (a negative value in a mixed-sign range),
433
+ * so its solid end is its right one. Excel fades a data bar away from the
434
+ * axis, and which way that is depends on the sign.
435
+ */
436
+ readonly negative?: boolean;
431
437
  }
432
438
  /**
433
439
  * A conditional-format icon: a small glyph at the cell's left, chosen by the
@@ -478,6 +484,18 @@ export interface CellProperties {
478
484
  readonly merge?: CellMerge;
479
485
  readonly borders?: CellBorders;
480
486
  readonly margins?: CellMargins;
487
+ /**
488
+ * How many of the spanned columns the cell's own PAINT covers, when that is
489
+ * fewer than `colSpan`.
490
+ *
491
+ * Text overflow is modelled as a span — a cell whose value does not fit runs
492
+ * across the empty neighbours to its right — but Excel runs the TEXT over an
493
+ * unpainted cell without painting it. With one width for both, a filled cell
494
+ * carried its fill along: 54436.xlsx ran its pivot header's blue a whole
495
+ * column past the pivot. Absent ⇒ the paint covers the whole span, which is
496
+ * what a merge wants.
497
+ */
498
+ readonly paintColumns?: number;
481
499
  readonly shading?: CellShading;
482
500
  readonly dataBar?: CellDataBar;
483
501
  readonly icon?: CellIcon;
@@ -487,6 +505,28 @@ export interface CellProperties {
487
505
  * dropdown affordance at the cell's right edge (a small button + ▾ glyph).
488
506
  */
489
507
  readonly dropdown?: boolean;
508
+ /**
509
+ * The cell's text is not allowed to wrap: it renders on one line and whatever
510
+ * does not fit the cell box is cut, as a spreadsheet cell without `wrapText`
511
+ * does. Only the paginated layout honours it — an HTML view has no page edge
512
+ * to clip against and lets the browser decide.
513
+ */
514
+ readonly noWrap?: boolean;
515
+ /**
516
+ * The cell holds a NUMBER under a format of its own, so it may not be shown
517
+ * truncated: a date cut to "4/30/201" is not a shorter date, it is the wrong
518
+ * one. Excel and LibreOffice fill such a cell with `#` instead, which says
519
+ * "widen me" and cannot be misread. Text is exempt — a clipped word is still
520
+ * recognisably that word.
521
+ */
522
+ readonly hashOnOverflow?: boolean;
523
+ /**
524
+ * Where the cell's content sits in a box taller than itself. A spreadsheet
525
+ * cell defaults to `'bottom'` — §18.8.1, and both Excel and LibreOffice do it
526
+ * — which is visible on any row taller than its text. Absent ⇒ the top, which
527
+ * is a word-processor table's default.
528
+ */
529
+ readonly verticalAlign?: 'top' | 'center' | 'bottom';
490
530
  }
491
531
  /** §17.4.81 `w:trPr` — a table row's properties: height, split/header flags. */
492
532
  export interface RowProperties {
@@ -668,6 +708,21 @@ export interface ShapeTextBody {
668
708
  * paragraph's properties for block spacing / alignment, mirroring
669
709
  * {@link ImageBlock}.
670
710
  */
711
+ /**
712
+ * §20.1.8.40 `a:outerShdw` — the drop shadow under a shape: how far it is
713
+ * displaced, how soft its edge is, and in what colour. `dxPt`/`dyPt` are the
714
+ * displacement in page coordinates (y grows DOWN), resolved from the spec's
715
+ * polar `dist`/`dir`.
716
+ */
717
+ export interface ShapeShadow {
718
+ readonly dxPt: number;
719
+ readonly dyPt: number;
720
+ /** `blurRad` in points; 0 is a hard edge. */
721
+ readonly blurPt: number;
722
+ readonly colorHex: string;
723
+ /** 0..1, from the shadow colour's `a:alpha` (absent ⇒ opaque). */
724
+ readonly alpha: number;
725
+ }
671
726
  export interface ShapeBlock {
672
727
  /** §20.4.2.3 — present when the drawing is anchored (floating). */
673
728
  readonly float?: FloatAnchor;
@@ -678,6 +733,8 @@ export interface ShapeBlock {
678
733
  readonly line?: ShapeLine;
679
734
  readonly transform?: ShapeTransform;
680
735
  readonly text?: ShapeTextBody;
736
+ /** §20.1.8.40 — the shape's drop shadow, direct or from its style reference. */
737
+ readonly shadow?: ShapeShadow;
681
738
  readonly paragraphProperties: ParagraphProperties;
682
739
  /** `wp:docPr @descr/@title` — alternate text for the tagged-PDF Figure (`/Alt`). */
683
740
  readonly altText?: string;
@@ -699,16 +756,91 @@ export interface ChartDataPoint {
699
756
  /** One chart data series (`c:ser`): its name, values and colour overrides. */
700
757
  export interface ChartSeries {
701
758
  readonly name?: string;
759
+ /**
760
+ * §21.2.2 — the chart group this series came from, when it is NOT the group
761
+ * that gave {@link Chart.type}. A `c:plotArea` may hold several groups: a
762
+ * combo chart writes `c:barChart` and `c:lineChart` side by side, and reading
763
+ * only the first drops the other's series off the page entirely (57362.xlsx
764
+ * loses its line). Absent ⇒ the series draws as the chart's own type.
765
+ */
766
+ readonly type?: ChartType;
767
+ /**
768
+ * §21.2.2.9 `c:axId` — the series plots against the SECONDARY value axis: its
769
+ * group names a `c:valAx` other than the one the first group uses. 57362.xlsx
770
+ * puts its line on an axis of its own at `axPos="r"`, and plotting it on the
771
+ * primary scale puts every point at the wrong height whenever the two ranges
772
+ * differ.
773
+ */
774
+ readonly secondaryAxis?: boolean;
702
775
  readonly values: ReadonlyArray<number>;
703
776
  readonly xValues?: ReadonlyArray<number>;
704
777
  readonly colorHex?: string;
705
778
  readonly pointColors?: ReadonlyArray<ChartDataPoint>;
779
+ /**
780
+ * §21.2.2.49 `c:dLbl/c:tx` — a data label the author typed rather than one
781
+ * the chart computes, by point index. Excel and Calc print it verbatim: it
782
+ * is the only place a label like "Промышленные потребители; 22,7млрд.кВтч;
783
+ * 67,3%" exists, and generating one from the value instead loses the whole
784
+ * sentence.
785
+ */
786
+ readonly pointLabels?: ReadonlyArray<{
787
+ readonly idx: number;
788
+ readonly text: string;
789
+ }>;
790
+ /**
791
+ * §21.2.2.59 `c:val/c:numRef/c:f` and §21.2.2.215 `c:tx/c:strRef/c:f` — where
792
+ * the series reads its numbers and its name FROM, when the chart part carries
793
+ * no cache of them. A chart written without caches is not a chart without
794
+ * data: the reader resolves these against the workbook.
795
+ */
796
+ readonly valuesRef?: string;
797
+ readonly nameRef?: string;
798
+ /**
799
+ * §21.2.2.106 `c:marker` — the symbol this series stamps on each of its
800
+ * points. Absent ⇒ the reader's own default.
801
+ */
802
+ readonly marker?: ChartMarker;
803
+ /**
804
+ * §21.2.2.198 `c:ser/c:spPr/a:ln` — the series' OWN rule. `<a:noFill/>` is
805
+ * how Excel writes "scatter with markers only": the group still says
806
+ * `lineMarker`, and it is this line that says the points are not joined.
807
+ * SimpleScatterChart.xlsx is two loose dots in both references and we ran a
808
+ * line between them.
809
+ */
810
+ readonly line?: ChartLineStyle;
811
+ }
812
+ /**
813
+ * §21.2.2.107 `c:symbol` (ST_MarkerStyle) — the shape of a scatter/line
814
+ * series' point marker. `auto` and `picture` are left to the reader, so they
815
+ * are not carried here.
816
+ */
817
+ export type ChartMarkerSymbol = 'circle' | 'dash' | 'diamond' | 'dot' | 'none' | 'plus' | 'square' | 'star' | 'triangle' | 'x';
818
+ /**
819
+ * §21.2.2.106 `c:marker` — a series' point symbol and its size in points
820
+ * (§21.2.2.153 `c:size`, 2–72). chartTitle_noTitle.xlsx asks for a 5pt circle
821
+ * at every point and both references draw one; we stamped a square.
822
+ */
823
+ export interface ChartMarker {
824
+ readonly symbol: ChartMarkerSymbol;
825
+ readonly sizePt?: number;
826
+ }
827
+ /**
828
+ * §21.2.2.196 `c:spPr/a:ln` on an axis or its gridlines — the rule the author
829
+ * gave it. `none` is `<a:ln><a:noFill/>`, which means the axis draws no line at
830
+ * all: 57362.xlsx hides its secondary value axis that way and keeps its labels.
831
+ */
832
+ export interface ChartLineStyle {
833
+ readonly none?: boolean;
834
+ readonly colorHex?: string;
835
+ readonly widthPt?: number;
706
836
  }
707
837
  /** A parsed chart (§21.2): its type, title, categories, series and rendering options. */
708
838
  export interface Chart {
709
839
  readonly type: ChartType;
710
840
  readonly title?: string;
711
841
  readonly categories: ReadonlyArray<string>;
842
+ /** §21.2.2.24 `c:cat/…/c:f` — where the categories live, when uncached. */
843
+ readonly categoriesRef?: string;
712
844
  readonly series: ReadonlyArray<ChartSeries>;
713
845
  readonly hasLegend: boolean;
714
846
  readonly legendPos?: 'r' | 'l' | 't' | 'b';
@@ -716,8 +848,62 @@ export interface Chart {
716
848
  readonly grouping?: 'clustered' | 'stacked' | 'percentStacked' | 'standard';
717
849
  readonly doughnut?: boolean;
718
850
  readonly showValues?: boolean;
851
+ /**
852
+ * §21.2.2.75 `c:gapWidth` — the gap between category slots as a percentage
853
+ * of the bar width. Absent ⇒ the schema's 150.
854
+ */
855
+ readonly gapPercent?: number;
719
856
  readonly catAxisTitle?: string;
857
+ /**
858
+ * §21.2.2.134 `c:catAx/c:scaling/c:orientation` = `maxMin` — the category
859
+ * axis runs the other way. A ranked bar chart is written this way so its
860
+ * first row reads at the TOP (dataValidationTableRange.xlsx ranks 38 counties
861
+ * and we printed the ranking upside down).
862
+ */
863
+ readonly catAxisReversed?: boolean;
720
864
  readonly valAxisTitle?: string;
865
+ /** §21.2.2.168 — the title of the secondary value axis, when one is drawn. */
866
+ readonly secondaryValAxisTitle?: string;
867
+ /**
868
+ * §21.2.2.161 `c:scatterStyle` — whether a scatter's points are joined by a
869
+ * line, marked, or both. The schema's default is `marker`; Excel writes
870
+ * `lineMarker` for the chart most people insert.
871
+ */
872
+ readonly scatterStyle?: 'none' | 'line' | 'lineMarker' | 'marker' | 'smooth' | 'smoothMarker';
873
+ /**
874
+ * §21.2.2.106 `c:marker` on a `c:lineChart` — whether the group's series mark
875
+ * their data points. WithChart.xlsx asks for them and we drew bare lines.
876
+ */
877
+ readonly lineMarkers?: boolean;
878
+ /** §21.2.2.196 — the category axis's own rule. */
879
+ readonly catAxisLine?: ChartLineStyle;
880
+ /** §21.2.2.196 — the value axis's own rule. */
881
+ readonly valAxisLine?: ChartLineStyle;
882
+ /** §21.2.2.196 — the secondary value axis's own rule. */
883
+ readonly secondaryValAxisLine?: ChartLineStyle;
884
+ /** §21.2.2.87 `c:majorGridlines/c:spPr/a:ln` — the gridlines' own rule. */
885
+ readonly gridLine?: ChartLineStyle;
886
+ /**
887
+ * §21.2.2.157 `c:valAx/c:scaling/c:min|c:max` — the value axis the AUTHOR
888
+ * fixed. Absent means "auto", and only then is the range read off the data:
889
+ * a chart whose cells all read zero still has the axis its author pinned, and
890
+ * scaling it to the data drew 0…1 where every reader draws 0…300.
891
+ */
892
+ readonly valAxisMin?: number;
893
+ readonly valAxisMax?: number;
894
+ /**
895
+ * §21.2.2.198 `c:chartSpace/c:spPr` — the frame around the whole chart: its
896
+ * background fill and its outline. Excel writes both on every chart it
897
+ * creates, and both references draw them.
898
+ */
899
+ readonly frameFillHex?: string;
900
+ readonly frameLineHex?: string;
901
+ /**
902
+ * §21.2.2.121 `c:valAx/c:numFmt@formatCode` — the number format the value
903
+ * axis's tick labels and the data labels are drawn in, in the same code
904
+ * grammar cells use (§18.8.31). Absent ⇒ a plain numeric render.
905
+ */
906
+ readonly numberFormat?: string;
721
907
  /**
722
908
  * MS-ODRAWXML `chartColorStyle` (`colorsN.xml`): the cycle of series colours;
723
909
  * overrides the built-in Office accent cycle when present.
@@ -51,6 +51,13 @@ export interface ChartLabel {
51
51
  readonly sizePt: number;
52
52
  readonly colorHex: string;
53
53
  readonly align: LabelAlign;
54
+ /**
55
+ * §21.2.2.216 `c:title/c:txPr/a:bodyPr@rot` — a value-axis title reads
56
+ * bottom-to-top (`rot="-5400000"`, the default every reader applies). Degrees
57
+ * counter-clockwise about the anchor; `align` then runs along the ROTATED
58
+ * reading direction.
59
+ */
60
+ readonly rotationDeg?: number;
54
61
  }
55
62
  /**
56
63
  * The fully laid-out chart: rectangles, polylines, wedges and labels (plus
@@ -64,6 +71,15 @@ export interface ChartScene {
64
71
  readonly wedges: ReadonlyArray<ChartWedge>;
65
72
  readonly labels: ReadonlyArray<ChartLabel>;
66
73
  readonly polygons?: ReadonlyArray<ChartPolygon>;
74
+ /** §21.2.2.198 chart-space fill + outline: drawn under everything else. */
75
+ readonly background?: ChartRect;
76
+ /**
77
+ * Major gridlines, drawn UNDER the plotted data. Kept apart from the other
78
+ * polylines because z-order is the whole point: gridlines over the bars strip
79
+ * every one of them with the axis's own ruling, which is not what any
80
+ * spreadsheet draws.
81
+ */
82
+ readonly gridlines?: ReadonlyArray<ChartPolyline>;
67
83
  }
68
84
  /**
69
85
  * Injected text-width measurer: the rendered advance width (points) of `text` at
@@ -127,6 +143,18 @@ export declare function formatTick(v: number, step: number): string;
127
143
  * @returns The positioned scene primitives.
128
144
  */
129
145
  export declare function buildBarScene(chart: Chart, wPt: number, hPt: number, measure: MeasureText): ChartScene;
146
+ /**
147
+ * The name a series shows in the legend: its own `c:tx`, or Excel's positional
148
+ * `SeriesN` when it has none. Exported because the SUBSET has to know it too —
149
+ * a name invented at draw time is a name no glyph collector ever saw, and
150
+ * 57362.xlsx drew its unnamed series as "eries1", the capital S appearing
151
+ * nowhere else on the page and so nowhere in the font.
152
+ *
153
+ * @param series The series.
154
+ * @param index Its zero-based index in the chart.
155
+ * @returns The legend text.
156
+ */
157
+ export declare function legendSeriesName(series: ChartSeries, index: number): string;
130
158
  /**
131
159
  * Lay out an area {@link Chart} into a {@link ChartScene}: each series becomes a
132
160
  * filled polygon down to the value baseline (stacked when `chart.grouping` is