ooxml.js 6.3.3 → 6.3.4

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.
@@ -3,7 +3,6 @@ const require_xml_fragment = require("../../xml/fragment.cjs");
3
3
  const require_xml_entities = require("../../xml/entities.cjs");
4
4
  require("../shared/units.cjs");
5
5
  const require_typed_xlsx_defined_names = require("./defined-names.cjs");
6
- const require_typed_xlsx_number_format = require("./number-format.cjs");
7
6
  const require_typed_xlsx_util = require("./util.cjs");
8
7
  const require_typed_xlsx_print_settings = require("./print-settings.cjs");
9
8
  const require_typed_xlsx_units = require("./units.cjs");
@@ -12,6 +11,7 @@ const require_typed_xlsx_shared_strings = require("./shared-strings.cjs");
12
11
  const require_typed_xlsx_styles = require("./styles.cjs");
13
12
  const require_typed_xlsx_conditional_format = require("./conditional-format.cjs");
14
13
  const require_typed_xlsx_data_validation = require("./data-validation.cjs");
14
+ const require_typed_xlsx_number_format = require("./number-format.cjs");
15
15
  let document_schema_js = require("document-schema.js");
16
16
  //#region src/typed/xlsx/build.ts
17
17
  const SML_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
@@ -2,7 +2,6 @@ import { el, txt } from "../../xml/fragment.js";
2
2
  import { encodeXmlText } from "../../xml/entities.js";
3
3
  import "../shared/units.js";
4
4
  import { XLNM_PRINT_AREA, XLNM_PRINT_TITLES, buildPrintAreaValue, buildPrintTitlesValue } from "./defined-names.js";
5
- import { BOOLEAN_NUMBER_FORMAT, DATE_NUMBER_FORMAT, DATE_TIME_NUMBER_FORMAT, PERCENTAGE_NUMBER_FORMAT, TIME_NUMBER_FORMAT, currencyNumberFormat } from "./number-format.js";
6
5
  import { pageSizeToPaperSizeCode, ptToUniversalMeasure, writeXmlBool } from "./util.js";
7
6
  import { DEFAULT_HEADER_FOOTER_MARGIN_PT } from "./print-settings.js";
8
7
  import { ptToColumnWidthChars } from "./units.js";
@@ -11,6 +10,7 @@ import { SharedStringTable } from "./shared-strings.js";
11
10
  import { CellFormatTable, RESERVED_BORDER_INDICES, RESERVED_FILL_INDICES } from "./styles.js";
12
11
  import { DxfTable, buildConditionalFormattingElements } from "./conditional-format.js";
13
12
  import { buildDataValidationsElement } from "./data-validation.js";
13
+ import { BOOLEAN_NUMBER_FORMAT, DATE_NUMBER_FORMAT, DATE_TIME_NUMBER_FORMAT, PERCENTAGE_NUMBER_FORMAT, TIME_NUMBER_FORMAT, currencyNumberFormat } from "./number-format.js";
14
14
  import { cellReference, rangeReference } from "document-schema.js";
15
15
  //#region src/typed/xlsx/build.ts
16
16
  const SML_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
@@ -3,7 +3,6 @@ const require_xml_build = require("../../xml/build.cjs");
3
3
  const require_typed_util = require("../util.cjs");
4
4
  const require_typed_shared_metadata = require("../shared/metadata.cjs");
5
5
  const require_typed_xlsx_defined_names = require("./defined-names.cjs");
6
- const require_typed_xlsx_number_format = require("./number-format.cjs");
7
6
  const require_typed_xlsx_util = require("./util.cjs");
8
7
  const require_typed_xlsx_print_settings = require("./print-settings.cjs");
9
8
  const require_typed_xlsx_units = require("./units.cjs");
@@ -15,6 +14,7 @@ const require_typed_xlsx_comments = require("./comments.cjs");
15
14
  const require_typed_xlsx_conditional_format = require("./conditional-format.cjs");
16
15
  const require_typed_xlsx_data_validation = require("./data-validation.cjs");
17
16
  let document_schema_js = require("document-schema.js");
17
+ let excel_number_format = require("excel-number-format");
18
18
  //#region src/typed/xlsx/content.ts
19
19
  const WORKBOOK_PATH = "xl/workbook.xml";
