reamkit 1.15.4 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/core/bidi/segments.js +1 -2
- package/dist/esm/core/converter/facade.d.ts +5 -0
- package/dist/esm/core/converter/project.js +5 -1
- package/dist/esm/core/converter/ream.d.ts +6 -0
- package/dist/esm/core/converter/ream.js +34 -8
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +659 -7
- package/dist/esm/core/drawingml/chart-geometry.d.ts +34 -10
- package/dist/esm/core/drawingml/chart-geometry.js +424 -92
- package/dist/esm/core/drawingml/chart-parser.js +301 -11
- package/dist/esm/core/drawingml/colors.d.ts +7 -7
- package/dist/esm/core/drawingml/colors.js +84 -18
- package/dist/esm/core/drawingml/preset-geometry.js +240 -6
- package/dist/esm/core/drawingml/shape-render.d.ts +12 -0
- package/dist/esm/core/drawingml/shape-render.js +116 -3
- package/dist/esm/core/drawingml/sparkline-geometry.js +6 -4
- package/dist/esm/core/drawingml/theme-parser.d.ts +51 -0
- package/dist/esm/core/drawingml/theme-parser.js +92 -1
- package/dist/esm/core/font/measure.d.ts +5 -0
- package/dist/esm/core/font/measure.js +21 -1
- package/dist/esm/core/font/ttf-subset.js +26 -1
- package/dist/esm/core/images.d.ts +2 -2
- package/dist/esm/core/images.js +353 -43
- package/dist/esm/core/indexed-colors.d.ts +11 -0
- package/dist/esm/core/indexed-colors.js +81 -0
- package/dist/esm/core/ir/flow.d.ts +23 -1
- package/dist/esm/core/ir/sheet.d.ts +61 -0
- package/dist/esm/{excel → core}/number-format.d.ts +37 -0
- package/dist/esm/core/number-format.js +800 -0
- package/dist/esm/core/numbering/apply.d.ts +5 -3
- package/dist/esm/core/numbering/apply.js +42 -11
- package/dist/esm/core/numbering/index.js +2 -0
- package/dist/esm/core/numbering/state.d.ts +13 -1
- package/dist/esm/core/numbering/state.js +256 -15
- package/dist/esm/core/opc/alternate-content.d.ts +13 -0
- package/dist/esm/core/opc/alternate-content.js +72 -0
- package/dist/esm/core/opc/core-properties.js +1 -0
- package/dist/esm/core/opc/package.d.ts +14 -1
- package/dist/esm/core/opc/package.js +43 -4
- package/dist/esm/core/opc/relationships.js +1 -0
- package/dist/esm/core/opc/xml-entities.d.ts +12 -0
- package/dist/esm/core/opc/xml-entities.js +91 -0
- package/dist/esm/core/po-helpers.js +16 -1
- package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
- package/dist/esm/core/spreadsheet-model/types.d.ts +137 -0
- package/dist/esm/core/style-cascade/resolver.js +66 -11
- package/dist/esm/core/style-cascade/table.js +35 -11
- package/dist/esm/core/style-cascade/types.d.ts +42 -1
- package/dist/esm/core/style-cascade/types.js +4 -0
- package/dist/esm/core/vector.d.ts +30 -0
- package/dist/esm/excel/activex-parser.js +1 -0
- package/dist/esm/excel/column-bands.d.ts +26 -1
- package/dist/esm/excel/column-bands.js +156 -20
- package/dist/esm/excel/comments-parser.js +5 -3
- package/dist/esm/excel/conditional-format.d.ts +25 -2
- package/dist/esm/excel/conditional-format.js +63 -19
- package/dist/esm/excel/escaped-text.d.ts +9 -0
- package/dist/esm/excel/escaped-text.js +20 -0
- package/dist/esm/excel/form-control-parser.js +1 -0
- package/dist/esm/excel/formula/dates.js +1 -1
- package/dist/esm/excel/header-footer.d.ts +9 -1
- package/dist/esm/excel/header-footer.js +162 -14
- package/dist/esm/excel/index.d.ts +1 -1
- package/dist/esm/excel/index.js +2 -2
- package/dist/esm/excel/pivot-table-parser.js +1 -0
- package/dist/esm/excel/print-model.d.ts +75 -0
- package/dist/esm/excel/print-model.js +899 -77
- package/dist/esm/excel/printer-settings.d.ts +16 -0
- package/dist/esm/excel/printer-settings.js +36 -0
- package/dist/esm/excel/rich-value.d.ts +13 -0
- package/dist/esm/excel/rich-value.js +120 -0
- package/dist/esm/excel/shared-strings-parser.js +11 -7
- package/dist/esm/excel/sheet-drawing.d.ts +11 -0
- package/dist/esm/excel/sheet-drawing.js +26 -3
- package/dist/esm/excel/sheet-shape-parser.d.ts +53 -1
- package/dist/esm/excel/sheet-shape-parser.js +461 -32
- package/dist/esm/excel/sheet-to-flow.d.ts +23 -2
- package/dist/esm/excel/sheet-to-flow.js +553 -36
- package/dist/esm/excel/slicer-parser.js +1 -0
- package/dist/esm/excel/styles-parser.d.ts +30 -2
- package/dist/esm/excel/styles-parser.js +177 -40
- package/dist/esm/excel/table-parser.js +1 -0
- package/dist/esm/excel/vml-drawing.d.ts +68 -0
- package/dist/esm/excel/vml-drawing.js +158 -0
- package/dist/esm/excel/workbook-parser.d.ts +5 -0
- package/dist/esm/excel/workbook-parser.js +5 -1
- package/dist/esm/excel/worksheet-parser.d.ts +2 -1
- package/dist/esm/excel/worksheet-parser.js +150 -61
- package/dist/esm/excel/xlsx-reader.js +242 -11
- package/dist/esm/excel/xlsx-to-pdf.js +12 -1
- package/dist/esm/html/html-writer.js +29 -6
- package/dist/esm/layout/page-doc.d.ts +87 -1
- package/dist/esm/layout/styled-layout.d.ts +46 -2
- package/dist/esm/layout/styled-layout.js +2345 -274
- package/dist/esm/pdf/cid-font.js +20 -9
- package/dist/esm/pdf/objects.d.ts +13 -0
- package/dist/esm/pdf/objects.js +18 -1
- package/dist/esm/pdf/shading.js +76 -6
- package/dist/esm/pdf/styled-page-emitter.js +355 -49
- package/dist/esm/pdf/text-page-renderer.js +1 -0
- package/dist/esm/pdf/vector-graphics.d.ts +31 -2
- package/dist/esm/pdf/vector-graphics.js +103 -3
- package/dist/esm/pptx/pptx-reader.js +2 -0
- package/dist/esm/pptx/slide-parser.d.ts +21 -4
- package/dist/esm/pptx/slide-parser.js +98 -24
- package/dist/esm/svg/svg-writer.js +23 -4
- package/dist/esm/word/document-parser.d.ts +96 -7
- package/dist/esm/word/document-parser.js +538 -116
- package/dist/esm/word/docx-reader.js +135 -43
- package/dist/esm/word/docx-writer.js +6 -1
- package/dist/esm/word/drawing-parser.d.ts +86 -5
- package/dist/esm/word/drawing-parser.js +1590 -54
- package/dist/esm/word/index.d.ts +4 -4
- package/dist/esm/word/numbering-parser.d.ts +2 -1
- package/dist/esm/word/numbering-parser.js +108 -21
- package/dist/esm/word/paragraph-properties.d.ts +11 -1
- package/dist/esm/word/paragraph-properties.js +219 -10
- package/dist/esm/word/run-properties.js +45 -1
- package/dist/esm/word/settings-parser.d.ts +24 -0
- package/dist/esm/word/settings-parser.js +32 -5
- package/dist/esm/word/shading.d.ts +11 -0
- package/dist/esm/word/shading.js +64 -0
- package/dist/esm/word/styles-parser.js +9 -2
- package/dist/esm/word/table-parser.d.ts +9 -1
- package/dist/esm/word/table-parser.js +182 -30
- package/package.json +7 -3
- package/dist/esm/excel/number-format.js +0 -476
|
@@ -1,476 +0,0 @@
|
|
|
1
|
-
//#region src/excel/number-format.ts
|
|
2
|
-
var BUILTIN = new Map([
|
|
3
|
-
[0, "General"],
|
|
4
|
-
[1, "0"],
|
|
5
|
-
[2, "0.00"],
|
|
6
|
-
[3, "#,##0"],
|
|
7
|
-
[4, "#,##0.00"],
|
|
8
|
-
[9, "0%"],
|
|
9
|
-
[10, "0.00%"],
|
|
10
|
-
[11, "0.00E+00"],
|
|
11
|
-
[37, "#,##0_);(#,##0)"],
|
|
12
|
-
[38, "#,##0_);[Red](#,##0)"],
|
|
13
|
-
[39, "#,##0.00_);(#,##0.00)"],
|
|
14
|
-
[40, "#,##0.00_);[Red](#,##0.00)"],
|
|
15
|
-
[49, "@"]
|
|
16
|
-
]);
|
|
17
|
-
var BUILTIN_DATE_FORMATS = new Map([
|
|
18
|
-
[14, "m/d/yyyy"],
|
|
19
|
-
[15, "d-mmm-yy"],
|
|
20
|
-
[16, "d-mmm"],
|
|
21
|
-
[17, "mmm-yy"],
|
|
22
|
-
[18, "h:mm AM/PM"],
|
|
23
|
-
[19, "h:mm:ss AM/PM"],
|
|
24
|
-
[20, "h:mm"],
|
|
25
|
-
[21, "h:mm:ss"],
|
|
26
|
-
[22, "m/d/yyyy h:mm"],
|
|
27
|
-
[45, "mm:ss"],
|
|
28
|
-
[46, "[h]:mm:ss"],
|
|
29
|
-
[47, "mm:ss.0"]
|
|
30
|
-
]);
|
|
31
|
-
/**
|
|
32
|
-
* Render a cell's raw stored value through its number format (§18.8.30 built-ins
|
|
33
|
-
* and §18.8.31 custom codes). Handles `General`, text (`@`), the built-in date /
|
|
34
|
-
* time formats, custom date codes, and the numeric placeholder grammar (`0` `#`
|
|
35
|
-
* `,` `.` `%`, scientific notation, quoted literals, `;`-separated sections). An
|
|
36
|
-
* unknown id, or a value that does not parse as a number, falls back to a plain
|
|
37
|
-
* render of `rawValue`.
|
|
38
|
-
*
|
|
39
|
-
* @param rawValue The cell's raw stored value (a serial for dates).
|
|
40
|
-
* @param numFmtId The number-format id from the cell's `cellXf`.
|
|
41
|
-
* @param customFormats Custom format codes by id (from `<numFmts>`).
|
|
42
|
-
* @param date1904 The workbook date epoch (1904 vs the 1900 default).
|
|
43
|
-
* @returns The formatted display string.
|
|
44
|
-
*/
|
|
45
|
-
function applyNumberFormat(rawValue, numFmtId, customFormats, date1904 = false) {
|
|
46
|
-
if (rawValue.length === 0) return "";
|
|
47
|
-
if (numFmtId === 0) return defaultNumberRender(rawValue);
|
|
48
|
-
if (numFmtId === 49) return rawValue;
|
|
49
|
-
const builtinDate = BUILTIN_DATE_FORMATS.get(numFmtId);
|
|
50
|
-
if (builtinDate !== void 0) return formatExcelDate(rawValue, builtinDate, date1904);
|
|
51
|
-
const custom = customFormats.get(numFmtId);
|
|
52
|
-
if (custom !== void 0 && isDateFormat(custom)) return formatExcelDate(rawValue, custom, date1904);
|
|
53
|
-
const format = custom ?? BUILTIN.get(numFmtId);
|
|
54
|
-
if (!format) return defaultNumberRender(rawValue);
|
|
55
|
-
if (format === "General") return defaultNumberRender(rawValue);
|
|
56
|
-
return applyFormatString(rawValue, format);
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Excel serial date → JS `Date`. The default 1900 epoch uses 1899-12-30 as day 0
|
|
60
|
-
* (so serial 1 is 1900-01-01) and inherits the Lotus 1-2-3 leap-year bug: serial 60
|
|
61
|
-
* is considered "1900-02-29" which never existed. For serial ≥ 61 the simple
|
|
62
|
-
* formula is exact; values < 60 are vanishingly rare in business sheets (and our
|
|
63
|
-
* render is approximate anyway).
|
|
64
|
-
*
|
|
65
|
-
* The 1904 epoch (legacy Mac Excel) uses 1904-01-01 as day 0 and has no leap bug.
|
|
66
|
-
* Files saved with `<workbookPr date1904="1"/>` store dates offset by exactly 1462
|
|
67
|
-
* days from the 1900-epoch interpretation.
|
|
68
|
-
*/
|
|
69
|
-
function excelSerialToDate(serial, date1904) {
|
|
70
|
-
const ms = serial * 86400 * 1e3;
|
|
71
|
-
if (date1904) return new Date(Date.UTC(1904, 0, 1) + ms);
|
|
72
|
-
return new Date(Date.UTC(1899, 11, 30) + ms);
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* The inverse over a UTC calendar date: `(year, month0, day)` → the integer Excel
|
|
76
|
-
* serial day, using the same epoch. Round-trips {@link excelSerialToDate} exactly
|
|
77
|
-
* for an integer serial (the time-of-day is zero), so a serial → parts → serial
|
|
78
|
-
* loop is stable. Used by the formula engine's date functions and the `timePeriod`
|
|
79
|
-
* windows (E-SHEET W9) to map an injected reference date into serial space.
|
|
80
|
-
*
|
|
81
|
-
* @param month0 The 0-indexed month (0 = January).
|
|
82
|
-
*/
|
|
83
|
-
function excelSerialFromUtcParts(year, month0, day, date1904) {
|
|
84
|
-
const epoch = date1904 ? Date.UTC(1904, 0, 1) : Date.UTC(1899, 11, 30);
|
|
85
|
-
return Math.round((Date.UTC(year, month0, day) - epoch) / 864e5);
|
|
86
|
-
}
|
|
87
|
-
var MONTH_ABBR = [
|
|
88
|
-
"Jan",
|
|
89
|
-
"Feb",
|
|
90
|
-
"Mar",
|
|
91
|
-
"Apr",
|
|
92
|
-
"May",
|
|
93
|
-
"Jun",
|
|
94
|
-
"Jul",
|
|
95
|
-
"Aug",
|
|
96
|
-
"Sep",
|
|
97
|
-
"Oct",
|
|
98
|
-
"Nov",
|
|
99
|
-
"Dec"
|
|
100
|
-
];
|
|
101
|
-
var MONTH_FULL = [
|
|
102
|
-
"January",
|
|
103
|
-
"February",
|
|
104
|
-
"March",
|
|
105
|
-
"April",
|
|
106
|
-
"May",
|
|
107
|
-
"June",
|
|
108
|
-
"July",
|
|
109
|
-
"August",
|
|
110
|
-
"September",
|
|
111
|
-
"October",
|
|
112
|
-
"November",
|
|
113
|
-
"December"
|
|
114
|
-
];
|
|
115
|
-
var DAY_ABBR = [
|
|
116
|
-
"Sun",
|
|
117
|
-
"Mon",
|
|
118
|
-
"Tue",
|
|
119
|
-
"Wed",
|
|
120
|
-
"Thu",
|
|
121
|
-
"Fri",
|
|
122
|
-
"Sat"
|
|
123
|
-
];
|
|
124
|
-
var DAY_FULL = [
|
|
125
|
-
"Sunday",
|
|
126
|
-
"Monday",
|
|
127
|
-
"Tuesday",
|
|
128
|
-
"Wednesday",
|
|
129
|
-
"Thursday",
|
|
130
|
-
"Friday",
|
|
131
|
-
"Saturday"
|
|
132
|
-
];
|
|
133
|
-
function pad2(n) {
|
|
134
|
-
return String(n).padStart(2, "0");
|
|
135
|
-
}
|
|
136
|
-
function isDateFormat(code) {
|
|
137
|
-
const cleaned = code.replace(/"[^"]*"/g, "").replace(/\[[^\]]*\]/g, "");
|
|
138
|
-
return /[dyhs]|m+/i.test(cleaned) && /[dyhs]/i.test(cleaned);
|
|
139
|
-
}
|
|
140
|
-
function tokenizeDateFormat(format) {
|
|
141
|
-
const tokens = [];
|
|
142
|
-
let i = 0;
|
|
143
|
-
while (i < format.length) {
|
|
144
|
-
const ch = format[i];
|
|
145
|
-
if (ch === "\"") {
|
|
146
|
-
let lit = "";
|
|
147
|
-
i++;
|
|
148
|
-
while (i < format.length && format[i] !== "\"") {
|
|
149
|
-
lit += format[i];
|
|
150
|
-
i++;
|
|
151
|
-
}
|
|
152
|
-
i++;
|
|
153
|
-
tokens.push({
|
|
154
|
-
kind: "lit",
|
|
155
|
-
text: lit
|
|
156
|
-
});
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
if (ch === "\\" && i + 1 < format.length) {
|
|
160
|
-
tokens.push({
|
|
161
|
-
kind: "lit",
|
|
162
|
-
text: format[i + 1]
|
|
163
|
-
});
|
|
164
|
-
i += 2;
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
if (ch === "[") {
|
|
168
|
-
let body = "";
|
|
169
|
-
i++;
|
|
170
|
-
while (i < format.length && format[i] !== "]") {
|
|
171
|
-
body += format[i];
|
|
172
|
-
i++;
|
|
173
|
-
}
|
|
174
|
-
i++;
|
|
175
|
-
if (/^h+$/i.test(body)) tokens.push({
|
|
176
|
-
kind: "elapsed-h",
|
|
177
|
-
text: body
|
|
178
|
-
});
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
const lower = ch.toLowerCase();
|
|
182
|
-
if (lower === "y" || lower === "m" || lower === "d" || lower === "h" || lower === "s") {
|
|
183
|
-
let run = ch;
|
|
184
|
-
i++;
|
|
185
|
-
while (i < format.length && format[i].toLowerCase() === lower) {
|
|
186
|
-
run += format[i];
|
|
187
|
-
i++;
|
|
188
|
-
}
|
|
189
|
-
if (lower === "y") tokens.push({
|
|
190
|
-
kind: "y",
|
|
191
|
-
text: run
|
|
192
|
-
});
|
|
193
|
-
else if (lower === "d") tokens.push({
|
|
194
|
-
kind: "d",
|
|
195
|
-
text: run
|
|
196
|
-
});
|
|
197
|
-
else if (lower === "h") tokens.push({
|
|
198
|
-
kind: "h",
|
|
199
|
-
text: run
|
|
200
|
-
});
|
|
201
|
-
else if (lower === "s") tokens.push({
|
|
202
|
-
kind: "s",
|
|
203
|
-
text: run
|
|
204
|
-
});
|
|
205
|
-
else tokens.push({
|
|
206
|
-
kind: "m",
|
|
207
|
-
text: run
|
|
208
|
-
});
|
|
209
|
-
continue;
|
|
210
|
-
}
|
|
211
|
-
if (format.startsWith("AM/PM", i) || format.startsWith("A/P", i)) {
|
|
212
|
-
const len = format.startsWith("AM/PM", i) ? 5 : 3;
|
|
213
|
-
tokens.push({
|
|
214
|
-
kind: "ampm",
|
|
215
|
-
text: format.substring(i, i + len)
|
|
216
|
-
});
|
|
217
|
-
i += len;
|
|
218
|
-
continue;
|
|
219
|
-
}
|
|
220
|
-
tokens.push({
|
|
221
|
-
kind: "lit",
|
|
222
|
-
text: ch
|
|
223
|
-
});
|
|
224
|
-
i++;
|
|
225
|
-
}
|
|
226
|
-
return tokens;
|
|
227
|
-
}
|
|
228
|
-
function resolveMonthVsMinute(tokens) {
|
|
229
|
-
const resolved = tokens.map((t) => ({ ...t }));
|
|
230
|
-
for (let i = 0; i < resolved.length; i++) {
|
|
231
|
-
const t = resolved[i];
|
|
232
|
-
if (t.kind !== "m") continue;
|
|
233
|
-
let prev = i - 1;
|
|
234
|
-
while (prev >= 0 && resolved[prev].kind === "lit") prev--;
|
|
235
|
-
let next = i + 1;
|
|
236
|
-
while (next < resolved.length && resolved[next].kind === "lit") next++;
|
|
237
|
-
const prevIsHour = prev >= 0 && resolved[prev].kind === "h";
|
|
238
|
-
const nextIsSec = next < resolved.length && resolved[next].kind === "s";
|
|
239
|
-
if (prevIsHour || nextIsSec) continue;
|
|
240
|
-
resolved[i] = {
|
|
241
|
-
kind: "M",
|
|
242
|
-
text: t.text
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
return resolved;
|
|
246
|
-
}
|
|
247
|
-
function formatExcelDate(rawValue, format, date1904) {
|
|
248
|
-
const serial = Number(rawValue);
|
|
249
|
-
if (!Number.isFinite(serial)) return rawValue;
|
|
250
|
-
format = splitSections(format)[0] ?? format;
|
|
251
|
-
const date = excelSerialToDate(serial, date1904);
|
|
252
|
-
const year = date.getUTCFullYear();
|
|
253
|
-
const month = date.getUTCMonth() + 1;
|
|
254
|
-
const day = date.getUTCDate();
|
|
255
|
-
const weekday = date.getUTCDay();
|
|
256
|
-
const hour24 = date.getUTCHours();
|
|
257
|
-
const minute = date.getUTCMinutes();
|
|
258
|
-
const second = date.getUTCSeconds();
|
|
259
|
-
const tokens = resolveMonthVsMinute(tokenizeDateFormat(format));
|
|
260
|
-
const hourValue = tokens.some((t) => t.kind === "ampm") ? hour24 % 12 === 0 ? 12 : hour24 % 12 : hour24;
|
|
261
|
-
const ampmLabel = (template) => {
|
|
262
|
-
const isUpper = template[0] === "A";
|
|
263
|
-
const isShort = template.length <= 3;
|
|
264
|
-
if (hour24 < 12) return isShort ? isUpper ? "A" : "a" : isUpper ? "AM" : "am";
|
|
265
|
-
return isShort ? isUpper ? "P" : "p" : isUpper ? "PM" : "pm";
|
|
266
|
-
};
|
|
267
|
-
let out = "";
|
|
268
|
-
for (const t of tokens) switch (t.kind) {
|
|
269
|
-
case "lit":
|
|
270
|
-
out += t.text;
|
|
271
|
-
break;
|
|
272
|
-
case "y":
|
|
273
|
-
out += t.text.length <= 2 ? pad2(year % 100) : String(year).padStart(4, "0");
|
|
274
|
-
break;
|
|
275
|
-
case "M": {
|
|
276
|
-
const len = t.text.length;
|
|
277
|
-
if (len === 5) out += MONTH_FULL[month - 1][0];
|
|
278
|
-
else if (len === 4) out += MONTH_FULL[month - 1];
|
|
279
|
-
else if (len === 3) out += MONTH_ABBR[month - 1];
|
|
280
|
-
else if (len === 2) out += pad2(month);
|
|
281
|
-
else out += String(month);
|
|
282
|
-
break;
|
|
283
|
-
}
|
|
284
|
-
case "d": {
|
|
285
|
-
const len = t.text.length;
|
|
286
|
-
if (len >= 4) out += DAY_FULL[weekday];
|
|
287
|
-
else if (len === 3) out += DAY_ABBR[weekday];
|
|
288
|
-
else if (len === 2) out += pad2(day);
|
|
289
|
-
else out += String(day);
|
|
290
|
-
break;
|
|
291
|
-
}
|
|
292
|
-
case "h":
|
|
293
|
-
out += t.text.length >= 2 ? pad2(hourValue) : String(hourValue);
|
|
294
|
-
break;
|
|
295
|
-
case "elapsed-h":
|
|
296
|
-
out += String(Math.floor(serial * 24));
|
|
297
|
-
break;
|
|
298
|
-
case "m":
|
|
299
|
-
out += t.text.length >= 2 ? pad2(minute) : String(minute);
|
|
300
|
-
break;
|
|
301
|
-
case "s":
|
|
302
|
-
out += t.text.length >= 2 ? pad2(second) : String(second);
|
|
303
|
-
break;
|
|
304
|
-
case "ampm":
|
|
305
|
-
out += ampmLabel(t.text);
|
|
306
|
-
break;
|
|
307
|
-
}
|
|
308
|
-
return out;
|
|
309
|
-
}
|
|
310
|
-
function defaultNumberRender(rawValue) {
|
|
311
|
-
const n = Number(rawValue);
|
|
312
|
-
if (!Number.isFinite(n)) return rawValue;
|
|
313
|
-
if (Number.isInteger(n)) return String(n);
|
|
314
|
-
return String(n);
|
|
315
|
-
}
|
|
316
|
-
function applyFormatString(rawValue, format) {
|
|
317
|
-
const n = Number(rawValue);
|
|
318
|
-
const sections = splitSections(format);
|
|
319
|
-
if (!Number.isFinite(n)) {
|
|
320
|
-
const textSection = sections[3];
|
|
321
|
-
if (textSection !== void 0) return textSection.replace(/@/g, rawValue);
|
|
322
|
-
return rawValue;
|
|
323
|
-
}
|
|
324
|
-
let sectionIdx;
|
|
325
|
-
if (n > 0) sectionIdx = 0;
|
|
326
|
-
else if (n < 0) sectionIdx = sections.length > 1 ? 1 : 0;
|
|
327
|
-
else sectionIdx = sections.length > 2 ? 2 : 0;
|
|
328
|
-
return applyNumericSection(n, sections[sectionIdx] ?? sections[0], sectionIdx === 1);
|
|
329
|
-
}
|
|
330
|
-
function splitSections(format) {
|
|
331
|
-
const out = [];
|
|
332
|
-
let current = "";
|
|
333
|
-
let inQuotes = false;
|
|
334
|
-
let bracketDepth = 0;
|
|
335
|
-
for (let i = 0; i < format.length; i++) {
|
|
336
|
-
const ch = format[i];
|
|
337
|
-
if (ch === "\"") {
|
|
338
|
-
inQuotes = !inQuotes;
|
|
339
|
-
current += ch;
|
|
340
|
-
continue;
|
|
341
|
-
}
|
|
342
|
-
if (!inQuotes) {
|
|
343
|
-
if (ch === "[") bracketDepth++;
|
|
344
|
-
else if (ch === "]") bracketDepth = Math.max(0, bracketDepth - 1);
|
|
345
|
-
else if (ch === "\\" && i + 1 < format.length) {
|
|
346
|
-
current += ch + format[i + 1];
|
|
347
|
-
i++;
|
|
348
|
-
continue;
|
|
349
|
-
} else if (ch === ";" && bracketDepth === 0) {
|
|
350
|
-
out.push(current);
|
|
351
|
-
current = "";
|
|
352
|
-
continue;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
current += ch;
|
|
356
|
-
}
|
|
357
|
-
out.push(current);
|
|
358
|
-
return out;
|
|
359
|
-
}
|
|
360
|
-
function countDigitPlaceholders(s) {
|
|
361
|
-
let n = 0;
|
|
362
|
-
for (const c of s) if (c === "0" || c === "#" || c === "?") n++;
|
|
363
|
-
return n;
|
|
364
|
-
}
|
|
365
|
-
function formatScientific(value, cleaned, negativeSection) {
|
|
366
|
-
const m = /^(.*?)([eE])([+-])(.*)$/.exec(cleaned);
|
|
367
|
-
if (!m) return cleaned;
|
|
368
|
-
const mantissaFmt = m[1];
|
|
369
|
-
const eChar = m[2];
|
|
370
|
-
const expSignFmt = m[3];
|
|
371
|
-
const expFmt = m[4];
|
|
372
|
-
const dot = mantissaFmt.indexOf(".");
|
|
373
|
-
const intDigits = Math.max(1, countDigitPlaceholders(dot >= 0 ? mantissaFmt.slice(0, dot) : mantissaFmt));
|
|
374
|
-
const decimals = dot >= 0 ? countDigitPlaceholders(mantissaFmt.slice(dot + 1)) : 0;
|
|
375
|
-
let exp = 0;
|
|
376
|
-
let mant = Math.abs(value);
|
|
377
|
-
if (mant !== 0) {
|
|
378
|
-
exp = Math.floor(Math.log10(mant));
|
|
379
|
-
exp -= (exp % intDigits + intDigits) % intDigits;
|
|
380
|
-
mant = mant / Math.pow(10, exp);
|
|
381
|
-
if (Number(mant.toFixed(decimals)) >= Math.pow(10, intDigits)) {
|
|
382
|
-
exp += intDigits;
|
|
383
|
-
mant = mant / Math.pow(10, intDigits);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
const mantStr = mant.toFixed(decimals);
|
|
387
|
-
const expDigits = countDigitPlaceholders(expFmt) || 2;
|
|
388
|
-
const expStr = String(Math.abs(exp)).padStart(expDigits, "0");
|
|
389
|
-
return `${value < 0 && !negativeSection ? "-" : ""}${mantStr}${eChar}${exp < 0 ? "-" : expSignFmt === "+" ? "+" : ""}${expStr}`;
|
|
390
|
-
}
|
|
391
|
-
function applyNumericSection(value, format, negativeSection) {
|
|
392
|
-
const cleaned = format.replace(/\[[^\]]*\]/g, "");
|
|
393
|
-
if (/[eE][+-]/.test(cleaned)) return formatScientific(value, cleaned, negativeSection);
|
|
394
|
-
const isPercent = cleaned.includes("%");
|
|
395
|
-
let magnitude = Math.abs(value);
|
|
396
|
-
if (isPercent) magnitude *= 100;
|
|
397
|
-
const { intFormat, decFormat, literalPrefix, literalSuffix } = splitNumberFormat(cleaned);
|
|
398
|
-
let decimals = 0;
|
|
399
|
-
for (const c of decFormat) if (c === "0" || c === "#") decimals++;
|
|
400
|
-
const [intRaw, decRaw] = magnitude.toFixed(decimals).split(".");
|
|
401
|
-
let numberPart = /,(?=\d)/.test(intFormat) || /[0#],[0#]/.test(intFormat) ? intRaw.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : intRaw;
|
|
402
|
-
if (decimals > 0) {
|
|
403
|
-
let dec = decRaw ?? "".padEnd(decimals, "0");
|
|
404
|
-
if (dec.length < decimals) dec = dec.padEnd(decimals, "0");
|
|
405
|
-
let kept = "";
|
|
406
|
-
for (let i = 0; i < decFormat.length; i++) {
|
|
407
|
-
const placeholder = decFormat[i];
|
|
408
|
-
const digit = dec[i] ?? "0";
|
|
409
|
-
if (placeholder === "0") kept += digit;
|
|
410
|
-
else if (placeholder === "#") {
|
|
411
|
-
if (digit !== "0" || kept.length > 0) kept += digit;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
if (kept.length > 0) numberPart += "." + kept;
|
|
415
|
-
else if (decFormat.includes("0")) numberPart += "." + dec;
|
|
416
|
-
}
|
|
417
|
-
let signPrefix = "";
|
|
418
|
-
if (value < 0 && !negativeSection) signPrefix = "-";
|
|
419
|
-
return `${literalPrefix}${signPrefix}${numberPart}${isPercent ? "%" : ""}${literalSuffix}`;
|
|
420
|
-
}
|
|
421
|
-
function splitNumberFormat(cleaned) {
|
|
422
|
-
let firstDigit = -1;
|
|
423
|
-
let lastDigit = -1;
|
|
424
|
-
for (let i = 0; i < cleaned.length; i++) {
|
|
425
|
-
const ch = cleaned[i];
|
|
426
|
-
if (ch === "0" || ch === "#") {
|
|
427
|
-
if (firstDigit < 0) firstDigit = i;
|
|
428
|
-
lastDigit = i;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
if (firstDigit < 0) return {
|
|
432
|
-
literalPrefix: cleaned,
|
|
433
|
-
intFormat: "",
|
|
434
|
-
decFormat: "",
|
|
435
|
-
literalSuffix: ""
|
|
436
|
-
};
|
|
437
|
-
const literalPrefix = unquoteLiteral(cleaned.substring(0, firstDigit));
|
|
438
|
-
const literalSuffix = unquoteLiteral(cleaned.substring(lastDigit + 1));
|
|
439
|
-
const digitRange = cleaned.substring(firstDigit, lastDigit + 1);
|
|
440
|
-
const dotIdx = digitRange.indexOf(".");
|
|
441
|
-
return {
|
|
442
|
-
literalPrefix,
|
|
443
|
-
intFormat: dotIdx >= 0 ? digitRange.substring(0, dotIdx) : digitRange,
|
|
444
|
-
decFormat: dotIdx >= 0 ? digitRange.substring(dotIdx + 1) : "",
|
|
445
|
-
literalSuffix
|
|
446
|
-
};
|
|
447
|
-
}
|
|
448
|
-
function unquoteLiteral(s) {
|
|
449
|
-
let out = "";
|
|
450
|
-
for (let i = 0; i < s.length; i++) {
|
|
451
|
-
const ch = s[i];
|
|
452
|
-
if (ch === "\"") {
|
|
453
|
-
i++;
|
|
454
|
-
while (i < s.length && s[i] !== "\"") {
|
|
455
|
-
out += s[i];
|
|
456
|
-
i++;
|
|
457
|
-
}
|
|
458
|
-
continue;
|
|
459
|
-
}
|
|
460
|
-
if (ch === "\\" && i + 1 < s.length) {
|
|
461
|
-
out += s[i + 1];
|
|
462
|
-
i++;
|
|
463
|
-
continue;
|
|
464
|
-
}
|
|
465
|
-
if (ch === "_" && i + 1 < s.length) {
|
|
466
|
-
out += " ";
|
|
467
|
-
i++;
|
|
468
|
-
continue;
|
|
469
|
-
}
|
|
470
|
-
if (ch === "%") continue;
|
|
471
|
-
out += ch;
|
|
472
|
-
}
|
|
473
|
-
return out;
|
|
474
|
-
}
|
|
475
|
-
//#endregion
|
|
476
|
-
export { applyNumberFormat, excelSerialFromUtcParts, excelSerialToDate };
|