@rowsncolumns/toolkit 24.4.3 → 24.4.5

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 (86) hide show
  1. package/dist/cjs/excel-parser/interface.d.ts +5 -1
  2. package/dist/cjs/excel-parser/interface.d.ts.map +1 -1
  3. package/dist/cjs/excel-parser/plugins/base/index.d.ts +2 -0
  4. package/dist/cjs/excel-parser/plugins/base/index.d.ts.map +1 -1
  5. package/dist/cjs/excel-parser/plugins/base/index.js +3 -0
  6. package/dist/cjs/excel-parser/plugins/xls/index.d.ts +55 -9
  7. package/dist/cjs/excel-parser/plugins/xls/index.d.ts.map +1 -1
  8. package/dist/cjs/excel-parser/plugins/xls/index.js +487 -24
  9. package/dist/cjs/excel-parser/plugins/xlsb/index.d.ts.map +1 -1
  10. package/dist/cjs/excel-parser/plugins/xlsb/index.js +12 -5
  11. package/dist/cjs/excel-parser/plugins/xlsx/chartex.d.ts +37 -0
  12. package/dist/cjs/excel-parser/plugins/xlsx/chartex.d.ts.map +1 -0
  13. package/dist/cjs/excel-parser/plugins/xlsx/chartex.js +244 -0
  14. package/dist/cjs/excel-parser/plugins/xlsx/form-controls.d.ts +70 -0
  15. package/dist/cjs/excel-parser/plugins/xlsx/form-controls.d.ts.map +1 -0
  16. package/dist/cjs/excel-parser/plugins/xlsx/form-controls.js +295 -0
  17. package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts +9 -1
  18. package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts.map +1 -1
  19. package/dist/cjs/excel-parser/plugins/xlsx/index.js +251 -104
  20. package/dist/cjs/excel-parser/plugins/xlsx/styles.d.ts +15 -1
  21. package/dist/cjs/excel-parser/plugins/xlsx/styles.d.ts.map +1 -1
  22. package/dist/cjs/excel-parser/plugins/xlsx/styles.js +90 -4
  23. package/dist/cjs/excel-parser/registry.d.ts +7 -0
  24. package/dist/cjs/excel-parser/registry.d.ts.map +1 -1
  25. package/dist/cjs/excel-parser/registry.js +28 -1
  26. package/dist/cjs/excel-parser/types.d.ts +10 -1
  27. package/dist/cjs/excel-parser/types.d.ts.map +1 -1
  28. package/dist/cjs/excel-parser/workbook.d.ts +2 -0
  29. package/dist/cjs/excel-parser/workbook.d.ts.map +1 -1
  30. package/dist/cjs/excel-parser/workbook.js +20 -14
  31. package/dist/cjs/excel-parser/worker.js +128 -130
  32. package/dist/cjs/exporter/xlsx/chart-builder.d.ts.map +1 -1
  33. package/dist/cjs/exporter/xlsx/chart-builder.js +5 -33
  34. package/dist/cjs/exporter/xlsx/chartex-builder.d.ts +36 -0
  35. package/dist/cjs/exporter/xlsx/chartex-builder.d.ts.map +1 -0
  36. package/dist/cjs/exporter/xlsx/chartex-builder.js +109 -0
  37. package/dist/cjs/exporter/xlsx/form-controls-builder.d.ts +61 -0
  38. package/dist/cjs/exporter/xlsx/form-controls-builder.d.ts.map +1 -0
  39. package/dist/cjs/exporter/xlsx/form-controls-builder.js +197 -0
  40. package/dist/cjs/exporter/xlsx/xlsx-export.d.ts.map +1 -1
  41. package/dist/cjs/exporter/xlsx/xlsx-export.js +431 -193
  42. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  43. package/dist/esm/excel-parser/interface.d.ts +5 -1
  44. package/dist/esm/excel-parser/interface.d.ts.map +1 -1
  45. package/dist/esm/excel-parser/plugins/base/index.d.ts +2 -0
  46. package/dist/esm/excel-parser/plugins/base/index.d.ts.map +1 -1
  47. package/dist/esm/excel-parser/plugins/base/index.js +3 -0
  48. package/dist/esm/excel-parser/plugins/xls/index.d.ts +55 -9
  49. package/dist/esm/excel-parser/plugins/xls/index.d.ts.map +1 -1
  50. package/dist/esm/excel-parser/plugins/xls/index.js +429 -23
  51. package/dist/esm/excel-parser/plugins/xlsb/index.d.ts.map +1 -1
  52. package/dist/esm/excel-parser/plugins/xlsb/index.js +10 -3
  53. package/dist/esm/excel-parser/plugins/xlsx/chartex.d.ts +37 -0
  54. package/dist/esm/excel-parser/plugins/xlsx/chartex.d.ts.map +1 -0
  55. package/dist/esm/excel-parser/plugins/xlsx/chartex.js +199 -0
  56. package/dist/esm/excel-parser/plugins/xlsx/form-controls.d.ts +70 -0
  57. package/dist/esm/excel-parser/plugins/xlsx/form-controls.d.ts.map +1 -0
  58. package/dist/esm/excel-parser/plugins/xlsx/form-controls.js +246 -0
  59. package/dist/esm/excel-parser/plugins/xlsx/index.d.ts +9 -1
  60. package/dist/esm/excel-parser/plugins/xlsx/index.d.ts.map +1 -1
  61. package/dist/esm/excel-parser/plugins/xlsx/index.js +92 -6
  62. package/dist/esm/excel-parser/plugins/xlsx/styles.d.ts +15 -1
  63. package/dist/esm/excel-parser/plugins/xlsx/styles.d.ts.map +1 -1
  64. package/dist/esm/excel-parser/plugins/xlsx/styles.js +80 -0
  65. package/dist/esm/excel-parser/registry.d.ts +7 -0
  66. package/dist/esm/excel-parser/registry.d.ts.map +1 -1
  67. package/dist/esm/excel-parser/registry.js +18 -1
  68. package/dist/esm/excel-parser/types.d.ts +10 -1
  69. package/dist/esm/excel-parser/types.d.ts.map +1 -1
  70. package/dist/esm/excel-parser/workbook.d.ts +2 -0
  71. package/dist/esm/excel-parser/workbook.d.ts.map +1 -1
  72. package/dist/esm/excel-parser/workbook.js +16 -10
  73. package/dist/esm/excel-parser/worker.js +10 -18
  74. package/dist/esm/exporter/xlsx/chart-builder.d.ts.map +1 -1
  75. package/dist/esm/exporter/xlsx/chart-builder.js +0 -28
  76. package/dist/esm/exporter/xlsx/chartex-builder.d.ts +36 -0
  77. package/dist/esm/exporter/xlsx/chartex-builder.d.ts.map +1 -0
  78. package/dist/esm/exporter/xlsx/chartex-builder.js +97 -0
  79. package/dist/esm/exporter/xlsx/form-controls-builder.d.ts +61 -0
  80. package/dist/esm/exporter/xlsx/form-controls-builder.d.ts.map +1 -0
  81. package/dist/esm/exporter/xlsx/form-controls-builder.js +173 -0
  82. package/dist/esm/exporter/xlsx/xlsx-export.d.ts.map +1 -1
  83. package/dist/esm/exporter/xlsx/xlsx-export.js +228 -19
  84. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  85. package/package.json +5 -3
  86. package/xlsx.d.ts +14 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../excel-parser/plugins/xlsb/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../excel-parser/plugins/xlsb/index.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,7 @@ import { processChart } from "../xlsx/charts";
