@shbernal/ts-xlsx 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/README.md +5 -0
  2. package/dist/core/address.d.ts +49 -2
  3. package/dist/core/address.js +31 -3
  4. package/dist/core/autofilter.d.ts +2 -2
  5. package/dist/core/cell.d.ts +17 -16
  6. package/dist/core/cell.js +3 -7
  7. package/dist/core/color-resolution.d.ts +7 -7
  8. package/dist/core/column.d.ts +8 -9
  9. package/dist/core/column.js +2 -4
  10. package/dist/core/comment-thread.d.ts +32 -23
  11. package/dist/core/comment-thread.js +4 -4
  12. package/dist/core/conditional-formatting-overlay.d.ts +1 -1
  13. package/dist/core/conditional-formatting.d.ts +3 -3
  14. package/dist/core/data-validation-overlay.d.ts +1 -1
  15. package/dist/core/data-validation.d.ts +3 -3
  16. package/dist/core/date.d.ts +3 -3
  17. package/dist/core/formula.d.ts +6 -6
  18. package/dist/core/grid-edits.js +3 -3
  19. package/dist/core/image.d.ts +37 -2
  20. package/dist/core/image.js +6 -0
  21. package/dist/core/internal.d.ts +9 -1
  22. package/dist/core/limits.d.ts +4 -4
  23. package/dist/core/merge.d.ts +6 -12
  24. package/dist/core/merge.js +0 -3
  25. package/dist/core/page-setup.d.ts +4 -4
  26. package/dist/core/pivot-table.d.ts +2 -4
  27. package/dist/core/pivot-table.js +5 -5
  28. package/dist/core/preserved.d.ts +3 -3
  29. package/dist/core/protection.d.ts +4 -4
  30. package/dist/core/range.d.ts +16 -14
  31. package/dist/core/range.js +5 -5
  32. package/dist/core/row-input.d.ts +2 -8
  33. package/dist/core/row-input.js +2 -2
  34. package/dist/core/row.d.ts +7 -8
  35. package/dist/core/row.js +2 -4
  36. package/dist/core/style.d.ts +14 -14
  37. package/dist/core/table-style.d.ts +9 -9
  38. package/dist/core/table-style.js +1 -1
  39. package/dist/core/table.d.ts +30 -42
  40. package/dist/core/table.js +16 -10
  41. package/dist/core/theme.d.ts +13 -43
  42. package/dist/core/theme.js +2 -148
  43. package/dist/core/value.d.ts +7 -7
  44. package/dist/core/workbook-protection.d.ts +2 -2
  45. package/dist/core/workbook-styles.d.ts +26 -0
  46. package/dist/core/workbook-styles.js +48 -0
  47. package/dist/core/workbook-theme.d.ts +25 -0
  48. package/dist/core/workbook-theme.js +49 -0
  49. package/dist/core/workbook-vba.d.ts +17 -0
  50. package/dist/core/workbook-vba.js +79 -0
  51. package/dist/core/workbook.d.ts +141 -83
  52. package/dist/core/workbook.js +74 -133
  53. package/dist/core/worksheet-comments.d.ts +9 -0
  54. package/dist/core/worksheet-comments.js +52 -0
  55. package/dist/core/worksheet-model.d.ts +4 -4
  56. package/dist/core/worksheet-model.js +1 -0
  57. package/dist/core/worksheet-pictures.d.ts +29 -0
  58. package/dist/core/worksheet-pictures.js +42 -0
  59. package/dist/core/worksheet.d.ts +94 -77
  60. package/dist/core/worksheet.js +36 -95
  61. package/dist/customui/errors.d.ts +1 -1
  62. package/dist/customui/ribbon.d.ts +3 -3
  63. package/dist/entries/core.d.ts +4 -4
  64. package/dist/entries/core.js +1 -1
  65. package/dist/entries/vba.d.ts +1 -1
  66. package/dist/entries/vba.js +1 -1
  67. package/dist/entries/xlsx.d.ts +1 -0
  68. package/dist/entries/xlsx.js +1 -0
  69. package/dist/errors.d.ts +12 -12
  70. package/dist/io/csv/read.js +1 -2
  71. package/dist/io/csv/write.d.ts +8 -3
  72. package/dist/io/csv/write.js +17 -2
  73. package/dist/io/opc/errors.d.ts +6 -6
  74. package/dist/io/opc/inflate.d.ts +1 -1
  75. package/dist/io/opc/namespaces.d.ts +1 -1
  76. package/dist/io/opc/read-opc.d.ts +19 -3
  77. package/dist/io/opc/read-opc.js +14 -8
  78. package/dist/io/opc/read-options.d.ts +2 -2
  79. package/dist/io/opc/sniff-format.d.ts +2 -2
  80. package/dist/io/opc/zip-mtime.d.ts +5 -0
  81. package/dist/io/opc/zip-mtime.js +1 -0
  82. package/dist/io/style/xf-style.d.ts +38 -6
  83. package/dist/io/style/xf-style.js +22 -0
  84. package/dist/io/xlsb/errors.d.ts +1 -1
  85. package/dist/io/xlsb/formula.d.ts +4 -4
  86. package/dist/io/xlsb/primitives.d.ts +8 -8
  87. package/dist/io/xlsb/ptg-functions.d.ts +1 -1
  88. package/dist/io/xlsb/read-styles.js +2 -20
  89. package/dist/io/xlsb/read.d.ts +2 -2
  90. package/dist/io/xlsx/cell-accumulator.d.ts +25 -6
  91. package/dist/io/xlsx/cell-accumulator.js +111 -30
  92. package/dist/io/xlsx/cell-value.d.ts +2 -2
  93. package/dist/io/xlsx/cell-value.js +3 -3
  94. package/dist/io/xlsx/color-xml.js +11 -17
  95. package/dist/io/xlsx/comments.d.ts +5 -5
  96. package/dist/io/xlsx/comments.js +13 -6
  97. package/dist/io/xlsx/conditional-formatting.d.ts +3 -3
  98. package/dist/io/xlsx/conditional-formatting.js +7 -16
  99. package/dist/io/xlsx/data-validation.d.ts +2 -2
  100. package/dist/io/xlsx/data-validation.js +1 -1
  101. package/dist/io/xlsx/edit-vba.js +2 -1
  102. package/dist/io/xlsx/errors.d.ts +3 -3
  103. package/dist/io/xlsx/hyperlinks.d.ts +4 -2
  104. package/dist/io/xlsx/hyperlinks.js +5 -5
  105. package/dist/io/xlsx/images.d.ts +1 -1
  106. package/dist/io/xlsx/images.js +8 -8
  107. package/dist/io/xlsx/namespaces.d.ts +2 -2
  108. package/dist/io/xlsx/package-plan.js +5 -2
  109. package/dist/io/xlsx/read-pivot.js +2 -5
  110. package/dist/io/xlsx/read-rows.d.ts +13 -13
  111. package/dist/io/xlsx/read-rows.js +19 -55
  112. package/dist/io/xlsx/read-shared-strings.js +7 -5
  113. package/dist/io/xlsx/read-styles.d.ts +3 -3
  114. package/dist/io/xlsx/read-styles.js +40 -65
  115. package/dist/io/xlsx/read-worksheet.js +67 -115
  116. package/dist/io/xlsx/read.d.ts +3 -5
  117. package/dist/io/xlsx/read.js +94 -71
  118. package/dist/io/xlsx/rich-runs.d.ts +1 -1
  119. package/dist/io/xlsx/rich-runs.js +1 -1
  120. package/dist/io/xlsx/rich-text.d.ts +1 -1
  121. package/dist/io/xlsx/shared-strings.d.ts +2 -2
  122. package/dist/io/xlsx/sheet-properties.js +5 -4
  123. package/dist/io/xlsx/styles.d.ts +8 -9
  124. package/dist/io/xlsx/styles.js +4 -3
  125. package/dist/io/xlsx/tables.d.ts +2 -2
  126. package/dist/io/xlsx/tables.js +8 -13
  127. package/dist/io/xlsx/theme-xml.d.ts +37 -0
  128. package/dist/io/xlsx/theme-xml.js +142 -0
  129. package/dist/io/xlsx/threaded-comments.d.ts +18 -27
  130. package/dist/io/xlsx/threaded-comments.js +9 -21
  131. package/dist/io/xlsx/workbook-xml.d.ts +1 -1
  132. package/dist/io/xlsx/workbook-xml.js +6 -2
  133. package/dist/io/xlsx/worksheet-xml.d.ts +2 -2
  134. package/dist/io/xlsx/worksheet-xml.js +7 -12
  135. package/dist/io/xlsx/write-stream.d.ts +15 -15
  136. package/dist/io/xlsx/write-stream.js +5 -3
  137. package/dist/io/xlsx/write.d.ts +12 -7
  138. package/dist/io/xlsx/write.js +10 -6
  139. package/dist/io/xlsx/x14-ext.d.ts +1 -1
  140. package/dist/vba/bytes.d.ts +12 -0
  141. package/dist/vba/bytes.js +40 -0
  142. package/dist/vba/cfb-writer.d.ts +1 -1
  143. package/dist/vba/cfb.d.ts +1 -1
  144. package/dist/vba/cfb.js +15 -51
  145. package/dist/vba/codepage.d.ts +2 -2
  146. package/dist/vba/errors.d.ts +2 -2
  147. package/dist/vba/index.d.ts +2 -2
  148. package/dist/vba/index.js +2 -2
  149. package/dist/vba/ms-ovba.d.ts +1 -1
  150. package/dist/vba/ms-ovba.js +1 -3
  151. package/dist/vba/project-editor.d.ts +9 -9
  152. package/dist/vba/project-editor.js +2 -11
  153. package/dist/vba/project.d.ts +5 -5
  154. package/dist/vba/project.js +1 -10
  155. package/dist/vba/vba-encoding.d.ts +1 -1
  156. package/dist/xml/errors.d.ts +1 -1
  157. package/dist/xml/xml-read.d.ts +38 -9
  158. package/dist/xml/xml-read.js +23 -0
  159. package/dist/xml/xml.d.ts +31 -9
  160. package/dist/xml/xml.js +23 -3
  161. package/package.json +41 -35