20
20
  function resolveSheetEntries(pkg) {
@@ -116,7 +116,7 @@ function entryOf(cell, context) {
116
116
  function numberFormatOf(cell, context) {
117
117
  const entry = entryOf(cell, context);
118
118
  if (entry?.numberFormatCode === void 0) return PLAIN_NUMBER;
119
- return require_typed_xlsx_number_format.classifyNumberFormat(entry.numberFormatCode);
119
+ return (0, excel_number_format.classifyNumberFormat)(entry.numberFormatCode);
120
120
  }
121
121
  function resolveNumericValue(num, cell, context) {
122
122
  const format = numberFormatOf(cell, context);
@@ -2,7 +2,6 @@ import { buildXml } from "../../xml/build.js";
2
2
  import { attr, childrenWithTag, elementsWithTag, resolveRelationships, rootElement, textContent } from "../util.js";
3
3
  import { readCoreProperties } from "../shared/metadata.js";
4
4
  import { readDefinedNamesBySheet } from "./defined-names.js";
5
- import { classifyNumberFormat } from "./number-format.js";
6
5
  import { readXmlBool } from "./util.js";
7
6
  import { readPrintSettings } from "./print-settings.js";
8
7
  import { columnWidthCharsToPt } from "./units.js";
@@ -14,6 +13,7 @@ import { readSheetCellComments } from "./comments.js";
14
13
  import { readConditionalFormats } from "./conditional-format.js";
15
14
  import { readDataValidations } from "./data-validation.js";
16
15
  import { parseCellReference, parseRangeReference } from "document-schema.js";
16
+ import { classifyNumberFormat } from "excel-number-format";
17
17
  //#region src/typed/xlsx/content.ts
18
18
  const WORKBOOK_PATH = "xl/workbook.xml";
19
19
  function resolveSheetEntries(pkg) {
@@ -1,283 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let excel_number_format = require("excel-number-format");
2
3
  //#region src/typed/xlsx/number-format.ts
3
- const MAX_NUMBER_FORMAT_SECTIONS = 4;
4
- function at(chars, index) {
5
- return chars[index] ?? "";
6
- }
7
- function tokenizeNumberFormat(formatCode) {
8
- const chars = [...formatCode];
9
- const tokens = [];
10
- let index = 0;
11
- while (index < chars.length) {
12
- const char = at(chars, index);
13
- if (char === "\"") {
14
- let text = "";
15
- index += 1;
16
- while (index < chars.length && at(chars, index) !== "\"") {
17
- text += at(chars, index);
18
- index += 1;
19
- }
20
- index += 1;
21
- tokens.push({
22
- kind: "literal",
23
- text
24
- });
25
- continue;
26
- }
27
- if (char === "\\" || char === "_" || char === "*") {
28
- tokens.push({
29
- kind: "literal",
30
- text: at(chars, index + 1)
31
- });
32
- index += 2;
33
- continue;
34
- }
35
- if (char === "[") {
36
- let body = "";
37
- index += 1;
38
- while (index < chars.length && at(chars, index) !== "]") {
39
- body += at(chars, index);
40
- index += 1;
41
- }
42
- index += 1;
43
- tokens.push({
44
- kind: "bracket",
45
- body
46
- });
47
- continue;
48
- }
49
- if (char === ";") {
50
- tokens.push({ kind: "separator" });
51
- index += 1;
52
- continue;
53
- }
54
- tokens.push({
55
- kind: "code",
56
- char
57
- });
58
- index += 1;
59
- }
60
- return tokens;
61
- }
62
- function splitNumberFormatSections(tokens) {
63
- const sections = [];
64
- let current = [];
65
- for (const token of tokens) {
66
- if (token.kind === "separator") {
67
- sections.push(current);
68
- current = [];
69
- continue;
70
- }
71
- current.push(token);
72
- }
73
- sections.push(current);
74
- return sections.slice(0, 4);
75
- }
76
- const CURRENCY_SYMBOL = /\p{Sc}/u;
77
- function containsCurrencySymbol(text) {
78
- return CURRENCY_SYMBOL.test(text);
79
- }
80
- function isIsoCurrencyCodeShape(marker) {
81
- if (marker.length !== 3) return false;
82
- for (const char of marker) {
83
- const upper = char.toUpperCase();
84
- if (upper < "A" || upper > "Z") return false;
85
- }
86
- return true;
87
- }
88
- function isElapsedBracketBody(body) {
89
- let letter;
90
- for (const char of body) {
91
- const lower = char.toLowerCase();
92
- if (letter === void 0) {
93
- if (lower !== "h" && lower !== "m" && lower !== "s") return false;
94
- letter = lower;
95
- } else if (lower !== letter) return false;
96
- }
97
- return letter !== void 0;
98
- }
99
- function classifyBracket(body) {
100
- if (body.startsWith("$")) {
101
- const rest = body.slice(1);
102
- const dashIndex = rest.indexOf("-");
103
- const marker = dashIndex === -1 ? rest : rest.slice(0, dashIndex);
104
- if (marker === "") return { kind: "none" };
105
- return isIsoCurrencyCodeShape(marker) ? {
106
- kind: "currency",
107
- code: marker.toUpperCase()
108
- } : { kind: "currency" };
109
- }
110
- return isElapsedBracketBody(body) ? { kind: "elapsed" } : { kind: "none" };
111
- }
112
- const AMPM_MARKERS = ["am/pm", "a/p"];
113
- const AMPM_LETTER = "ampm";
114
- function matchesAt(chars, index, marker) {
115
- return [...marker].every((char, offset) => at(chars, index + offset).toLowerCase() === char);
116
- }
117
- function codeRunsOf(section) {
118
- const chars = [];
119
- for (const token of section) if (token.kind === "code") chars.push(token.char);
120
- const runs = [];
121
- let index = 0;
122
- while (index < chars.length) {
123
- const marker = AMPM_MARKERS.find((candidate) => matchesAt(chars, index, candidate));
124
- if (marker !== void 0) {
125
- runs.push({
126
- letter: AMPM_LETTER,
127
- length: marker.length
128
- });
129
- index += marker.length;
130
- continue;
131
- }
132
- const char = at(chars, index).toLowerCase();
133
- let length = 0;
134
- while (index + length < chars.length && at(chars, index + length).toLowerCase() === char) length += 1;
135
- runs.push({
136
- letter: char,
137
- length
138
- });
139
- index += length;
140
- }
141
- return runs;
142
- }
143
- const RESOLVING_LETTERS = [
144
- "y",
145
- "d",
146
- "h",
147
- "s"
148
- ];
149
- function nearestResolvingLetter(runs, from, step) {
150
- for (let index = from + step; index >= 0 && index < runs.length; index += step) {
151
- const run = runs[index];
152
- if (run !== void 0 && RESOLVING_LETTERS.includes(run.letter)) return run.letter;
153
- }
154
- }
155
- function monthRunIsMinutes(runs, index) {
156
- return nearestResolvingLetter(runs, index, -1) === "h" || nearestResolvingLetter(runs, index, 1) === "s";
157
- }
158
- const PLAIN_NUMBER = { kind: "number" };
159
- const NUMERIC_CODES = [
160
- "0",
161
- "#",
162
- "?",
163
- ".",
164
- ","
165
- ];
166
- function collectSignals(section) {
167
- const signals = {
168
- hasDate: false,
169
- hasTime: false,
170
- hasElapsed: false,
171
- hasPercent: false,
172
- hasNumeric: false,
173
- hasText: false,
174
- hasCurrency: false
175
- };
176
- for (const token of section) {
177
- if (token.kind === "literal" && containsCurrencySymbol(token.text)) signals.hasCurrency = true;
178
- if (token.kind === "bracket") {
179
- const meaning = classifyBracket(token.body);
180
- if (meaning.kind === "elapsed") signals.hasElapsed = true;
181
- if (meaning.kind === "currency") {
182
- signals.hasCurrency = true;
183
- if (signals.currencyCode === void 0 && meaning.code !== void 0) signals.currencyCode = meaning.code;
184
- }
185
- }
186
- }
187
- const runs = codeRunsOf(section);
188
- runs.forEach((run, index) => {
189
- if (run.letter === "y" || run.letter === "d") {
190
- signals.hasDate = true;
191
- return;
192
- }
193
- if (run.letter === "h" || run.letter === "s" || run.letter === AMPM_LETTER) {
194
- signals.hasTime = true;
195
- return;
196
- }
197
- if (run.letter === "m") {
198
- if (run.length <= 2 && monthRunIsMinutes(runs, index)) signals.hasTime = true;
199
- else signals.hasDate = true;
200
- return;
201
- }
202
- if (run.letter === "e") {
203
- const next = runs[index + 1];
204
- signals.hasNumeric = signals.hasNumeric || next?.letter === "+" || next?.letter === "-";
205
- return;
206
- }
207
- if (run.letter === "%") {
208
- signals.hasPercent = true;
209
- return;
210
- }
211
- if (run.letter === "@") {
212
- signals.hasText = true;
213
- return;
214
- }
215
- if (NUMERIC_CODES.includes(run.letter)) {
216
- signals.hasNumeric = true;
217
- return;
218
- }
219
- if (containsCurrencySymbol(run.letter)) signals.hasCurrency = true;
220
- });
221
- return signals;
222
- }
223
- function classifySection(section) {
224
- const signals = collectSignals(section);
225
- if (signals.hasElapsed) return { kind: "elapsedTime" };
226
- if (signals.hasDate) return signals.hasTime ? { kind: "dateTime" } : { kind: "date" };
227
- if (signals.hasTime) return { kind: "time" };
228
- if (signals.hasPercent) return { kind: "percentage" };
229
- if (signals.hasCurrency) {
230
- const code = signals.currencyCode;
231
- return code === void 0 ? { kind: "currency" } : {
232
- kind: "currency",
233
- code
234
- };
235
- }
236
- if (signals.hasText && !signals.hasNumeric) return { kind: "text" };
237
- return PLAIN_NUMBER;
238
- }
239
- function classifyNumberFormat(formatCode) {
240
- const first = splitNumberFormatSections(tokenizeNumberFormat(formatCode))[0];
241
- return first === void 0 ? PLAIN_NUMBER : classifySection(first);
242
- }
243
- const BUILTIN_NUMBER_FORMATS = /* @__PURE__ */ new Map([
244
- [0, "General"],
245
- [1, "0"],
246
- [2, "0.00"],
247
- [3, "#,##0"],
248
- [4, "#,##0.00"],
249
- [5, "$#,##0_);($#,##0)"],
250
- [6, "$#,##0_);[Red]($#,##0)"],
251
- [7, "$#,##0.00_);($#,##0.00)"],
252
- [8, "$#,##0.00_);[Red]($#,##0.00)"],
253
- [9, "0%"],
254
- [10, "0.00%"],
255
- [11, "0.00E+00"],
256
- [12, "# ?/?"],
257
- [13, "# ??/??"],
258
- [14, "mm-dd-yy"],
259
- [15, "d-mmm-yy"],
260
- [16, "d-mmm"],
261
- [17, "mmm-yy"],
262
- [18, "h:mm AM/PM"],
263
- [19, "h:mm:ss AM/PM"],
264
- [20, "h:mm"],
265
- [21, "h:mm:ss"],
266
- [22, "m/d/yy h:mm"],
267
- [37, "#,##0 ;(#,##0)"],
268
- [38, "#,##0 ;[Red](#,##0)"],
269
- [39, "#,##0.00;(#,##0.00)"],
270
- [40, "#,##0.00;[Red](#,##0.00)"],
271
- [41, "_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)"],
272
- [42, "_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)"],
273
- [43, "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)"],
274
- [44, "_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)"],
275
- [45, "mm:ss"],
276
- [46, "[h]:mm:ss"],
277
- [47, "mmss.0"],
278
- [48, "##0.0E+0"],
279
- [49, "@"]
280
- ]);
281
4
  const PERCENTAGE_NUMBER_FORMAT = {
282
5
  kind: "builtin",
283
6
  id: 10
@@ -303,7 +26,7 @@ const BOOLEAN_NUMBER_FORMAT = {
303
26
  code: "\"TRUE\";\"TRUE\";\"FALSE\""
304
27
  };
305
28
  function currencyNumberFormat(code) {
306
- if (code === void 0 || !isIsoCurrencyCodeShape(code)) return AMOUNT_NUMBER_FORMAT;
29
+ if (code === void 0 || !(0, excel_number_format.isIsoCurrencyCodeShape)(code)) return AMOUNT_NUMBER_FORMAT;
307
30
  return {
308
31
  kind: "custom",
309
32
  code: `[$${code.toUpperCase()}]#,##0.00`
@@ -312,13 +35,8 @@ function currencyNumberFormat(code) {
312
35
  //#endregion
313
36
  exports.AMOUNT_NUMBER_FORMAT = AMOUNT_NUMBER_FORMAT;
314
37
  exports.BOOLEAN_NUMBER_FORMAT = BOOLEAN_NUMBER_FORMAT;
315
- exports.BUILTIN_NUMBER_FORMATS = BUILTIN_NUMBER_FORMATS;
316
38
  exports.DATE_NUMBER_FORMAT = DATE_NUMBER_FORMAT;
317
39
  exports.DATE_TIME_NUMBER_FORMAT = DATE_TIME_NUMBER_FORMAT;
318
- exports.MAX_NUMBER_FORMAT_SECTIONS = MAX_NUMBER_FORMAT_SECTIONS;
319
40
  exports.PERCENTAGE_NUMBER_FORMAT = PERCENTAGE_NUMBER_FORMAT;
320
41
  exports.TIME_NUMBER_FORMAT = TIME_NUMBER_FORMAT;
321
- exports.classifyNumberFormat = classifyNumberFormat;
322
42
  exports.currencyNumberFormat = currencyNumberFormat;
323
- exports.splitNumberFormatSections = splitNumberFormatSections;
324
- exports.tokenizeNumberFormat = tokenizeNumberFormat;
@@ -1,39 +1,4 @@
1
1
  //#region src/typed/xlsx/number-format.d.ts
2
- type NumberFormatToken = {
3
- kind: "literal";
4
- text: string;
5
- } | {
6
- kind: "bracket";
7
- body: string;
8
- } | {
9
- kind: "separator";
10
- } | {
11
- kind: "code";
12
- char: string;
13
- };
14
- declare const MAX_NUMBER_FORMAT_SECTIONS = 4;
15
- declare function tokenizeNumberFormat(formatCode: string): NumberFormatToken[];
16
- declare function splitNumberFormatSections(tokens: readonly NumberFormatToken[]): NumberFormatToken[][];
17
- type NumberFormatClass = {
18
- kind: "number";
19
- } | {
20
- kind: "text";
21
- } | {
22
- kind: "percentage";
23
- } | {
24
- kind: "currency";
25
- code?: string;
26
- } | {
27
- kind: "date";
28
- } | {
29
- kind: "time";
30
- } | {
31
- kind: "dateTime";
32
- } | {
33
- kind: "elapsedTime";
34
- };
35
- declare function classifyNumberFormat(formatCode: string): NumberFormatClass;
36
- declare const BUILTIN_NUMBER_FORMATS: ReadonlyMap<number, string>;
37
2
  type CellNumberFormat = {
38
3
  kind: "builtin";
39
4
  id: number;
@@ -49,4 +14,4 @@ declare const DATE_TIME_NUMBER_FORMAT: CellNumberFormat;
49
14
  declare const BOOLEAN_NUMBER_FORMAT: CellNumberFormat;
50
15
  declare function currencyNumberFormat(code: string | undefined): CellNumberFormat;
51
16
  //#endregion
52
- export { AMOUNT_NUMBER_FORMAT, BOOLEAN_NUMBER_FORMAT, BUILTIN_NUMBER_FORMATS, CellNumberFormat, DATE_NUMBER_FORMAT, DATE_TIME_NUMBER_FORMAT, MAX_NUMBER_FORMAT_SECTIONS, NumberFormatClass, NumberFormatToken, PERCENTAGE_NUMBER_FORMAT, TIME_NUMBER_FORMAT, classifyNumberFormat, currencyNumberFormat, splitNumberFormatSections, tokenizeNumberFormat };
17
+ export { AMOUNT_NUMBER_FORMAT, BOOLEAN_NUMBER_FORMAT, CellNumberFormat, DATE_NUMBER_FORMAT, DATE_TIME_NUMBER_FORMAT, PERCENTAGE_NUMBER_FORMAT, TIME_NUMBER_FORMAT, currencyNumberFormat };
@@ -1,39 +1,4 @@
1
1
  //#region src/typed/xlsx/number-format.d.ts
2
- type NumberFormatToken = {
3
- kind: "literal";
4
- text: string;
5
- } | {
6
- kind: "bracket";
7
- body: string;
8
- } | {
9
- kind: "separator";
10
- } | {
11
- kind: "code";
12
- char: string;
13
- };
14
- declare const MAX_NUMBER_FORMAT_SECTIONS = 4;
15
- declare function tokenizeNumberFormat(formatCode: string): NumberFormatToken[];
16
- declare function splitNumberFormatSections(tokens: readonly NumberFormatToken[]): NumberFormatToken[][];
17
- type NumberFormatClass = {
18
- kind: "number";
19
- } | {
20
- kind: "text";
21
- } | {
22
- kind: "percentage";
23
- } | {
24
- kind: "currency";
25
- code?: string;
26
- } | {
27
- kind: "date";
28
- } | {
29
- kind: "time";
30
- } | {
31
- kind: "dateTime";
32
- } | {
33
- kind: "elapsedTime";
34
- };
35
- declare function classifyNumberFormat(formatCode: string): NumberFormatClass;
36
- declare const BUILTIN_NUMBER_FORMATS: ReadonlyMap<number, string>;
37
2
  type CellNumberFormat = {
38
3
  kind: "builtin";
39
4
  id: number;
@@ -49,4 +14,4 @@ declare const DATE_TIME_NUMBER_FORMAT: CellNumberFormat;
49
14
  declare const BOOLEAN_NUMBER_FORMAT: CellNumberFormat;
50
15
  declare function currencyNumberFormat(code: string | undefined): CellNumberFormat;
51
16
  //#endregion
52
- export { AMOUNT_NUMBER_FORMAT, BOOLEAN_NUMBER_FORMAT, BUILTIN_NUMBER_FORMATS, CellNumberFormat, DATE_NUMBER_FORMAT, DATE_TIME_NUMBER_FORMAT, MAX_NUMBER_FORMAT_SECTIONS, NumberFormatClass, NumberFormatToken, PERCENTAGE_NUMBER_FORMAT, TIME_NUMBER_FORMAT, classifyNumberFormat, currencyNumberFormat, splitNumberFormatSections, tokenizeNumberFormat };
17
+ export { AMOUNT_NUMBER_FORMAT, BOOLEAN_NUMBER_FORMAT, CellNumberFormat, DATE_NUMBER_FORMAT, DATE_TIME_NUMBER_FORMAT, PERCENTAGE_NUMBER_FORMAT, TIME_NUMBER_FORMAT, currencyNumberFormat };
@@ -1,282 +1,5 @@
1
+ import { isIsoCurrencyCodeShape } from "excel-number-format";
1
2
  //#region src/typed/xlsx/number-format.ts
2
- const MAX_NUMBER_FORMAT_SECTIONS = 4;
3
- function at(chars, index) {
4
- return chars[index] ?? "";
5
- }
6
- function tokenizeNumberFormat(formatCode) {
7
- const chars = [...formatCode];
8
- const tokens = [];
9
- let index = 0;
10
- while (index < chars.length) {
11
- const char = at(chars, index);
12
- if (char === "\"") {
13
- let text = "";
14
- index += 1;
15
- while (index < chars.length && at(chars, index) !== "\"") {
16
- text += at(chars, index);
17
- index += 1;
18
- }
19
- index += 1;
20
- tokens.push({
21
- kind: "literal",
22
- text
23
- });
24
- continue;
25
- }
26
- if (char === "\\" || char === "_" || char === "*") {
27
- tokens.push({
28
- kind: "literal",
29
- text: at(chars, index + 1)
30
- });
31
- index += 2;
32
- continue;
33
- }
34
- if (char === "[") {
35
- let body = "";
36
- index += 1;
37
- while (index < chars.length && at(chars, index) !== "]") {
38
- body += at(chars, index);
39
- index += 1;
40
- }
41
- index += 1;
42
- tokens.push({
43
- kind: "bracket",
44
- body
45
- });
46
- continue;
47
- }
48
- if (char === ";") {
49
- tokens.push({ kind: "separator" });
50
- index += 1;
51
- continue;
52
- }
53
- tokens.push({
54
- kind: "code",
55
- char
56
- });
57
- index += 1;
58
- }
59
- return tokens;
60
- }
61
- function splitNumberFormatSections(tokens) {
62
- const sections = [];
63
- let current = [];
64
- for (const token of tokens) {
65
- if (token.kind === "separator") {
66
- sections.push(current);
67
- current = [];
68
- continue;
69
- }
70
- current.push(token);
71
- }
72
- sections.push(current);
73
- return sections.slice(0, 4);
74
- }
75
- const CURRENCY_SYMBOL = /\p{Sc}/u;
76
- function containsCurrencySymbol(text) {
77
- return CURRENCY_SYMBOL.test(text);
78
- }
79
- function isIsoCurrencyCodeShape(marker) {
80
- if (marker.length !== 3) return false;
81
- for (const char of marker) {
82
- const upper = char.toUpperCase();
83
- if (upper < "A" || upper > "Z") return false;
84
- }
85
- return true;
86
- }
87
- function isElapsedBracketBody(body) {
88
- let letter;
89
- for (const char of body) {
90
- const lower = char.toLowerCase();
91
- if (letter === void 0) {
92
- if (lower !== "h" && lower !== "m" && lower !== "s") return false;
93
- letter = lower;
94
- } else if (lower !== letter) return false;
95
- }
96
- return letter !== void 0;
97
- }
98
- function classifyBracket(body) {
99
- if (body.startsWith("$")) {
100
- const rest = body.slice(1);
101
- const dashIndex = rest.indexOf("-");
102
- const marker = dashIndex === -1 ? rest : rest.slice(0, dashIndex);
103
- if (marker === "") return { kind: "none" };
104
- return isIsoCurrencyCodeShape(marker) ? {
105
- kind: "currency",
106
- code: marker.toUpperCase()
107
- } : { kind: "currency" };
108
- }
109
- return isElapsedBracketBody(body) ? { kind: "elapsed" } : { kind: "none" };
110
- }
111
- const AMPM_MARKERS = ["am/pm", "a/p"];
112
- const AMPM_LETTER = "ampm";
113
- function matchesAt(chars, index, marker) {
114
- return [...marker].every((char, offset) => at(chars, index + offset).toLowerCase() === char);
115
- }
116
- function codeRunsOf(section) {
117
- const chars = [];
118
- for (const token of section) if (token.kind === "code") chars.push(token.char);
119
- const runs = [];
120
- let index = 0;
121
- while (index < chars.length) {
122
- const marker = AMPM_MARKERS.find((candidate) => matchesAt(chars, index, candidate));
123
- if (marker !== void 0) {
124
- runs.push({
125
- letter: AMPM_LETTER,
126
- length: marker.length
127
- });
128
- index += marker.length;
129
- continue;
130
- }
131
- const char = at(chars, index).toLowerCase();
132
- let length = 0;
133
- while (index + length < chars.length && at(chars, index + length).toLowerCase() === char) length += 1;
134
- runs.push({
135
- letter: char,
136
- length
137
- });
138
- index += length;
139
- }
140
- return runs;
141
- }
142
- const RESOLVING_LETTERS = [
143
- "y",
144
- "d",
145
- "h",
146
- "s"
147
- ];
148
- function nearestResolvingLetter(runs, from, step) {
149
- for (let index = from + step; index >= 0 && index < runs.length; index += step) {
150
- const run = runs[index];
151
- if (run !== void 0 && RESOLVING_LETTERS.includes(run.letter)) return run.letter;
152
- }
153
- }
154
- function monthRunIsMinutes(runs, index) {
155
- return nearestResolvingLetter(runs, index, -1) === "h" || nearestResolvingLetter(runs, index, 1) === "s";
156
- }
157
- const PLAIN_NUMBER = { kind: "number" };
158
- const NUMERIC_CODES = [
159
- "0",
160
- "#",
161
- "?",
162
- ".",
163
- ","
164
- ];
165
- function collectSignals(section) {
166
- const signals = {
167
- hasDate: false,
168
- hasTime: false,
169
- hasElapsed: false,
170
- hasPercent: false,
171
- hasNumeric: false,
172
- hasText: false,
173
- hasCurrency: false
174
- };
175
- for (const token of section) {
176
- if (token.kind === "literal" && containsCurrencySymbol(token.text)) signals.hasCurrency = true;
177
- if (token.kind === "bracket") {
178
- const meaning = classifyBracket(token.body);
179
- if (meaning.kind === "elapsed") signals.hasElapsed = true;
180
- if (meaning.kind === "currency") {
181
- signals.hasCurrency = true;
182
- if (signals.currencyCode === void 0 && meaning.code !== void 0) signals.currencyCode = meaning.code;
183
- }
184
- }
185
- }
186
- const runs = codeRunsOf(section);
187
- runs.forEach((run, index) => {
188
- if (run.letter === "y" || run.letter === "d") {
189
- signals.hasDate = true;
190
- return;
191
- }
192
- if (run.letter === "h" || run.letter === "s" || run.letter === AMPM_LETTER) {
193
- signals.hasTime = true;
194
- return;
195
- }
196
- if (run.letter === "m") {
197
- if (run.length <= 2 && monthRunIsMinutes(runs, index)) signals.hasTime = true;
198
- else signals.hasDate = true;
199
- return;
200
- }
201
- if (run.letter === "e") {
202
- const next = runs[index + 1];
203
- signals.hasNumeric = signals.hasNumeric || next?.letter === "+" || next?.letter === "-";
204
- return;
205
- }
206
- if (run.letter === "%") {
207
- signals.hasPercent = true;
208
- return;
209
- }
210
- if (run.letter === "@") {
211
- signals.hasText = true;
212
- return;
213
- }
214
- if (NUMERIC_CODES.includes(run.letter)) {
215
- signals.hasNumeric = true;
216
- return;
217
- }
218
- if (containsCurrencySymbol(run.letter)) signals.hasCurrency = true;
219
- });
220
- return signals;
221
- }
222
- function classifySection(section) {
223
- const signals = collectSignals(section);
224
- if (signals.hasElapsed) return { kind: "elapsedTime" };
225
- if (signals.hasDate) return signals.hasTime ? { kind: "dateTime" } : { kind: "date" };
226
- if (signals.hasTime) return { kind: "time" };
227
- if (signals.hasPercent) return { kind: "percentage" };
228
- if (signals.hasCurrency) {
229
- const code = signals.currencyCode;
230
- return code === void 0 ? { kind: "currency" } : {
231
- kind: "currency",
232
- code
233
- };
234
- }
235
- if (signals.hasText && !signals.hasNumeric) return { kind: "text" };
236
- return PLAIN_NUMBER;
237
- }
238
- function classifyNumberFormat(formatCode) {
239
- const first = splitNumberFormatSections(tokenizeNumberFormat(formatCode))[0];
240
- return first === void 0 ? PLAIN_NUMBER : classifySection(first);
241
- }
242
- const BUILTIN_NUMBER_FORMATS = /* @__PURE__ */ new Map([
243
- [0, "General"],
244
- [1, "0"],
245
- [2, "0.00"],
246
- [3, "#,##0"],
247
- [4, "#,##0.00"],
248
- [5, "$#,##0_);($#,##0)"],
249
- [6, "$#,##0_);[Red]($#,##0)"],
250
- [7, "$#,##0.00_);($#,##0.00)"],
251
- [8, "$#,##0.00_);[Red]($#,##0.00)"],
252
- [9, "0%"],
253
- [10, "0.00%"],
254
- [11, "0.00E+00"],
255
- [12, "# ?/?"],
256
- [13, "# ??/??"],
257
- [14, "mm-dd-yy"],
258
- [15, "d-mmm-yy"],
259
- [16, "d-mmm"],
260
- [17, "mmm-yy"],
261
- [18, "h:mm AM/PM"],
262
- [19, "h:mm:ss AM/PM"],
263
- [20, "h:mm"],
264
- [21, "h:mm:ss"],
265
- [22, "m/d/yy h:mm"],
266
- [37, "#,##0 ;(#,##0)"],
267
- [38, "#,##0 ;[Red](#,##0)"],
268
- [39, "#,##0.00;(#,##0.00)"],
269
- [40, "#,##0.00;[Red](#,##0.00)"],
270
- [41, "_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)"],
271
- [42, "_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)"],
272
- [43, "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)"],
273
- [44, "_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)"],
274
- [45, "mm:ss"],
275
- [46, "[h]:mm:ss"],
276
- [47, "mmss.0"],
277
- [48, "##0.0E+0"],
278
- [49, "@"]
279
- ]);
280
3
  const PERCENTAGE_NUMBER_FORMAT = {
281
4
  kind: "builtin",
282
5
  id: 10
@@ -309,4 +32,4 @@ function currencyNumberFormat(code) {
309
32
  };
310
33
  }
311
34
  //#endregion
312
- export { AMOUNT_NUMBER_FORMAT, BOOLEAN_NUMBER_FORMAT, BUILTIN_NUMBER_FORMATS, DATE_NUMBER_FORMAT, DATE_TIME_NUMBER_FORMAT, MAX_NUMBER_FORMAT_SECTIONS, PERCENTAGE_NUMBER_FORMAT, TIME_NUMBER_FORMAT, classifyNumberFormat, currencyNumberFormat, splitNumberFormatSections, tokenizeNumberFormat };
35
+ export { AMOUNT_NUMBER_FORMAT, BOOLEAN_NUMBER_FORMAT, DATE_NUMBER_FORMAT, DATE_TIME_NUMBER_FORMAT, PERCENTAGE_NUMBER_FORMAT, TIME_NUMBER_FORMAT, currencyNumberFormat };
@@ -1,12 +1,12 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_typed_util = require("../util.cjs");
3
- const require_typed_xlsx_number_format = require("./number-format.cjs");
4
3
  let document_schema_js = require("document-schema.js");
4
+ let excel_number_format = require("excel-number-format");
5
5
  //#region src/typed/xlsx/styles.ts
6
6
  const STYLES_PATH = "xl/styles.xml";
7
7
  const GENERAL_NUM_FMT_ID = 0;
8
8
  function readNumberFormatCodesById(styleSheet) {
9
- const codes = new Map(require_typed_xlsx_number_format.BUILTIN_NUMBER_FORMATS);
9
+ const codes = new Map(excel_number_format.BUILTIN_NUMBER_FORMATS);
10
10
  const numFmtsEl = require_typed_util.childrenWithTag(styleSheet, "numFmts")[0];
11
11
  if (numFmtsEl === void 0) return codes;
12
12
  for (const numFmt of require_typed_util.childrenWithTag(numFmtsEl, "numFmt")) {
@@ -18,12 +18,6 @@ function readNumberFormatCodesById(styleSheet) {
18
18
  }
19
19
  return codes;
20
20
  }
21
- const BORDER_WIDTH_PT = {
22
- hair: .5,
23
- thin: .75,
24
- medium: 1.5,
25
- thick: 2.25
26
- };
27
21
  const XLSX_BORDER_STYLE = {
28
22
  thin: {
29
23
  weight: "thin",
@@ -78,11 +72,6 @@ const XLSX_BORDER_STYLE = {
78
72
  pattern: "dashed"
79
73
  }
80
74
  };
81
- const BORDER_WEIGHT_UPPER_PT = {
82
- hair: .625,
83
- thin: 1.125,
84
- medium: 1.875
85
- };
86
75
  function colorFromElement(colorEl) {
87
76
  if (colorEl === void 0) return;
88
77
  const raw = require_typed_util.attr(colorEl, "rgb");
@@ -119,7 +108,7 @@ function readBorderEdge(border, edge) {
119
108
  if (color === void 0) return;
120
109
  const result = {
121
110
  color,
122
- widthPt: BORDER_WIDTH_PT[resolved.weight]
111
+ widthPt: document_schema_js.BORDER_WIDTH_PT[resolved.weight]
123
112
  };
124
113
  if (resolved.pattern !== "solid") result.style = resolved.pattern;
125
114
  return result;
@@ -231,13 +220,9 @@ function borderToXlsxStyle(border) {
231
220
  switch (border.style) {
232
221
  case "double": return "double";
233
222
  case "dotted": return "dotted";
234
- case "dashed": return border.widthPt >= BORDER_WEIGHT_UPPER_PT.thin ? "mediumDashed" : "dashed";
223
+ case "dashed": return (0, document_schema_js.dashedBorderWeightForWidthPt)(border.widthPt) === "medium" ? "mediumDashed" : "dashed";
235
224
  case "solid":
236
- case void 0:
237
- if (border.widthPt < BORDER_WEIGHT_UPPER_PT.hair) return "hair";
238
- if (border.widthPt < BORDER_WEIGHT_UPPER_PT.thin) return "thin";
239
- if (border.widthPt < BORDER_WEIGHT_UPPER_PT.medium) return "medium";
240
- return "thick";
225
+ case void 0: return (0, document_schema_js.borderWeightForWidthPt)(border.widthPt);
241
226
  }
242
227
  }
243
228
  var CellFormatTable = class {
@@ -1,6 +1,6 @@
1
1
  import { attr, childrenWithTag, decodeEntities, rootElement } from "../util.js";
2
- import { BUILTIN_NUMBER_FORMATS } from "./number-format.js";
3
- import { colorToRgbHex, rgbHexToColor } from "document-schema.js";
2
+ import { BORDER_WIDTH_PT, borderWeightForWidthPt, colorToRgbHex, dashedBorderWeightForWidthPt, rgbHexToColor } from "document-schema.js";
3
+ import { BUILTIN_NUMBER_FORMATS } from "excel-number-format";
4
4
  //#region src/typed/xlsx/styles.ts
5
5
  const STYLES_PATH = "xl/styles.xml";
6
6
  const GENERAL_NUM_FMT_ID = 0;
@@ -17,12 +17,6 @@ function readNumberFormatCodesById(styleSheet) {
17
17
  }
18
18
  return codes;
19
19
  }
20
- const BORDER_WIDTH_PT = {
21
- hair: .5,
22
- thin: .75,
23
- medium: 1.5,
24
- thick: 2.25
25
- };
26
20
  const XLSX_BORDER_STYLE = {
27
21
  thin: {
28
22
  weight: "thin",
@@ -77,11 +71,6 @@ const XLSX_BORDER_STYLE = {
77
71
  pattern: "dashed"
78
72
  }
79
73
  };
80
- const BORDER_WEIGHT_UPPER_PT = {
81
- hair: .625,
82
- thin: 1.125,
83
- medium: 1.875
84
- };
85
74
  function colorFromElement(colorEl) {
86
75
  if (colorEl === void 0) return;
87
76
  const raw = attr(colorEl, "rgb");
@@ -230,13 +219,9 @@ function borderToXlsxStyle(border) {
230
219
  switch (border.style) {
231
220
  case "double": return "double";
232
221
  case "dotted": return "dotted";
233
- case "dashed": return border.widthPt >= BORDER_WEIGHT_UPPER_PT.thin ? "mediumDashed" : "dashed";
222
+ case "dashed": return dashedBorderWeightForWidthPt(border.widthPt) === "medium" ? "mediumDashed" : "dashed";
234
223
  case "solid":
235
- case void 0:
236
- if (border.widthPt < BORDER_WEIGHT_UPPER_PT.hair) return "hair";
237
- if (border.widthPt < BORDER_WEIGHT_UPPER_PT.thin) return "thin";
238
- if (border.widthPt < BORDER_WEIGHT_UPPER_PT.medium) return "medium";
239
- return "thick";
224
+ case void 0: return borderWeightForWidthPt(border.widthPt);
240
225
  }
241
226
  }
242
227
  var CellFormatTable = class {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ooxml.js",
3
- "version": "6.3.3",
3
+ "version": "6.3.4",
4
4
  "description": "Type-safe, lossless round-trip conversion between OOXML packages (docx, pptx, xlsx) and JSON, built on Zod 4 codecs.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -80,8 +80,9 @@
80
80
  "license": "MIT",
81
81
  "packageManager": "pnpm@11.6.0",
82
82
  "dependencies": {
83
- "archive-codec": "^1.3.0",
84
- "document-schema.js": "^5.5.0",
83
+ "archive-codec": "^1.4.0",
84
+ "document-schema.js": "^5.5.1",
85
+ "excel-number-format": "^1.0.0",
85
86
  "fast-xml-parser": "^5.10.1",
86
87
  "fflate": "^0.8.3",
87
88
  "zod": "^4.4.3"