ooxml.js 6.1.0 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/typed/xlsx/build.cjs +12 -4
- package/dist/typed/xlsx/build.js +12 -4
- package/dist/typed/xlsx/conditional-format.cjs +519 -0
- package/dist/typed/xlsx/conditional-format.d.cts +16 -0
- package/dist/typed/xlsx/conditional-format.d.ts +16 -0
- package/dist/typed/xlsx/conditional-format.js +516 -0
- package/dist/typed/xlsx/content.cjs +11 -7
- package/dist/typed/xlsx/content.js +12 -8
- package/dist/typed/xlsx/data-validation.cjs +116 -0
- package/dist/typed/xlsx/data-validation.d.cts +11 -0
- package/dist/typed/xlsx/data-validation.d.ts +11 -0
- package/dist/typed/xlsx/data-validation.js +114 -0
- package/dist/typed/xlsx/rule-residue.cjs +29 -0
- package/dist/typed/xlsx/rule-residue.d.cts +7 -0
- package/dist/typed/xlsx/rule-residue.d.ts +7 -0
- package/dist/typed/xlsx/rule-residue.js +27 -0
- package/dist/typed/xlsx/sqref.cjs +24 -0
- package/dist/typed/xlsx/sqref.d.cts +7 -0
- package/dist/typed/xlsx/sqref.d.ts +7 -0
- package/dist/typed/xlsx/sqref.js +21 -0
- package/dist/typed/xlsx/styles.cjs +14 -2
- package/dist/typed/xlsx/styles.d.cts +5 -1
- package/dist/typed/xlsx/styles.d.ts +5 -1
- package/dist/typed/xlsx/styles.js +12 -3
- package/package.json +2 -2
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
import { parseXml } from "../../xml/parse.js";
|
|
2
|
+
import { buildXml } from "../../xml/build.js";
|
|
3
|
+
import { el, txt } from "../../xml/fragment.js";
|
|
4
|
+
import { encodeXmlText } from "../../xml/entities.js";
|
|
5
|
+
import { attr, childrenWithTag, decodeEntities, textContent } from "../util.js";
|
|
6
|
+
import { readXmlBool, writeXmlBool } from "./util.js";
|
|
7
|
+
import { colorFromElement, readColorRgb } from "./styles.js";
|
|
8
|
+
import { captureResidualAttributes, residualAttributesFor } from "./rule-residue.js";
|
|
9
|
+
import { formatSqref, parseSqref } from "./sqref.js";
|
|
10
|
+
import { colorToRgbHex } from "document-schema.js";
|
|
11
|
+
//#region src/typed/xlsx/conditional-format.ts
|
|
12
|
+
const CF_RULE_MANAGED_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
13
|
+
"type",
|
|
14
|
+
"dxfId",
|
|
15
|
+
"priority",
|
|
16
|
+
"stopIfTrue",
|
|
17
|
+
"operator",
|
|
18
|
+
"text",
|
|
19
|
+
"rank",
|
|
20
|
+
"percent",
|
|
21
|
+
"bottom",
|
|
22
|
+
"aboveAverage",
|
|
23
|
+
"equalAverage",
|
|
24
|
+
"stdDev",
|
|
25
|
+
"timePeriod",
|
|
26
|
+
"iconSet",
|
|
27
|
+
"reverse",
|
|
28
|
+
"showValue"
|
|
29
|
+
]);
|
|
30
|
+
function readConditionalFormats(worksheet, dxfs) {
|
|
31
|
+
const formats = [];
|
|
32
|
+
const residueElements = [];
|
|
33
|
+
for (const wrapper of childrenWithTag(worksheet, "conditionalFormatting")) {
|
|
34
|
+
const ranges = parseSqref(attr(wrapper, "sqref"));
|
|
35
|
+
for (const cfRule of childrenWithTag(wrapper, "cfRule")) {
|
|
36
|
+
const promoted = ranges.length === 0 ? void 0 : readCfRule(cfRule, ranges, dxfs);
|
|
37
|
+
if (promoted === void 0) {
|
|
38
|
+
residueElements.push({
|
|
39
|
+
type: "element",
|
|
40
|
+
tag: "conditionalFormatting",
|
|
41
|
+
attributes: wrapper.attributes,
|
|
42
|
+
children: [cfRule]
|
|
43
|
+
});
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
formats.push(promoted);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
formats,
|
|
51
|
+
residueElements
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function readCommonFields(cfRule, ranges) {
|
|
55
|
+
const result = { ranges: [...ranges] };
|
|
56
|
+
const priorityRaw = attr(cfRule, "priority");
|
|
57
|
+
if (priorityRaw !== void 0) {
|
|
58
|
+
const priority = Number.parseInt(priorityRaw, 10);
|
|
59
|
+
if (Number.isInteger(priority)) result.priority = priority;
|
|
60
|
+
}
|
|
61
|
+
if (readXmlBool(attr(cfRule, "stopIfTrue"))) result.stopIfTrue = true;
|
|
62
|
+
const source = captureResidualAttributes(cfRule, CF_RULE_MANAGED_ATTRIBUTES);
|
|
63
|
+
if (source !== void 0) result.source = source;
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
function readFormula(cfRule, index) {
|
|
67
|
+
const formulaEl = childrenWithTag(cfRule, "formula")[index];
|
|
68
|
+
return formulaEl === void 0 ? void 0 : textContent(formulaEl);
|
|
69
|
+
}
|
|
70
|
+
function isSheetRuleOperator(value) {
|
|
71
|
+
return value === "between" || value === "notBetween" || value === "equal" || value === "notEqual" || value === "greaterThan" || value === "greaterThanOrEqual" || value === "lessThan" || value === "lessThanOrEqual";
|
|
72
|
+
}
|
|
73
|
+
const TEXT_PREDICATE_TYPES = /* @__PURE__ */ new Set([
|
|
74
|
+
"containsText",
|
|
75
|
+
"notContainsText",
|
|
76
|
+
"beginsWith",
|
|
77
|
+
"endsWith"
|
|
78
|
+
]);
|
|
79
|
+
function isTextPredicateType(value) {
|
|
80
|
+
return value !== void 0 && TEXT_PREDICATE_TYPES.has(value);
|
|
81
|
+
}
|
|
82
|
+
const OPERAND_FREE_TYPES = /* @__PURE__ */ new Set([
|
|
83
|
+
"containsBlanks",
|
|
84
|
+
"notContainsBlanks",
|
|
85
|
+
"containsErrors",
|
|
86
|
+
"notContainsErrors",
|
|
87
|
+
"uniqueValues",
|
|
88
|
+
"duplicateValues"
|
|
89
|
+
]);
|
|
90
|
+
function isOperandFreeType(value) {
|
|
91
|
+
return value !== void 0 && OPERAND_FREE_TYPES.has(value);
|
|
92
|
+
}
|
|
93
|
+
const TIME_PERIODS = /* @__PURE__ */ new Set([
|
|
94
|
+
"yesterday",
|
|
95
|
+
"today",
|
|
96
|
+
"tomorrow",
|
|
97
|
+
"last7Days",
|
|
98
|
+
"thisMonth",
|
|
99
|
+
"lastMonth",
|
|
100
|
+
"nextMonth",
|
|
101
|
+
"thisWeek",
|
|
102
|
+
"lastWeek",
|
|
103
|
+
"nextWeek"
|
|
104
|
+
]);
|
|
105
|
+
function isTimePeriod(value) {
|
|
106
|
+
return value !== void 0 && TIME_PERIODS.has(value);
|
|
107
|
+
}
|
|
108
|
+
function isCfvoType(value) {
|
|
109
|
+
return value === "num" || value === "percent" || value === "max" || value === "min" || value === "formula" || value === "percentile";
|
|
110
|
+
}
|
|
111
|
+
function readCfvo(cfvoEl) {
|
|
112
|
+
const type = attr(cfvoEl, "type");
|
|
113
|
+
if (!isCfvoType(type)) return;
|
|
114
|
+
if (type === "min" || type === "max") return { type };
|
|
115
|
+
const valRaw = attr(cfvoEl, "val");
|
|
116
|
+
if (valRaw === void 0) return;
|
|
117
|
+
return {
|
|
118
|
+
type,
|
|
119
|
+
value: decodeEntities(valRaw)
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function readColorScaleStops(colorScaleEl) {
|
|
123
|
+
const cfvoEls = childrenWithTag(colorScaleEl, "cfvo");
|
|
124
|
+
const colorEls = childrenWithTag(colorScaleEl, "color");
|
|
125
|
+
if (cfvoEls.length !== colorEls.length || cfvoEls.length < 2 || cfvoEls.length > 3) return;
|
|
126
|
+
const stops = [];
|
|
127
|
+
for (let index = 0; index < cfvoEls.length; index++) {
|
|
128
|
+
const cfvoEl = cfvoEls[index];
|
|
129
|
+
const colorEl = colorEls[index];
|
|
130
|
+
if (cfvoEl === void 0 || colorEl === void 0) return;
|
|
131
|
+
const value = readCfvo(cfvoEl);
|
|
132
|
+
const color = colorFromElement(colorEl);
|
|
133
|
+
if (value === void 0 || color === void 0) return;
|
|
134
|
+
stops.push({
|
|
135
|
+
value,
|
|
136
|
+
color
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return stops;
|
|
140
|
+
}
|
|
141
|
+
function readDataBar(dataBarEl) {
|
|
142
|
+
const cfvoEls = childrenWithTag(dataBarEl, "cfvo");
|
|
143
|
+
const minEl = cfvoEls[0];
|
|
144
|
+
const maxEl = cfvoEls[1];
|
|
145
|
+
const min = minEl === void 0 ? void 0 : readCfvo(minEl);
|
|
146
|
+
const max = maxEl === void 0 ? void 0 : readCfvo(maxEl);
|
|
147
|
+
const color = colorFromElement(childrenWithTag(dataBarEl, "color")[0]);
|
|
148
|
+
if (min === void 0 || max === void 0 || color === void 0) return;
|
|
149
|
+
const result = {
|
|
150
|
+
min,
|
|
151
|
+
max,
|
|
152
|
+
color
|
|
153
|
+
};
|
|
154
|
+
const showValueRaw = attr(dataBarEl, "showValue");
|
|
155
|
+
if (showValueRaw !== void 0 && !readXmlBool(showValueRaw)) result.showValue = false;
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
const DEFAULT_ICON_SET_TYPE = "3TrafficLights1";
|
|
159
|
+
function readIconSet(iconSetEl) {
|
|
160
|
+
const thresholds = [];
|
|
161
|
+
for (const cfvoEl of childrenWithTag(iconSetEl, "cfvo")) {
|
|
162
|
+
const value = readCfvo(cfvoEl);
|
|
163
|
+
if (value === void 0) return;
|
|
164
|
+
thresholds.push(value);
|
|
165
|
+
}
|
|
166
|
+
if (thresholds.length === 0) return;
|
|
167
|
+
const result = {
|
|
168
|
+
iconSetType: attr(iconSetEl, "iconSet") ?? DEFAULT_ICON_SET_TYPE,
|
|
169
|
+
thresholds
|
|
170
|
+
};
|
|
171
|
+
if (readXmlBool(attr(iconSetEl, "reverse"))) result.reverse = true;
|
|
172
|
+
const showValueRaw = attr(iconSetEl, "showValue");
|
|
173
|
+
if (showValueRaw !== void 0 && !readXmlBool(showValueRaw)) result.showValue = false;
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
function styleFromDxf(dxf) {
|
|
177
|
+
const fontEl = childrenWithTag(dxf, "font")[0];
|
|
178
|
+
const textColor = fontEl === void 0 ? void 0 : readColorRgb(fontEl, "color");
|
|
179
|
+
const fillEl = childrenWithTag(dxf, "fill")[0];
|
|
180
|
+
const patternFillEl = fillEl === void 0 ? void 0 : childrenWithTag(fillEl, "patternFill")[0];
|
|
181
|
+
const background = patternFillEl === void 0 ? void 0 : readColorRgb(patternFillEl, "bgColor");
|
|
182
|
+
const residueChildren = dxfResidueChildren(dxf, textColor !== void 0, background !== void 0);
|
|
183
|
+
const style = {};
|
|
184
|
+
if (textColor !== void 0) style.textColor = textColor;
|
|
185
|
+
if (background !== void 0) style.background = background;
|
|
186
|
+
if (residueChildren.length > 0) style.source = {
|
|
187
|
+
format: "xlsx",
|
|
188
|
+
xml: buildXml(residueChildren)
|
|
189
|
+
};
|
|
190
|
+
return style.textColor === void 0 && style.background === void 0 && style.source === void 0 ? void 0 : style;
|
|
191
|
+
}
|
|
192
|
+
function withoutChildTag(element, tag) {
|
|
193
|
+
const remaining = element.children.filter((child) => !(child.type === "element" && child.tag === tag));
|
|
194
|
+
if (remaining.length === 0 && element.attributes.length === 0) return;
|
|
195
|
+
return {
|
|
196
|
+
...element,
|
|
197
|
+
children: remaining
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
function fillResidue(fillEl) {
|
|
201
|
+
const patternFillEl = childrenWithTag(fillEl, "patternFill")[0];
|
|
202
|
+
const otherFillChildren = fillEl.children.filter((child) => !(child.type === "element" && child.tag === "patternFill"));
|
|
203
|
+
if (patternFillEl === void 0) return otherFillChildren.length === 0 && fillEl.attributes.length === 0 ? void 0 : {
|
|
204
|
+
...fillEl,
|
|
205
|
+
children: otherFillChildren
|
|
206
|
+
};
|
|
207
|
+
const patternFillResidue = withoutChildTag(patternFillEl, "bgColor");
|
|
208
|
+
if (patternFillResidue === void 0) return otherFillChildren.length === 0 && fillEl.attributes.length === 0 ? void 0 : {
|
|
209
|
+
...fillEl,
|
|
210
|
+
children: otherFillChildren
|
|
211
|
+
};
|
|
212
|
+
return {
|
|
213
|
+
...fillEl,
|
|
214
|
+
children: [patternFillResidue, ...otherFillChildren]
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function dxfResidueChildren(dxf, textColorCaptured, backgroundCaptured) {
|
|
218
|
+
const residue = [];
|
|
219
|
+
for (const child of dxf.children) {
|
|
220
|
+
if (child.type !== "element") continue;
|
|
221
|
+
if (child.tag === "font" && textColorCaptured) {
|
|
222
|
+
const remainder = withoutChildTag(child, "color");
|
|
223
|
+
if (remainder !== void 0) residue.push(remainder);
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (child.tag === "fill" && backgroundCaptured) {
|
|
227
|
+
const remainder = fillResidue(child);
|
|
228
|
+
if (remainder !== void 0) residue.push(remainder);
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
residue.push(child);
|
|
232
|
+
}
|
|
233
|
+
return residue;
|
|
234
|
+
}
|
|
235
|
+
function resolveStyle(cfRule, dxfs) {
|
|
236
|
+
const dxfIdRaw = attr(cfRule, "dxfId");
|
|
237
|
+
if (dxfIdRaw === void 0) return;
|
|
238
|
+
const dxfId = Number.parseInt(dxfIdRaw, 10);
|
|
239
|
+
const dxf = Number.isInteger(dxfId) ? dxfs[dxfId] : void 0;
|
|
240
|
+
return dxf === void 0 ? void 0 : styleFromDxf(dxf);
|
|
241
|
+
}
|
|
242
|
+
function readCfRule(cfRule, ranges, dxfs) {
|
|
243
|
+
const type = attr(cfRule, "type");
|
|
244
|
+
const common = readCommonFields(cfRule, ranges);
|
|
245
|
+
const style = resolveStyle(cfRule, dxfs);
|
|
246
|
+
const styleField = style === void 0 ? {} : { style };
|
|
247
|
+
if (type === "cellIs") {
|
|
248
|
+
const operatorRaw = attr(cfRule, "operator");
|
|
249
|
+
const formula1 = readFormula(cfRule, 0);
|
|
250
|
+
if (!isSheetRuleOperator(operatorRaw) || formula1 === void 0) return;
|
|
251
|
+
const formula2 = operatorRaw === "between" || operatorRaw === "notBetween" ? readFormula(cfRule, 1) : void 0;
|
|
252
|
+
return {
|
|
253
|
+
type: "cellIs",
|
|
254
|
+
...common,
|
|
255
|
+
operator: operatorRaw,
|
|
256
|
+
formula1,
|
|
257
|
+
...formula2 === void 0 ? {} : { formula2 },
|
|
258
|
+
...styleField
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
if (isTextPredicateType(type)) {
|
|
262
|
+
const text = attr(cfRule, "text");
|
|
263
|
+
if (text === void 0) return;
|
|
264
|
+
return {
|
|
265
|
+
type,
|
|
266
|
+
...common,
|
|
267
|
+
text: decodeEntities(text),
|
|
268
|
+
...styleField
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
if (isOperandFreeType(type)) return {
|
|
272
|
+
type,
|
|
273
|
+
...common,
|
|
274
|
+
...styleField
|
|
275
|
+
};
|
|
276
|
+
if (type === "top10") {
|
|
277
|
+
const rankRaw = attr(cfRule, "rank");
|
|
278
|
+
const rank = rankRaw === void 0 ? void 0 : Number(rankRaw);
|
|
279
|
+
if (rank === void 0 || !Number.isFinite(rank) || rank <= 0) return;
|
|
280
|
+
return {
|
|
281
|
+
type: "top10",
|
|
282
|
+
...common,
|
|
283
|
+
rank,
|
|
284
|
+
...readXmlBool(attr(cfRule, "percent")) ? { percent: true } : {},
|
|
285
|
+
...readXmlBool(attr(cfRule, "bottom")) ? { bottom: true } : {},
|
|
286
|
+
...styleField
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
if (type === "aboveAverage") {
|
|
290
|
+
const aboveAverageRaw = attr(cfRule, "aboveAverage");
|
|
291
|
+
const stdDevRaw = attr(cfRule, "stdDev");
|
|
292
|
+
const stdDev = stdDevRaw === void 0 ? void 0 : Number.parseInt(stdDevRaw, 10);
|
|
293
|
+
return {
|
|
294
|
+
type: "aboveAverage",
|
|
295
|
+
...common,
|
|
296
|
+
...aboveAverageRaw !== void 0 && !readXmlBool(aboveAverageRaw) ? { aboveAverage: false } : {},
|
|
297
|
+
...readXmlBool(attr(cfRule, "equalAverage")) ? { equalAverage: true } : {},
|
|
298
|
+
...stdDev !== void 0 && Number.isInteger(stdDev) && stdDev > 0 ? { stdDev } : {},
|
|
299
|
+
...styleField
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
if (type === "timePeriod") {
|
|
303
|
+
const timePeriod = attr(cfRule, "timePeriod");
|
|
304
|
+
if (!isTimePeriod(timePeriod)) return;
|
|
305
|
+
return {
|
|
306
|
+
type: "timePeriod",
|
|
307
|
+
...common,
|
|
308
|
+
timePeriod,
|
|
309
|
+
...styleField
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
if (type === "colorScale") {
|
|
313
|
+
const colorScaleEl = childrenWithTag(cfRule, "colorScale")[0];
|
|
314
|
+
const stops = colorScaleEl === void 0 ? void 0 : readColorScaleStops(colorScaleEl);
|
|
315
|
+
if (stops === void 0) return;
|
|
316
|
+
return {
|
|
317
|
+
type: "colorScale",
|
|
318
|
+
...common,
|
|
319
|
+
stops
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
if (type === "dataBar") {
|
|
323
|
+
const dataBarEl = childrenWithTag(cfRule, "dataBar")[0];
|
|
324
|
+
const parsed = dataBarEl === void 0 ? void 0 : readDataBar(dataBarEl);
|
|
325
|
+
if (parsed === void 0) return;
|
|
326
|
+
return {
|
|
327
|
+
type: "dataBar",
|
|
328
|
+
...common,
|
|
329
|
+
min: parsed.min,
|
|
330
|
+
max: parsed.max,
|
|
331
|
+
color: parsed.color,
|
|
332
|
+
...parsed.showValue === void 0 ? {} : { showValue: parsed.showValue }
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
if (type === "iconSet") {
|
|
336
|
+
const iconSetEl = childrenWithTag(cfRule, "iconSet")[0];
|
|
337
|
+
const parsed = iconSetEl === void 0 ? void 0 : readIconSet(iconSetEl);
|
|
338
|
+
if (parsed === void 0) return;
|
|
339
|
+
return {
|
|
340
|
+
type: "iconSet",
|
|
341
|
+
...common,
|
|
342
|
+
iconSetType: parsed.iconSetType,
|
|
343
|
+
thresholds: parsed.thresholds,
|
|
344
|
+
...parsed.reverse === void 0 ? {} : { reverse: parsed.reverse },
|
|
345
|
+
...parsed.showValue === void 0 ? {} : { showValue: parsed.showValue }
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
var DxfTable = class {
|
|
350
|
+
elements = [];
|
|
351
|
+
intern(style) {
|
|
352
|
+
const index = this.elements.length;
|
|
353
|
+
this.elements.push(buildDxfElement(style));
|
|
354
|
+
return index;
|
|
355
|
+
}
|
|
356
|
+
dxfElements() {
|
|
357
|
+
return this.elements;
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
function attrsRecord(attributes) {
|
|
361
|
+
const result = {};
|
|
362
|
+
for (const attribute of attributes) result[attribute.name] = attribute.value;
|
|
363
|
+
return result;
|
|
364
|
+
}
|
|
365
|
+
function extractResidueElements(source) {
|
|
366
|
+
if (source?.format !== "xlsx") return [];
|
|
367
|
+
const elements = [];
|
|
368
|
+
for (const node of parseXml(source.xml)) if (node.type === "element") elements.push(node);
|
|
369
|
+
return elements;
|
|
370
|
+
}
|
|
371
|
+
function buildDxfElement(style) {
|
|
372
|
+
const residueByTag = /* @__PURE__ */ new Map();
|
|
373
|
+
for (const element of extractResidueElements(style.source)) residueByTag.set(element.tag, element);
|
|
374
|
+
const children = [];
|
|
375
|
+
const residualFont = residueByTag.get("font");
|
|
376
|
+
if (style.textColor !== void 0) {
|
|
377
|
+
const fontChildren = residualFont === void 0 ? [] : residualFont.children;
|
|
378
|
+
const fontAttrs = residualFont === void 0 ? {} : attrsRecord(residualFont.attributes);
|
|
379
|
+
children.push(el("font", fontAttrs, [...fontChildren, el("color", { rgb: `FF${colorToRgbHex(style.textColor)}` })]));
|
|
380
|
+
} else if (residualFont !== void 0) children.push(residualFont);
|
|
381
|
+
const residualNumFmt = residueByTag.get("numFmt");
|
|
382
|
+
if (residualNumFmt !== void 0) children.push(residualNumFmt);
|
|
383
|
+
const residualFill = residueByTag.get("fill");
|
|
384
|
+
if (style.background !== void 0) {
|
|
385
|
+
const residualPatternFill = residualFill === void 0 ? void 0 : childrenWithTag(residualFill, "patternFill")[0];
|
|
386
|
+
const patternFillChildren = residualPatternFill === void 0 ? [] : residualPatternFill.children;
|
|
387
|
+
const patternFillAttrs = residualPatternFill === void 0 ? {} : attrsRecord(residualPatternFill.attributes);
|
|
388
|
+
const otherFillChildren = residualFill === void 0 ? [] : residualFill.children.filter((child) => !(child.type === "element" && child.tag === "patternFill"));
|
|
389
|
+
children.push(el("fill", residualFill === void 0 ? {} : attrsRecord(residualFill.attributes), [el("patternFill", patternFillAttrs, [...patternFillChildren, el("bgColor", { rgb: `FF${colorToRgbHex(style.background)}` })]), ...otherFillChildren]));
|
|
390
|
+
} else if (residualFill !== void 0) children.push(residualFill);
|
|
391
|
+
for (const tag of [
|
|
392
|
+
"alignment",
|
|
393
|
+
"border",
|
|
394
|
+
"protection"
|
|
395
|
+
]) {
|
|
396
|
+
const residual = residueByTag.get(tag);
|
|
397
|
+
if (residual !== void 0) children.push(residual);
|
|
398
|
+
}
|
|
399
|
+
return el("dxf", {}, children);
|
|
400
|
+
}
|
|
401
|
+
function rangeSetKey(ranges) {
|
|
402
|
+
return ranges.map((range) => `${range.startRow}:${range.startColumn}:${range.endRow}:${range.endColumn}`).join("|");
|
|
403
|
+
}
|
|
404
|
+
const TEXT_PREDICATE_OPERATOR = {
|
|
405
|
+
containsText: "containsText",
|
|
406
|
+
notContainsText: "notContains",
|
|
407
|
+
beginsWith: "beginsWith",
|
|
408
|
+
endsWith: "endsWith"
|
|
409
|
+
};
|
|
410
|
+
function buildCfvoElement(value) {
|
|
411
|
+
const attrs = { type: value.type };
|
|
412
|
+
if (value.value !== void 0) attrs.val = encodeXmlText(value.value);
|
|
413
|
+
return el("cfvo", attrs);
|
|
414
|
+
}
|
|
415
|
+
function buildCfRuleElement(rule, priority, dxfTable) {
|
|
416
|
+
const attrs = residualAttributesFor(rule.source, "cfRule");
|
|
417
|
+
attrs.type = rule.type;
|
|
418
|
+
attrs.priority = String(priority);
|
|
419
|
+
if (rule.stopIfTrue === true) attrs.stopIfTrue = writeXmlBool(true);
|
|
420
|
+
const children = [];
|
|
421
|
+
let style;
|
|
422
|
+
switch (rule.type) {
|
|
423
|
+
case "cellIs":
|
|
424
|
+
attrs.operator = rule.operator;
|
|
425
|
+
children.push(el("formula", {}, [txt(encodeXmlText(rule.formula1))]));
|
|
426
|
+
if (rule.formula2 !== void 0) children.push(el("formula", {}, [txt(encodeXmlText(rule.formula2))]));
|
|
427
|
+
style = rule.style;
|
|
428
|
+
break;
|
|
429
|
+
case "containsText":
|
|
430
|
+
case "notContainsText":
|
|
431
|
+
case "beginsWith":
|
|
432
|
+
case "endsWith":
|
|
433
|
+
attrs.operator = TEXT_PREDICATE_OPERATOR[rule.type];
|
|
434
|
+
attrs.text = encodeXmlText(rule.text);
|
|
435
|
+
style = rule.style;
|
|
436
|
+
break;
|
|
437
|
+
case "containsBlanks":
|
|
438
|
+
case "notContainsBlanks":
|
|
439
|
+
case "containsErrors":
|
|
440
|
+
case "notContainsErrors":
|
|
441
|
+
case "uniqueValues":
|
|
442
|
+
case "duplicateValues":
|
|
443
|
+
style = rule.style;
|
|
444
|
+
break;
|
|
445
|
+
case "top10":
|
|
446
|
+
attrs.rank = String(rule.rank);
|
|
447
|
+
if (rule.percent === true) attrs.percent = writeXmlBool(true);
|
|
448
|
+
if (rule.bottom === true) attrs.bottom = writeXmlBool(true);
|
|
449
|
+
style = rule.style;
|
|
450
|
+
break;
|
|
451
|
+
case "aboveAverage":
|
|
452
|
+
if (rule.aboveAverage === false) attrs.aboveAverage = writeXmlBool(false);
|
|
453
|
+
if (rule.equalAverage === true) attrs.equalAverage = writeXmlBool(true);
|
|
454
|
+
if (rule.stdDev !== void 0) attrs.stdDev = String(rule.stdDev);
|
|
455
|
+
style = rule.style;
|
|
456
|
+
break;
|
|
457
|
+
case "timePeriod":
|
|
458
|
+
attrs.timePeriod = rule.timePeriod;
|
|
459
|
+
style = rule.style;
|
|
460
|
+
break;
|
|
461
|
+
case "colorScale":
|
|
462
|
+
children.push(el("colorScale", {}, [...rule.stops.map((stop) => buildCfvoElement(stop.value)), ...rule.stops.map((stop) => el("color", { rgb: `FF${colorToRgbHex(stop.color)}` }))]));
|
|
463
|
+
break;
|
|
464
|
+
case "dataBar": {
|
|
465
|
+
const dataBarChildren = [
|
|
466
|
+
buildCfvoElement(rule.min),
|
|
467
|
+
buildCfvoElement(rule.max),
|
|
468
|
+
el("color", { rgb: `FF${colorToRgbHex(rule.color)}` })
|
|
469
|
+
];
|
|
470
|
+
const dataBarAttrs = rule.showValue === false ? { showValue: writeXmlBool(false) } : {};
|
|
471
|
+
children.push(el("dataBar", dataBarAttrs, dataBarChildren));
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
474
|
+
case "iconSet": {
|
|
475
|
+
const iconSetAttrs = {};
|
|
476
|
+
if (rule.iconSetType !== DEFAULT_ICON_SET_TYPE) iconSetAttrs.iconSet = rule.iconSetType;
|
|
477
|
+
if (rule.reverse === true) iconSetAttrs.reverse = writeXmlBool(true);
|
|
478
|
+
if (rule.showValue === false) iconSetAttrs.showValue = writeXmlBool(false);
|
|
479
|
+
children.push(el("iconSet", iconSetAttrs, rule.thresholds.map(buildCfvoElement)));
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (style !== void 0) attrs.dxfId = String(dxfTable.intern(style));
|
|
484
|
+
return el("cfRule", attrs, children);
|
|
485
|
+
}
|
|
486
|
+
function buildConditionalFormattingElements(formats, dxfTable) {
|
|
487
|
+
const groupsByKey = /* @__PURE__ */ new Map();
|
|
488
|
+
const groupOrder = [];
|
|
489
|
+
for (const format of formats) {
|
|
490
|
+
const key = rangeSetKey(format.ranges);
|
|
491
|
+
const existing = groupsByKey.get(key);
|
|
492
|
+
if (existing === void 0) {
|
|
493
|
+
const group = {
|
|
494
|
+
ranges: format.ranges,
|
|
495
|
+
rules: [format]
|
|
496
|
+
};
|
|
497
|
+
groupsByKey.set(key, group);
|
|
498
|
+
groupOrder.push(group);
|
|
499
|
+
} else existing.rules.push(format);
|
|
500
|
+
}
|
|
501
|
+
const usedPriorities = /* @__PURE__ */ new Set();
|
|
502
|
+
for (const format of formats) if (format.priority !== void 0) usedPriorities.add(format.priority);
|
|
503
|
+
let nextPriority = 1;
|
|
504
|
+
const assignPriority = (explicit) => {
|
|
505
|
+
if (explicit !== void 0) return explicit;
|
|
506
|
+
while (usedPriorities.has(nextPriority)) nextPriority++;
|
|
507
|
+
usedPriorities.add(nextPriority);
|
|
508
|
+
return nextPriority++;
|
|
509
|
+
};
|
|
510
|
+
return groupOrder.map((group) => {
|
|
511
|
+
const cfRuleElements = group.rules.map((rule) => buildCfRuleElement(rule, assignPriority(rule.priority), dxfTable));
|
|
512
|
+
return el("conditionalFormatting", { sqref: formatSqref(group.ranges) }, cfRuleElements);
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
//#endregion
|
|
516
|
+
export { DxfTable, buildConditionalFormattingElements, readConditionalFormats };
|
|
@@ -12,6 +12,8 @@ const require_typed_xlsx_serial = require("./serial.cjs");
|
|
|
12
12
|
const require_typed_xlsx_shared_strings = require("./shared-strings.cjs");
|
|
13
13
|
const require_typed_xlsx_styles = require("./styles.cjs");
|
|
14
14
|
const require_typed_xlsx_comments = require("./comments.cjs");
|
|
15
|
+
const require_typed_xlsx_conditional_format = require("./conditional-format.cjs");
|
|
16
|
+
const require_typed_xlsx_data_validation = require("./data-validation.cjs");
|
|
15
17
|
let document_schema_js = require("document-schema.js");
|
|
16
18
|
//#region src/typed/xlsx/content.ts
|
|
17
19
|
const WORKBOOK_PATH = "xl/workbook.xml";
|
|
@@ -320,10 +322,7 @@ function applyCellComments(comments, cells) {
|
|
|
320
322
|
byPosition.set(key, materialised);
|
|
321
323
|
}
|
|
322
324
|
}
|
|
323
|
-
function applyCellResidueRules(
|
|
324
|
-
const rules = [];
|
|
325
|
-
for (const container of require_typed_util.childrenWithTag(worksheet, "dataValidations")) rules.push(...require_typed_util.childrenWithTag(container, "dataValidation"));
|
|
326
|
-
rules.push(...require_typed_util.childrenWithTag(worksheet, "conditionalFormatting"));
|
|
325
|
+
function applyCellResidueRules(cells, rules) {
|
|
327
326
|
if (rules.length === 0) return;
|
|
328
327
|
const byPosition = /* @__PURE__ */ new Map();
|
|
329
328
|
for (const cell of cells) byPosition.set(`${cell.row}:${cell.column}`, cell);
|
|
@@ -355,7 +354,7 @@ function applyCellResidueRules(worksheet, cells) {
|
|
|
355
354
|
};
|
|
356
355
|
}
|
|
357
356
|
}
|
|
358
|
-
function readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet, context) {
|
|
357
|
+
function readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet, context, dxfs) {
|
|
359
358
|
const worksheet = require_typed_util.rootElement(pkg.parts[entry.path]);
|
|
360
359
|
if (worksheet === void 0) return {
|
|
361
360
|
name: entry.name,
|
|
@@ -367,7 +366,9 @@ function readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet, c
|
|
|
367
366
|
};
|
|
368
367
|
const cells = readCells(worksheet, sharedStrings, context);
|
|
369
368
|
applyCellComments(require_typed_xlsx_comments.readSheetCellComments(pkg, entry.path), cells);
|
|
370
|
-
|
|
369
|
+
const { validations, residueElements: dataValidationResidue } = require_typed_xlsx_data_validation.readDataValidations(worksheet);
|
|
370
|
+
const { formats, residueElements: conditionalFormatResidue } = require_typed_xlsx_conditional_format.readConditionalFormats(worksheet, dxfs);
|
|
371
|
+
applyCellResidueRules(cells, [...dataValidationResidue, ...conditionalFormatResidue]);
|
|
371
372
|
const drawing = require_typed_xlsx_drawings.readSheetDrawing(pkg, entry.path, worksheet);
|
|
372
373
|
return {
|
|
373
374
|
name: entry.name,
|
|
@@ -376,6 +377,8 @@ function readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet, c
|
|
|
376
377
|
rows: readRows(worksheet),
|
|
377
378
|
images: drawing.images,
|
|
378
379
|
...drawing.embeddedObjects === void 0 ? {} : { embeddedObjects: drawing.embeddedObjects },
|
|
380
|
+
...validations.length === 0 ? {} : { dataValidations: validations },
|
|
381
|
+
...formats.length === 0 ? {} : { conditionalFormats: formats },
|
|
379
382
|
printSettings: require_typed_xlsx_print_settings.readPrintSettings(worksheet, sheetIndex, definedNamesBySheet)
|
|
380
383
|
};
|
|
381
384
|
}
|
|
@@ -391,7 +394,8 @@ function readXlsxContent(pkg) {
|
|
|
391
394
|
const sharedStrings = require_typed_xlsx_shared_strings.loadSharedStrings(pkg);
|
|
392
395
|
const definedNamesBySheet = require_typed_xlsx_defined_names.readDefinedNamesBySheet(pkg);
|
|
393
396
|
const context = readCellFormatContext(pkg);
|
|
394
|
-
const
|
|
397
|
+
const dxfs = require_typed_xlsx_styles.readDxfElements(pkg);
|
|
398
|
+
const sheets = resolveSheetEntries(pkg).map((entry, sheetIndex) => readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet, context, dxfs));
|
|
395
399
|
return {
|
|
396
400
|
kind: "spreadsheet",
|
|
397
401
|
metadata: require_typed_shared_metadata.readCoreProperties(pkg),
|
|
@@ -9,8 +9,10 @@ import { columnWidthCharsToPt } from "./units.js";
|
|
|
9
9
|
import { readSheetDrawing } from "./drawings.js";
|
|
10
10
|
import { readDate1904, serialToIsoDate, serialToIsoDateTime, serialToIsoTime } from "./serial.js";
|
|
11
11
|
import { loadSharedStrings } from "./shared-strings.js";
|
|
12
|
-
import { readCellStyles } from "./styles.js";
|
|
12
|
+
import { readCellStyles, readDxfElements } from "./styles.js";
|
|
13
13
|
import { readSheetCellComments } from "./comments.js";
|
|
14
|
+
import { readConditionalFormats } from "./conditional-format.js";
|
|
15
|
+
import { readDataValidations } from "./data-validation.js";
|
|
14
16
|
import { parseCellReference, parseRangeReference } from "document-schema.js";
|
|
15
17
|
//#region src/typed/xlsx/content.ts
|
|
16
18
|
const WORKBOOK_PATH = "xl/workbook.xml";
|
|
@@ -319,10 +321,7 @@ function applyCellComments(comments, cells) {
|
|
|
319
321
|
byPosition.set(key, materialised);
|
|
320
322
|
}
|
|
321
323
|
}
|
|
322
|
-
function applyCellResidueRules(
|
|
323
|
-
const rules = [];
|
|
324
|
-
for (const container of childrenWithTag(worksheet, "dataValidations")) rules.push(...childrenWithTag(container, "dataValidation"));
|
|
325
|
-
rules.push(...childrenWithTag(worksheet, "conditionalFormatting"));
|
|
324
|
+
function applyCellResidueRules(cells, rules) {
|
|
326
325
|
if (rules.length === 0) return;
|
|
327
326
|
const byPosition = /* @__PURE__ */ new Map();
|
|
328
327
|
for (const cell of cells) byPosition.set(`${cell.row}:${cell.column}`, cell);
|
|
@@ -354,7 +353,7 @@ function applyCellResidueRules(worksheet, cells) {
|
|
|
354
353
|
};
|
|
355
354
|
}
|
|
356
355
|
}
|
|
357
|
-
function readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet, context) {
|
|
356
|
+
function readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet, context, dxfs) {
|
|
358
357
|
const worksheet = rootElement(pkg.parts[entry.path]);
|
|
359
358
|
if (worksheet === void 0) return {
|
|
360
359
|
name: entry.name,
|
|
@@ -366,7 +365,9 @@ function readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet, c
|
|
|
366
365
|
};
|
|
367
366
|
const cells = readCells(worksheet, sharedStrings, context);
|
|
368
367
|
applyCellComments(readSheetCellComments(pkg, entry.path), cells);
|
|
369
|
-
|
|
368
|
+
const { validations, residueElements: dataValidationResidue } = readDataValidations(worksheet);
|
|
369
|
+
const { formats, residueElements: conditionalFormatResidue } = readConditionalFormats(worksheet, dxfs);
|
|
370
|
+
applyCellResidueRules(cells, [...dataValidationResidue, ...conditionalFormatResidue]);
|
|
370
371
|
const drawing = readSheetDrawing(pkg, entry.path, worksheet);
|
|
371
372
|
return {
|
|
372
373
|
name: entry.name,
|
|
@@ -375,6 +376,8 @@ function readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet, c
|
|
|
375
376
|
rows: readRows(worksheet),
|
|
376
377
|
images: drawing.images,
|
|
377
378
|
...drawing.embeddedObjects === void 0 ? {} : { embeddedObjects: drawing.embeddedObjects },
|
|
379
|
+
...validations.length === 0 ? {} : { dataValidations: validations },
|
|
380
|
+
...formats.length === 0 ? {} : { conditionalFormats: formats },
|
|
378
381
|
printSettings: readPrintSettings(worksheet, sheetIndex, definedNamesBySheet)
|
|
379
382
|
};
|
|
380
383
|
}
|
|
@@ -390,7 +393,8 @@ function readXlsxContent(pkg) {
|
|
|
390
393
|
const sharedStrings = loadSharedStrings(pkg);
|
|
391
394
|
const definedNamesBySheet = readDefinedNamesBySheet(pkg);
|
|
392
395
|
const context = readCellFormatContext(pkg);
|
|
393
|
-
const
|
|
396
|
+
const dxfs = readDxfElements(pkg);
|
|
397
|
+
const sheets = resolveSheetEntries(pkg).map((entry, sheetIndex) => readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet, context, dxfs));
|
|
394
398
|
return {
|
|
395
399
|
kind: "spreadsheet",
|
|
396
400
|
metadata: readCoreProperties(pkg),
|