package/dist/xml/xml.d.ts CHANGED
@@ -1,23 +1,45 @@
1
+ /**
2
+ * Refuse a string that XML cannot carry, naming the character and where it is so the author
3
+ * can find it in a value they never inspected. These arrive from a database column or a CSV
4
+ * field, not from a literal in the calling code.
5
+ *
6
+ * Exported for the one escape that cannot be {@link escapeAttr}: a number format code escapes
7
+ * everything but the apostrophe, and needs this guard just the same.
8
+ *
9
+ * @throws {AuthoringError} naming the code point and its offset.
10
+ */
11
+ export declare function assertRepresentable(value: string): void;
1
12
  /** Escape a string for use as XML element text. */
2
13
  export declare function escapeText(value: string): string;
3
14
  /** Escape a string for use inside a double-quoted XML attribute value. */
4
15
  export declare function escapeAttr(value: string): string;
5
16
  /**
6
- * Whether an element's text must be wrapped with `xml:space="preserve"` to survive a
7
- * round-trip. Leading/trailing whitespace is otherwise collapsed by consumers, so a
8
- * string cell value that begins or ends with a space needs the marker.
17
+ * Escape a cell value: the `_xHHHH_` convention first, then XML's own escapes.
18
+ *
19
+ * The order of the two replacements is load-bearing. Once `_xHHHH_` decodes to something, a
20
+ * value that legitimately reads `_x0041_` would come back as `A`, so the underscore is
21
+ * escaped first, and only where it begins a sequence that would otherwise decode, leaving
22
+ * every other underscore alone. Doing that after the character escape would re-escape the
23
+ * `_x005F_` it had just introduced.
24
+ *
25
+ * `escapeText` runs last and sees no unrepresentable character left, so its guard is a
26
+ * standing proof that the escape was complete rather than a second check of the same thing.
27
+ *
28
+ * Reversed by `decodeSpreadsheetText` in `./xml-read.ts`, whose single left-to-right pass is what
29
+ * makes the `_x005F_` step above reversible. Change either and read its comment first.
9
30
  */