11
11
  import { processAnchors } from "../xlsx/drawing";
12
12
  import { readAllRecordHeaders } from "./biff-record-reader";
13
13
  import { standardExcelFormatCodeById } from "../xlsx/numfmt";
14
+ import { DATE_1904_OFFSET_DAYS, isEpochShiftedFormat } from "../xlsx/styles";
14
15
  import { extractThemeColors, extractThemeFonts, generateDarkThemeColors, } from "../xlsx/theme";
15
16
  const RT = {
16
17
  BrtCellRk: 0x0002,
@@ -939,7 +940,7 @@ const resolveXf = (styles, xfIndex) => {
939
940
  indent: xf.indent ?? parent.indent,
940
941
  };
941
942
  };
942
- const toCellData = (parsed, styles, sharedStrings, enableCellXfsRegistry, enableSharedStrings, cellXfs) => {
943
+ const toCellData = (parsed, styles, sharedStrings, enableCellXfsRegistry, enableSharedStrings, cellXfs, use1904) => {
943
944
  const xf = resolveXf(styles, parsed.styleRef);
944
945
  const format = {};
945
946
  const pattern = xf
@@ -1052,7 +1053,13 @@ const toCellData = (parsed, styles, sharedStrings, enableCellXfsRegistry, enable
1052
1053
  };
1053
1054
  }
1054
1055
  if (parsed.kind === "n") {
1055
- const value = Number(parsed.value);
1056
+ // A 1904-system workbook (`BrtWbProp.fDate1904`) stores date serials
1057
+ // 1462 days below the engine's 1900 system; date-formatted numbers are
1058
+ // converted on the way in, like the XLSX importer does.
1059
+ const value = Number(parsed.value) +
1060
+ (use1904 && isEpochShiftedFormat(format.numberFormat?.type)
1061
+ ? DATE_1904_OFFSET_DAYS
1062
+ : 0);
1056
1063
  const pattern = format.numberFormat?.pattern ?? "GENERAL";
1057
1064
  const fv = ssfFormat(pattern, value);
1058
1065
  // If there's a formula, use it in ue.fv, otherwise use the numeric value
@@ -1861,7 +1868,7 @@ export class XlsbPlugin extends BaseWorkbookPlugin {
1861
1868
  row = { values: [] };
1862
1869
  rows.set(parsed.row, row);
1863
1870
  }
1864
- row.values[parsed.col] = toCellData(parsed, this.styles, this.sharedStrings, enableCellXfsRegistry, enableSharedStrings, this.cellXfs);
1871
+ row.values[parsed.col] = toCellData(parsed, this.styles, this.sharedStrings, enableCellXfsRegistry, enableSharedStrings, this.cellXfs, this.use1904);
1865
1872
  }
1866
1873
  // Apply merge cell formatting
1867
1874
  // In Excel, merged cells should have formatting from the top-left (anchor) cell
@@ -0,0 +1,37 @@
1
+ import type { EmbeddedChart, SheetRange } from "@rowsncolumns/spreadsheet";
2
+ import type { StreamingZipParser } from "../../zip-parser-streaming";
3
+ import { type ResolveSheetId, type SheetDimensions } from "./charts";
4
+ /**
5
+ * Excel 2016+ "chartex" charts (`xl/charts/chartEx{N}.xml`, namespace
6
+ * `http://schemas.microsoft.com/office/drawing/2014/chartex`): treemap,
7
+ * sunburst, histogram / pareto, box & whisker, waterfall, funnel. They are
8
+ * anchored through an `mc:AlternateContent` whose `Choice` graphic frame
9
+ * carries `<cx:chart r:id>` instead of `<c:chart>`, and their data lives in
10
+ * `<cx:chartData><cx:data>` dimensions (`strDim type="cat"` for the
11
+ * hierarchy, `numDim type="size"|"val"` for the numbers) referenced by the
12
+ * series through `<cx:dataId>`.
13
+ *
14
+ * The exporter counterpart is `exporter/xlsx/chartex-builder.ts`.
15
+ */
16
+ export declare const CHART_EX_REL_TYPE = "http://schemas.microsoft.com/office/2014/relationships/chartEx";
17
+ export declare const CHART_EX_GRAPHIC_URI = "http://schemas.microsoft.com/office/drawing/2014/chartex";
18
+ /**
19
+ * `<cx:chart r:id>` inside an anchor's `mc:AlternateContent` choice (Excel
20
+ * also writes a plain `xdr:graphicFrame` for some producers — both forms are
21
+ * checked). Returns the `cx:chart` node or undefined for non-chartex anchors.
22
+ */
23
+ export declare function getChartExReferenceFromAnchor(anchor: any): any;
24
+ /**
25
+ * Split a multi-column hierarchy range (Excel lays the treemap hierarchy out
26
+ * as columns, top level first, leaf last) into `parentLabels` (one entry per
27
+ * parent column) and `labels` (the leaf column).
28
+ */
29
+ export declare const splitHierarchyRange: (range: SheetRange) => {
30
+ parentLabels: SheetRange[];
31
+ labels: SheetRange;
32
+ };
33
+ /** Parse a `cx:chartSpace` DOM into an `EmbeddedChart` spec (null when unsupported). */
34
+ export declare function parseChartExSpec(chartSpaceDom: any, sheetId: number, resolveSheetId?: ResolveSheetId): EmbeddedChart["spec"] | null;
35
+ /** Resolve + parse one chartex part referenced from a drawing anchor. */
36
+ export declare function processChartEx(chartTarget: string, drawingPath: string, anchor: any, sheetId: number, zipParser: StreamingZipParser, xmlParser: any, sheetDimensions?: SheetDimensions, resolveSheetId?: ResolveSheetId): Promise<EmbeddedChart | null>;
37
+ //# sourceMappingURL=chartex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chartex.d.ts","sourceRoot":"","sources":["../../../../../excel-parser/plugins/xlsx/chartex.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,aAAa,EACb,UAAU,EACX,MAAM,2BAA2B,CAAC;AAInC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,eAAe,EACrB,MAAM,UAAU,CAAC;AAElB;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,iBAAiB,mEACoC,CAAC;AACnE,eAAO,MAAM,oBAAoB,6DAC2B,CAAC;AAyB7D;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,CAoB9D;AA8BD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC9B,OAAO,UAAU,KAChB;IAAE,YAAY,EAAE,UAAU,EAAE,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAalD,CAAC;AAWF,wFAAwF;AACxF,wBAAgB,gBAAgB,CAC9B,aAAa,EAAE,GAAG,EAClB,OAAO,EAAE,MAAM,EACf,cAAc,CAAC,EAAE,cAAc,GAC9B,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI,CA0D9B;AAED,yEAAyE;AACzE,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,GAAG,EACX,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,kBAAkB,EAC7B,SAAS,EAAE,GAAG,EACd,eAAe,CAAC,EAAE,eAAe,EACjC,cAAc,CAAC,EAAE,cAAc,GAC9B,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAsB/B"}
@@ -0,0 +1,199 @@
1
+ import { generateSelectionsFromFormula, uuid } from "@rowsncolumns/utils";
2
+ import { get } from "lodash-es";
3
+ import { extractChartPosition, } from "./charts";
4
+ /**
5
+ * Excel 2016+ "chartex" charts (`xl/charts/chartEx{N}.xml`, namespace
6
+ * `http://schemas.microsoft.com/office/drawing/2014/chartex`): treemap,
7
+ * sunburst, histogram / pareto, box & whisker, waterfall, funnel. They are
8
+ * anchored through an `mc:AlternateContent` whose `Choice` graphic frame
9
+ * carries `<cx:chart r:id>` instead of `<c:chart>`, and their data lives in
10
+ * `<cx:chartData><cx:data>` dimensions (`strDim type="cat"` for the
11
+ * hierarchy, `numDim type="size"|"val"` for the numbers) referenced by the
12
+ * series through `<cx:dataId>`.
13
+ *
14
+ * The exporter counterpart is `exporter/xlsx/chartex-builder.ts`.
15
+ */
16
+ export const CHART_EX_REL_TYPE = "http://schemas.microsoft.com/office/2014/relationships/chartEx";
17
+ export const CHART_EX_GRAPHIC_URI = "http://schemas.microsoft.com/office/drawing/2014/chartex";
18
+ const asArray = (value) => value == null ? [] : Array.isArray(value) ? value : [value];
19
+ /** Read a child by local name, tolerating any namespace prefix. */
20
+ const child = (node, localName) => {
21
+ if (!node || typeof node !== "object")
22
+ return undefined;
23
+ if (node[localName] !== undefined)
24
+ return node[localName];
25
+ for (const key of Object.keys(node)) {
26
+ const colon = key.indexOf(":");
27
+ if (colon >= 0 && key.slice(colon + 1) === localName)
28
+ return node[key];
29
+ }
30
+ return undefined;
31
+ };
32
+ const textOf = (node) => {
33
+ if (node == null)
34
+ return undefined;
35
+ if (typeof node === "object") {
36
+ const inner = node.t$;
37
+ return inner == null ? undefined : String(inner);
38
+ }
39
+ return String(node);
40
+ };
41
+ /**
42
+ * `<cx:chart r:id>` inside an anchor's `mc:AlternateContent` choice (Excel
43
+ * also writes a plain `xdr:graphicFrame` for some producers — both forms are
44
+ * checked). Returns the `cx:chart` node or undefined for non-chartex anchors.
45
+ */
46
+ export function getChartExReferenceFromAnchor(anchor) {
47
+ const frames = [];
48
+ for (const alternate of asArray(child(anchor, "AlternateContent"))) {
49
+ for (const choice of asArray(child(alternate, "Choice"))) {
50
+ frames.push(...asArray(child(choice, "graphicFrame")));
51
+ }
52
+ }
53
+ frames.push(...asArray(child(anchor, "graphicFrame")));
54
+ for (const frame of frames) {
55
+ const graphicData = child(child(frame, "graphic"), "graphicData");
56
+ if (!graphicData)
57
+ continue;
58
+ const uri = get(graphicData, "a$.uri");
59
+ const cxChart = child(graphicData, "chart");
60
+ if (uri === CHART_EX_GRAPHIC_URI && cxChart)
61
+ return cxChart;
62
+ // A `cx:`-prefixed chart element without the uri attribute (defensive).
63
+ if (cxChart && Object.keys(graphicData).some((k) => k.startsWith("cx:"))) {
64
+ return cxChart;
65
+ }
66
+ }
67
+ return undefined;
68
+ }
69
+ /** `layoutId` → engine chart type. Unknown layouts are not imported. */
70
+ const CHART_TYPE_BY_LAYOUT = {
71
+ treemap: "treemap",
72
+ sunburst: "sunburst",
73
+ waterfall: "waterfall",
74
+ funnel: "funnel",
75
+ boxWhisker: "boxplot",
76
+ // `clusteredColumn` is a histogram / pareto only when it carries `<cx:binning>`.
77
+ };
78
+ const sourcesFromRef = (ref, hostSheetId, resolveSheetId) => {
79
+ if (!ref)
80
+ return [];
81
+ const selections = generateSelectionsFromFormula(`=${ref}`);
82
+ return selections.map((sel) => ({
83
+ ...sel.range,
84
+ sheetId: (sel.sheetName ? resolveSheetId?.(sel.sheetName) : undefined) ??
85
+ hostSheetId,
86
+ }));
87
+ };
88
+ const chartData = (sources) => ({ sources });
89
+ /**
90
+ * Split a multi-column hierarchy range (Excel lays the treemap hierarchy out
91
+ * as columns, top level first, leaf last) into `parentLabels` (one entry per
92
+ * parent column) and `labels` (the leaf column).
93
+ */
94
+ export const splitHierarchyRange = (range) => {
95
+ const parentLabels = [];
96
+ for (let c = range.startColumnIndex; c < range.endColumnIndex; c++) {
97
+ parentLabels.push({ ...range, startColumnIndex: c, endColumnIndex: c });
98
+ }
99
+ return {
100
+ parentLabels,
101
+ labels: {
102
+ ...range,
103
+ startColumnIndex: range.endColumnIndex,
104
+ endColumnIndex: range.endColumnIndex,
105
+ },
106
+ };
107
+ };
108
+ const dimensionRef = (data, dimTag, type) => {
109
+ const dims = asArray(child(data, dimTag)).filter((dim) => get(dim, "a$.type") === type);
110
+ const dim = dims[0] ?? (dimTag === "numDim" ? asArray(child(data, dimTag))[0] : undefined);
111
+ const f = child(dim, "f");
112
+ return textOf(Array.isArray(f) ? f[0] : f)?.trim() || undefined;
113
+ };
114
+ /** Parse a `cx:chartSpace` DOM into an `EmbeddedChart` spec (null when unsupported). */
115
+ export function parseChartExSpec(chartSpaceDom, sheetId, resolveSheetId) {
116
+ const chartSpace = child(chartSpaceDom, "chartSpace") ?? chartSpaceDom;
117
+ const chart = child(chartSpace, "chart");
118
+ if (!chart)
119
+ return null;
120
+ const region = child(child(chart, "plotArea"), "plotAreaRegion");
121
+ const series = asArray(child(region, "series"))[0];
122
+ if (!series)
123
+ return null;
124
+ const layoutId = String(get(series, "a$.layoutId") ?? "");
125
+ // Excel nests `<cx:binning>` in `<cx:layoutPr>`; tolerate it directly on the series too.
126
+ const binning = child(child(series, "layoutPr"), "binning") ?? child(series, "binning");
127
+ const chartType = layoutId === "clusteredColumn" && binning
128
+ ? "histogram"
129
+ : CHART_TYPE_BY_LAYOUT[layoutId];
130
+ if (!chartType)
131
+ return null;
132
+ const dataId = String(get(child(series, "dataId"), "a$.val") ?? "0");
133
+ const data = asArray(child(child(chartSpace, "chartData"), "data")).find((d) => String(get(d, "a$.id")) === dataId) ?? asArray(child(child(chartSpace, "chartData"), "data"))[0];
134
+ if (!data)
135
+ return null;
136
+ const title = textOf(child(child(child(child(chart, "title"), "tx"), "txData"), "v"));
137
+ const catRef = dimensionRef(data, "strDim", "cat");
138
+ const catSources = sourcesFromRef(catRef, sheetId, resolveSheetId);
139
+ if (chartType === "treemap" || chartType === "sunburst") {
140
+ const sizeRef = dimensionRef(data, "numDim", "size");
141
+ const sizeSources = sourcesFromRef(sizeRef, sheetId, resolveSheetId);
142
+ if (!catSources.length || !sizeSources.length)
143
+ return null;
144
+ const hierarchy = splitHierarchyRange(catSources[0]);
145
+ return {
146
+ chartType,
147
+ ...(title ? { title } : {}),
148
+ labels: [chartData([hierarchy.labels])],
149
+ parentLabels: hierarchy.parentLabels.map((range) => chartData([range])),
150
+ sizeData: [chartData(sizeSources)],
151
+ };
152
+ }
153
+ const valRef = dimensionRef(data, "numDim", "val");
154
+ const valSources = sourcesFromRef(valRef, sheetId, resolveSheetId);
155
+ if (!valSources.length)
156
+ return null;
157
+ const spec = {
158
+ chartType,
159
+ ...(title ? { title } : {}),
160
+ series: [chartData(valSources)],
161
+ ...(catSources.length ? { domains: [chartData(catSources)] } : {}),
162
+ };
163
+ if (chartType === "histogram") {
164
+ const binCount = Number(get(child(binning, "binCount"), "a$.val"));
165
+ if (Number.isFinite(binCount) && binCount > 0)
166
+ spec.binCount = binCount;
167
+ }
168
+ return spec;
169
+ }
170
+ /** Resolve + parse one chartex part referenced from a drawing anchor. */
171
+ export async function processChartEx(chartTarget, drawingPath, anchor, sheetId, zipParser, xmlParser, sheetDimensions, resolveSheetId) {
172
+ let chartPath = chartTarget;
173
+ const drawingDir = drawingPath.substring(0, drawingPath.lastIndexOf("/"));
174
+ if (chartPath.startsWith("/")) {
175
+ chartPath = chartPath.slice(1);
176
+ }
177
+ else if (chartPath.startsWith("../")) {
178
+ chartPath = `xl/${chartPath.replace("../", "")}`;
179
+ }
180
+ else if (!chartPath.startsWith("xl/")) {
181
+ chartPath = `${drawingDir}/${chartPath}`;
182
+ }
183
+ let content;
184
+ try {
185
+ content = await zipParser.getText(chartPath);
186
+ }
187
+ catch {
188
+ return null;
189
+ }
190
+ if (!content)
191
+ return null;
192
+ const spec = parseChartExSpec(xmlParser.parse(content), sheetId, resolveSheetId);
193
+ if (!spec)
194
+ return null;
195
+ const position = extractChartPosition(anchor, sheetId, sheetDimensions);
196
+ if (!position)
197
+ return null;
198
+ return { chartId: uuid(), spec, position };
199
+ }
@@ -0,0 +1,70 @@
1
+ import type { EmbeddedObject } from "@rowsncolumns/spreadsheet";
2
+ export declare const CTRL_PROP_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp";
3
+ export declare const VML_DRAWING_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing";
4
+ type CellAnchor = {
5
+ col: number;
6
+ colOff: number;
7
+ row: number;
8
+ rowOff: number;
9
+ };
10
+ /**
11
+ * `<controlPr><anchor><from>…</from><to>…</to></anchor>` → the engine's
12
+ * pixel overlay position (1-based anchor cell, EMU offsets → px, size from
13
+ * the cell span at the grid defaults — the same approximation the drawing
14
+ * importer uses for `twoCellAnchor`s).
15
+ */
16
+ export declare const controlAnchorToOverlayPosition: (from: CellAnchor, to: CellAnchor | undefined) => {
17
+ anchorCell: {
18
+ rowIndex: number;
19
+ columnIndex: number;
20
+ };
21
+ offsetXPixels?: number;
22
+ offsetYPixels?: number;
23
+ widthPixels?: number;
24
+ heightPixels?: number;
25
+ };
26
+ /**
27
+ * Parse an `xl/ctrlProps/ctrlPropN.xml` part: `objectType`, every other
28
+ * `formControlPr` attribute verbatim, and the literal `itemLst` items.
29
+ */
30
+ export declare const parseFormControlPr: (ctrlPropDom: any) => {
31
+ objectType: string;
32
+ properties: Record<string, string>;
33
+ listItems?: string[];
34
+ } | undefined;
35
+ /**
36
+ * Captions live only in the legacy VML part: `<v:shape id="_x0000_s1025">
37
+ * … <v:textbox><div>Check Box 1</div></v:textbox>`. Returns shapeId → text.
38
+ * VML is scanned textually — Excel's VML is not reliably well-formed XML.
39
+ */
40
+ export declare const parseVmlControlCaptions: (vml: string | undefined) => Map<number, string>;
41
+ export type RawWorksheetControl = {
42
+ shapeId?: number;
43
+ name?: string;
44
+ relId?: string;
45
+ controlProperties: Record<string, string>;
46
+ moveWithCells?: boolean;
47
+ sizeWithCells?: boolean;
48
+ from?: CellAnchor;
49
+ to?: CellAnchor;
50
+ };
51
+ /**
52
+ * `<controls>` from a worksheet DOM, whether wrapped in
53
+ * `<mc:AlternateContent><mc:Choice Requires="x14">` (Excel) or bare.
54
+ */
55
+ export declare const readWorksheetControls: (sheetDom: any) => RawWorksheetControl[];
56
+ /**
57
+ * Assemble the sheet's form controls. `loadCtrlProp` resolves a control's
58
+ * `r:id` to its parsed `ctrlProp` DOM (undefined when the part is missing —
59
+ * the control is then skipped, Excel would repair it the same way).
60
+ */
61
+ export declare const buildFormControlEmbeds: ({ controls, sheetId, ctrlProps, captions, }: {
62
+ controls: RawWorksheetControl[];
63
+ sheetId: number;
64
+ ctrlProps: Map<string, ReturnType<typeof parseFormControlPr>>;
65
+ captions: Map<number, string>;
66
+ }) => EmbeddedObject[];
67
+ /** The `r:id` of a worksheet's `<legacyDrawing>` (VML part), if any. */
68
+ export declare const readLegacyDrawingRelId: (sheetDom: any) => string | undefined;
69
+ export {};
70
+ //# sourceMappingURL=form-controls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form-controls.d.ts","sourceRoot":"","sources":["../../../../../excel-parser/plugins/xlsx/form-controls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,cAAc,EACf,MAAM,2BAA2B,CAAC;AAgBnC,eAAO,MAAM,kBAAkB,iFACiD,CAAC;AACjF,eAAO,MAAM,oBAAoB,mFACiD,CAAC;AA6CnF,KAAK,UAAU,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAe/E;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,GACzC,MAAM,UAAU,EAChB,IAAI,UAAU,GAAG,SAAS;gBAKZ;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE;oBACrC,MAAM;oBACN,MAAM;kBACR,MAAM;mBACL,MAAM;CAiBxB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC7B,aAAa,GAAG,KACf;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB,GAAG,SAkBH,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,GAClC,KAAK,MAAM,GAAG,SAAS,KACtB,GAAG,CAAC,MAAM,EAAE,MAAM,CAwBpB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,EAAE,CAAC,EAAE,UAAU,CAAC;CACjB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAAI,UAAU,GAAG,KAAG,mBAAmB,EA+BxE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAI,6CAKpC;IACD,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC;IAC9D,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B,KAAG,cAAc,EA+BjB,CAAC;AAEF,wEAAwE;AACxE,eAAO,MAAM,sBAAsB,GAAI,UAAU,GAAG,KAAG,MAAM,GAAG,SAK/D,CAAC"}
@@ -0,0 +1,246 @@
1
+ /**
2
+ * Excel form controls (`<controls>` in the worksheet + `xl/ctrlProps/*` +
3
+ * the legacy VML shape). Parsed into `EmbeddedObject`s with an
4
+ * {@link EmbedFormControlSpec} so the exporter can write the same three
5
+ * parts back (`exporter/xlsx/form-controls-builder.ts`). The grid does not
6
+ * run the control; the spec is a faithful, opaque carrier of what Excel
7
+ * stored.
8
+ */
9
+ const EMU_PER_PIXEL = 9525;
10
+ /** Grid defaults used to size a control from its cell-span anchor. */
11
+ const DEFAULT_COLUMN_WIDTH_PX = 100;
12
+ const DEFAULT_ROW_HEIGHT_PX = 20;
13
+ export const CTRL_PROP_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp";
14
+ export const VML_DRAWING_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing";
15
+ const asArray = (value) => value == null ? [] : Array.isArray(value) ? value : [value];
16
+ /** Read a child by local name, tolerating any namespace prefix. */
17
+ const childByLocalName = (node, localName) => {
18
+ if (!node || typeof node !== "object")
19
+ return undefined;
20
+ if (node[localName] !== undefined)
21
+ return node[localName];
22
+ for (const key of Object.keys(node)) {
23
+ const colon = key.indexOf(":");
24
+ if (colon >= 0 && key.slice(colon + 1) === localName) {
25
+ return node[key];
26
+ }
27
+ }
28
+ return undefined;
29
+ };
30
+ /** Text of a leaf element (`t$` when it carries attributes, else the value). */
31
+ const textOf = (node) => {
32
+ if (node == null)
33
+ return undefined;
34
+ if (typeof node === "object") {
35
+ const inner = node.t$;
36
+ return inner == null ? undefined : String(inner);
37
+ }
38
+ return String(node);
39
+ };
40
+ const numberOf = (node) => {
41
+ const text = textOf(node);
42
+ const value = text == null ? Number.NaN : Number(text);
43
+ return Number.isFinite(value) ? value : 0;
44
+ };
45
+ const attrs = (node) => {
46
+ const raw = node?.a$;
47
+ const out = {};
48
+ if (!raw || typeof raw !== "object")
49
+ return out;
50
+ for (const [key, value] of Object.entries(raw)) {
51
+ if (value == null)
52
+ continue;
53
+ out[key] = String(value);
54
+ }
55
+ return out;
56
+ };
57
+ const readCellAnchor = (node) => {
58
+ if (!node)
59
+ return undefined;
60
+ const col = childByLocalName(node, "col");
61
+ const row = childByLocalName(node, "row");
62
+ if (col === undefined || row === undefined)
63
+ return undefined;
64
+ return {
65
+ col: numberOf(col),
66
+ colOff: numberOf(childByLocalName(node, "colOff")),
67
+ row: numberOf(row),
68
+ rowOff: numberOf(childByLocalName(node, "rowOff")),
69
+ };
70
+ };
71
+ /**
72
+ * `<controlPr><anchor><from>…</from><to>…</to></anchor>` → the engine's
73
+ * pixel overlay position (1-based anchor cell, EMU offsets → px, size from
74
+ * the cell span at the grid defaults — the same approximation the drawing
75
+ * importer uses for `twoCellAnchor`s).
76
+ */
77
+ export const controlAnchorToOverlayPosition = (from, to) => {
78
+ const offsetXPixels = Math.round(from.colOff / EMU_PER_PIXEL);
79
+ const offsetYPixels = Math.round(from.rowOff / EMU_PER_PIXEL);
80
+ const overlay = {
81
+ anchorCell: { rowIndex: from.row + 1, columnIndex: from.col + 1 },
82
+ };
83
+ if (offsetXPixels)
84
+ overlay.offsetXPixels = offsetXPixels;
85
+ if (offsetYPixels)
86
+ overlay.offsetYPixels = offsetYPixels;
87
+ if (to) {
88
+ const width = (to.col - from.col) * DEFAULT_COLUMN_WIDTH_PX +
89
+ (to.colOff - from.colOff) / EMU_PER_PIXEL;
90
+ const height = (to.row - from.row) * DEFAULT_ROW_HEIGHT_PX +
91
+ (to.rowOff - from.rowOff) / EMU_PER_PIXEL;
92
+ if (width > 0)
93
+ overlay.widthPixels = Math.round(width);
94
+ if (height > 0)
95
+ overlay.heightPixels = Math.round(height);
96
+ }
97
+ return overlay;
98
+ };
99
+ /**
100
+ * Parse an `xl/ctrlProps/ctrlPropN.xml` part: `objectType`, every other
101
+ * `formControlPr` attribute verbatim, and the literal `itemLst` items.
102
+ */
103
+ export const parseFormControlPr = (ctrlPropDom) => {
104
+ const root = childByLocalName(ctrlPropDom, "formControlPr");
105
+ if (!root)
106
+ return undefined;
107
+ const { objectType, ...properties } = attrs(root);
108
+ if (!objectType)
109
+ return undefined;
110
+ // Namespace declarations ride along as attributes in fast-xml-parser.
111
+ for (const key of Object.keys(properties)) {
112
+ if (key === "xmlns" || key.startsWith("xmlns:"))
113
+ delete properties[key];
114
+ }
115
+ const itemLst = childByLocalName(root, "itemLst");
116
+ const listItems = asArray(childByLocalName(itemLst, "item"))
117
+ .map((item) => attrs(item).val)
118
+ .filter((val) => typeof val === "string");
119
+ return {
120
+ objectType,
121
+ properties,
122
+ ...(listItems.length ? { listItems } : {}),
123
+ };
124
+ };
125
+ /**
126
+ * Captions live only in the legacy VML part: `<v:shape id="_x0000_s1025">
127
+ * … <v:textbox><div>Check Box 1</div></v:textbox>`. Returns shapeId → text.
128
+ * VML is scanned textually — Excel's VML is not reliably well-formed XML.
129
+ */
130
+ export const parseVmlControlCaptions = (vml) => {
131
+ const captions = new Map();
132
+ if (!vml)
133
+ return captions;
134
+ const shapeRe = /<v:shape\b([^>]*)>([\s\S]*?)<\/v:shape>/g;
135
+ let match;
136
+ while ((match = shapeRe.exec(vml))) {
137
+ const idMatch = /\bid="_x0000_s(\d+)"/.exec(match[1]);
138
+ if (!idMatch)
139
+ continue;
140
+ const body = match[2];
141
+ if (!/<x:ClientData\b/.test(body))
142
+ continue;
143
+ const textbox = /<v:textbox\b[^>]*>([\s\S]*?)<\/v:textbox>/.exec(body);
144
+ if (!textbox)
145
+ continue;
146
+ const text = textbox[1]
147
+ .replace(/<br\s*\/?>/gi, "\n")
148
+ .replace(/<[^>]+>/g, "")
149
+ .replace(/&amp;/g, "&")
150
+ .replace(/&lt;/g, "<")
151
+ .replace(/&gt;/g, ">")
152
+ .replace(/&quot;/g, '"')
153
+ .replace(/&#(\d+);/g, (_, code) => String.fromCodePoint(Number(code)))
154
+ .trim();
155
+ if (text)
156
+ captions.set(Number(idMatch[1]), text);
157
+ }
158
+ return captions;
159
+ };
160
+ /**
161
+ * `<controls>` from a worksheet DOM, whether wrapped in
162
+ * `<mc:AlternateContent><mc:Choice Requires="x14">` (Excel) or bare.
163
+ */
164
+ export const readWorksheetControls = (sheetDom) => {
165
+ const worksheet = childByLocalName(sheetDom, "worksheet") ?? sheetDom;
166
+ const controls = childByLocalName(worksheet, "controls");
167
+ if (!controls)
168
+ return [];
169
+ const controlNodes = [...asArray(childByLocalName(controls, "control"))];
170
+ for (const alternate of asArray(childByLocalName(controls, "AlternateContent"))) {
171
+ for (const choice of asArray(childByLocalName(alternate, "Choice"))) {
172
+ controlNodes.push(...asArray(childByLocalName(choice, "control")));
173
+ }
174
+ }
175
+ return controlNodes.map((node) => {
176
+ const a = attrs(node);
177
+ const controlPr = childByLocalName(node, "controlPr");
178
+ const anchor = childByLocalName(controlPr, "anchor");
179
+ const anchorAttrs = attrs(anchor);
180
+ const shapeId = Number(a.shapeId);
181
+ return {
182
+ ...(Number.isFinite(shapeId) && a.shapeId ? { shapeId } : {}),
183
+ ...(a.name ? { name: a.name } : {}),
184
+ ...(a["r:id"] ?? a.id ? { relId: a["r:id"] ?? a.id } : {}),
185
+ controlProperties: attrs(controlPr),
186
+ ...(anchorAttrs.moveWithCells !== undefined
187
+ ? { moveWithCells: anchorAttrs.moveWithCells === "1" || anchorAttrs.moveWithCells === "true" }
188
+ : {}),
189
+ ...(anchorAttrs.sizeWithCells !== undefined
190
+ ? { sizeWithCells: anchorAttrs.sizeWithCells === "1" || anchorAttrs.sizeWithCells === "true" }
191
+ : {}),
192
+ from: readCellAnchor(childByLocalName(anchor, "from")),
193
+ to: readCellAnchor(childByLocalName(anchor, "to")),
194
+ };
195
+ });
196
+ };
197
+ /**
198
+ * Assemble the sheet's form controls. `loadCtrlProp` resolves a control's
199
+ * `r:id` to its parsed `ctrlProp` DOM (undefined when the part is missing —
200
+ * the control is then skipped, Excel would repair it the same way).
201
+ */
202
+ export const buildFormControlEmbeds = ({ controls, sheetId, ctrlProps, captions, }) => {
203
+ const embeds = [];
204
+ controls.forEach((control, index) => {
205
+ const parsed = control.relId ? ctrlProps.get(control.relId) : undefined;
206
+ if (!parsed || !control.from)
207
+ return;
208
+ const spec = {
209
+ type: "formControl",
210
+ objectType: parsed.objectType,
211
+ properties: parsed.properties,
212
+ };
213
+ if (control.name)
214
+ spec.name = control.name;
215
+ if (control.shapeId !== undefined)
216
+ spec.shapeId = control.shapeId;
217
+ const caption = control.shapeId !== undefined ? captions.get(control.shapeId) : undefined;
218
+ if (caption)
219
+ spec.text = caption;
220
+ if (parsed.listItems)
221
+ spec.listItems = parsed.listItems;
222
+ if (Object.keys(control.controlProperties).length) {
223
+ spec.controlProperties = control.controlProperties;
224
+ }
225
+ if (control.moveWithCells !== undefined)
226
+ spec.moveWithCells = control.moveWithCells;
227
+ if (control.sizeWithCells !== undefined)
228
+ spec.sizeWithCells = control.sizeWithCells;
229
+ embeds.push({
230
+ embedId: `control-${sheetId}-${control.shapeId ?? index + 1}`,
231
+ spec,
232
+ position: {
233
+ sheetId,
234
+ overlayPosition: controlAnchorToOverlayPosition(control.from, control.to),
235
+ },
236
+ });
237
+ });
238
+ return embeds;
239
+ };
240
+ /** The `r:id` of a worksheet's `<legacyDrawing>` (VML part), if any. */
241
+ export const readLegacyDrawingRelId = (sheetDom) => {
242
+ const worksheet = childByLocalName(sheetDom, "worksheet") ?? sheetDom;
243
+ const legacy = childByLocalName(worksheet, "legacyDrawing");
244
+ const a = attrs(legacy);
245
+ return a["r:id"] ?? a.id;
246
+ };
@@ -1,5 +1,5 @@
1
1
  import type { CellFormat, ConditionalFormatRule, DataValidationRuleRecord, EmbeddedChart, EmbeddedObject, NamedRange, ProtectedRange, Sheet, Slicer, SpreadsheetTheme, TableView } from "@rowsncolumns/spreadsheet";
2
- import type { CommentThread, TextFormat, TextFormatRun } from "@rowsncolumns/common-types";
2
+ import type { NamedCellStyle, CommentThread, TextFormat, TextFormatRun } from "@rowsncolumns/common-types";
3
3
  import { XMLParser } from "fast-xml-parser";
4
4
  import type { IWorkbookPlugin } from "../../interface";
5
5
  import type { ExternalLink, ProcessSheetDataForSheetOptions, ProcessSheetDataResult, SheetCatalogEntry, WorkbookProperties } from "../../types";
@@ -252,6 +252,8 @@ export declare class XlsxPlugin extends BaseWorkbookPlugin implements IWorkbookP
252
252
  getSheetData(rid: string): Promise<any>;
253
253
  getStyles(): any;
254
254
  getTheme(): SpreadsheetTheme;
255
+ /** `<cellStyles>` resolved to cell formats (toolbar "Workbook styles" gallery). */
256
+ getNamedCellStyles(): NamedCellStyle[];
255
257
  /**
256
258
  * The workbook default font — styles.xml fonts[0], the font every cell
257
259
  * without an explicit font inherits. Exporters pass this through so the
@@ -294,6 +296,12 @@ export declare class XlsxPlugin extends BaseWorkbookPlugin implements IWorkbookP
294
296
  releaseSheetCaches(sheetId: number): void;
295
297
  private processOneSheet;
296
298
  getDrawings(): Promise<EmbeddedObjectWithPosition[]>;
299
+ /**
300
+ * Form controls: `<controls><control r:id>` → `xl/ctrlProps/ctrlPropN.xml`
301
+ * (+ the caption from the sheet's legacy VML part), as `formControl`
302
+ * embeds. Nothing is rendered interactively — they round-trip.
303
+ */
304
+ _getFormControls(rid: string, sheetId: number, sheetData: any): Promise<EmbeddedObject[]>;
297
305
  getCharts(): Promise<EmbeddedChart[]>;
298
306
  /**
299
307
  * Phase D1 — extract every pivot table across every worksheet.