10
- export declare function needsSpacePreserve(value: string): boolean;
31
+ export declare function escapeSpreadsheetText(value: string): string;
11
32
  /**
12
33
  * A `<t>` text element carrying an escaped string, marked `xml:space="preserve"` when its
13
- * whitespace would otherwise be collapsed. Shared by every string-bearing element a plain
14
- * inline string cell, a rich-text run so all decode identically on the way back.
34
+ * whitespace would otherwise be collapsed. Shared by every string-bearing element (a plain
35
+ * inline string cell, a rich-text run, a pooled string, a note's body) so all decode
36
+ * identically on the way back.
15
37
  */
16
38
  export declare function textElement(value: string): string;
17
39
  /**
18
40
  * Render a formula operand for serialisation: a number becomes its literal, a string is stripped of
19
41
  * the single optional leading '=' an author may write (OOXML stores the expression without it, e.g.
20
- * `=A1>0` on disk is `A1>0`). The result is unescaped the caller escapes it for its target,
42
+ * `=A1>0` on disk is `A1>0`). The result is unescaped: the caller escapes it for its target,
21
43
  * whether that is element text or an attribute value.
22
44
  */
23
45
  export declare function stripFormulaEquals(value: string | number): string;
@@ -25,12 +47,12 @@ export declare function stripFormulaEquals(value: string | number): string;
25
47
  * A boolean attribute rendered with a leading space (` name="1"` / ` name="0"`), or '' when the value
26
48
  * is undefined. OOXML booleans serialise as 1/0; emitting the explicit `="0"` lets a writer force a
27
49
  * flag off against a consumer's default, while an unset (undefined) flag stays out of the element
28
- * entirely the two-state-plus-absent contract every flag writer here shares.
50
+ * entirely: the two-state-plus-absent contract every flag writer here shares.
29
51
  */
30
52
  export declare function boolAttr(name: string, value: boolean | undefined): string;
31
53
  /**
32
54
  * A numeric attribute rendered with a leading space (` name="42"`), or '' when the value is undefined
33
- * so a count an author never set stays out of the element rather than fabricating a default.
55
+ * so that a count an author never set stays out of the element rather than fabricating a default.
34
56
  */
35
57
  export declare function attr(name: string, value: number | undefined): string;
36
58
  /**
package/dist/xml/xml.js CHANGED
@@ -14,18 +14,38 @@ const ATTR_ESCAPES = {
14
14
  '\r': '&#13;',
15
15
  '\t': '&#9;',
16
16
  };
17
+ const UNREPRESENTABLE = /[\u{0}-\u{8}\u{B}\u{C}\u{E}-\u{1F}\u{FFFE}\u{FFFF}\u{D800}-\u{DFFF}]/u;
18
+ const UNREPRESENTABLE_GLOBAL = new RegExp(UNREPRESENTABLE.source, 'gu');
19
+ function codePointHex(codePoint) {
20
+ return codePoint.toString(16).toUpperCase().padStart(4, '0');
21
+ }
22
+ export function assertRepresentable(value) {
23
+ const found = UNREPRESENTABLE.exec(value);
24
+ if (found === null)
25
+ return;
26
+ throw new AuthoringError(`cannot write U+${codePointHex(value.codePointAt(found.index))} at offset ${found.index}: ` +
27
+ 'XML 1.0 has no representation for it, and the _xHHHH_ escape that would carry it is a ' +
28
+ 'convention of cell values only');
29
+ }
17
30
  export function escapeText(value) {
31
+ assertRepresentable(value);
18
32
  return value.replace(/[&<>]/g, (ch) => TEXT_ESCAPES[ch]);
19
33
  }
20
34
  export function escapeAttr(value) {
35
+ assertRepresentable(value);
21
36
  return value.replace(/[&<>"'\n\r\t]/g, (ch) => ATTR_ESCAPES[ch]);
22
37
  }
23
- export function needsSpacePreserve(value) {
38
+ export function escapeSpreadsheetText(value) {
39
+ return escapeText(value
40
+ .replace(/_(x[0-9A-Fa-f]{4}_)/g, '_x005F_$1')
41
+ .replace(UNREPRESENTABLE_GLOBAL, (ch) => `_x${codePointHex(ch.codePointAt(0))}_`));
42
+ }
43
+ function needsSpacePreserve(value) {
24
44
  return value.length > 0 && (value !== value.trim() || /[\n\r\t]/.test(value));
25
45
  }
26
46
  export function textElement(value) {
27
47
  const space = needsSpacePreserve(value) ? ' xml:space="preserve"' : '';
28
- return `<t${space}>${escapeText(value)}</t>`;
48
+ return `<t${space}>${escapeSpreadsheetText(value)}</t>`;
29
49
  }
30
50
  export function stripFormulaEquals(value) {
31
51
  if (typeof value === 'number')
@@ -40,7 +60,7 @@ export function attr(name, value) {
40
60
  }
41
61
  export function numberText(value) {
42
62
  if (!Number.isFinite(value)) {
43
- throw new AuthoringError(`cannot write a non-finite number (${value}) it has no OOXML representation`);
63
+ throw new AuthoringError(`cannot write a non-finite number (${value}): it has no OOXML representation`);
44
64
  }
45
65
  return String(value);
46
66
  }
package/package.json CHANGED
@@ -1,23 +1,37 @@
1
1
  {
2
2
  "name": "@shbernal/ts-xlsx",
3
- "version": "1.2.0",
3
+ "version": "2.0.0",
4
4
  "description": "A TypeScript-first library for reading and writing xlsx (OOXML) spreadsheets.",
5
+ "keywords": [
6
+ "csv",
7
+ "excel",
8
+ "ooxml",
9
+ "spreadsheet",
10
+ "streaming",
11
+ "typescript",
12
+ "workbook",
13
+ "xlsx"
14
+ ],
15
+ "homepage": "https://github.com/shbernal/ts-xlsx#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/shbernal/ts-xlsx/issues"
18
+ },
5
19
  "license": "MIT",
6
20
  "author": "shbernal",
7
- "type": "module",
8
21
  "repository": {
9
22
  "type": "git",
10
23
  "url": "https://github.com/shbernal/ts-xlsx.git"
11
24
  },
12
- "homepage": "https://github.com/shbernal/ts-xlsx#readme",
13
- "bugs": {
14
- "url": "https://github.com/shbernal/ts-xlsx/issues"
15
- },
16
- "engines": {
17
- "node": ">=24"
18
- },
19
- "packageManager": "pnpm@11.11.0",
25
+ "files": [
26
+ "dist",
27
+ "skills",
28
+ "LICENSE",
29
+ "README.md"
30
+ ],
31
+ "type": "module",
20
32
  "sideEffects": false,
33
+ "main": "./dist/index.js",
34
+ "types": "./dist/index.d.ts",
21
35
  "exports": {
22
36
  ".": {
23
37
  "types": "./dist/index.d.ts",
@@ -53,17 +67,9 @@
53
67
  },
54
68
  "./package.json": "./package.json"
55
69
  },
56
- "main": "./dist/index.js",
57
- "types": "./dist/index.d.ts",
58
70
  "publishConfig": {
59
71
  "access": "public"
60
72
  },
61
- "files": [
62
- "dist",
63
- "skills",
64
- "LICENSE",
65
- "README.md"
66
- ],
67
73
  "scripts": {
68
74
  "prepare": "node scripts/install-hooks.ts",
69
75
  "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
@@ -76,42 +82,42 @@
76
82
  "layering:check": "node scripts/check-layering.ts",
77
83
  "entries:check": "node scripts/check-entries.ts",
78
84
  "source-text:check": "node scripts/check-source-text.ts",
79
- "lint": "biome check --error-on-warnings src scripts test tools",
80
- "lint:fix": "biome check --write --error-on-warnings src scripts test tools",
81
- "format": "biome format --write src scripts test tools",
85
+ "chars:check": "charcheck",
86
+ "lint": "node node_modules/oxlint/bin/oxlint src scripts test tools charcheck.config.ts --type-aware --deny-warnings --report-unused-disable-directives",
87
+ "lint:fix": "pnpm run lint --fix",
88
+ "format": "node scripts/format.ts --write",
89
+ "format:check": "node scripts/format.ts --check",
82
90
  "typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.test.json",
83
91
  "typecheck:src": "tsc --noEmit -p tsconfig.json",
84
92
  "typecheck:test": "tsc --noEmit -p tsconfig.test.json",
85
93
  "typecheck:dist": "tsc --noEmit -p tsconfig.dist.json",
86
94
  "test:src": "node --test \"src/**/*.test.ts\"",
87
- "test:coverage": "node --test --experimental-test-coverage \"src/**/*.test.ts\"",
95
+ "coverage": "node scripts/coverage.ts",
88
96
  "corpus": "node test/corpus/run.ts",
89
97
  "corpus:dist": "node test/corpus/run.ts --target dist",
90
98
  "verify": "node scripts/verify.ts --full",
91
99
  "verify:quick": "node scripts/verify.ts --quick",
92
100
  "test": "node scripts/verify.ts --full",
93
101
  "prepublishOnly": "pnpm run build && pnpm run test && pnpm run smoke:dist && pnpm run size",
94
- "validate:ooxml": "node scripts/ooxml-validator.ts",
102
+ "validate:ooxml": "ooxml-validate",
95
103
  "test:ooxml": "node test/ooxml-validation/run.ts"
96
104
  },
97
- "keywords": [
98
- "xlsx",
99
- "ooxml",
100
- "excel",
101
- "spreadsheet",
102
- "csv",
103
- "typescript",
104
- "workbook",
105
- "streaming"
106
- ],
107
105
  "dependencies": {
108
106
  "fflate": "^0.8.3"
109
107
  },
110
108
  "devDependencies": {
111
- "@biomejs/biome": "2.5.7",
112
109
  "@types/node": "^24.13.3",
110
+ "charcheck": "^0.3.0",
113
111
  "jszip": "^3.10.1",
114
112
  "lefthook": "^2.1.10",
113
+ "ooxml-validate": "^0.0.3",
114
+ "oxfmt": "^0.64.0",
115
+ "oxlint": "^1.80.0",
116
+ "oxlint-tsgolint": "7.0.2001",
115
117
  "typescript": "^7.0.2"
116
- }
118
+ },
119
+ "engines": {
120
+ "node": ">=24"
121
+ },
122
+ "packageManager": "pnpm@11.11.0"
117
123
  }