@js-ak/excel-toolbox 1.8.3 → 1.9.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 (207) hide show
  1. package/build/cjs/lib/template/template-fs.js +2 -1
  2. package/build/cjs/lib/template/template-memory.js +2 -1
  3. package/build/cjs/lib/template/utils/column-letter-to-index.js +15 -0
  4. package/build/cjs/lib/template/utils/index.js +1 -1
  5. package/build/cjs/lib/template/utils/prepare-row-to-cells.js +2 -2
  6. package/build/cjs/lib/template/utils/validate-worksheet-xml.js +19 -9
  7. package/build/cjs/lib/utils/index.js +2 -0
  8. package/build/cjs/lib/utils/trim-and-join-multiline.js +32 -0
  9. package/build/cjs/lib/workbook-builder/default/border.js +18 -0
  10. package/build/cjs/lib/workbook-builder/default/cell-xf.js +15 -0
  11. package/build/cjs/lib/workbook-builder/default/fill.js +18 -0
  12. package/build/cjs/lib/workbook-builder/default/font.js +19 -0
  13. package/build/cjs/lib/workbook-builder/default/index.js +21 -0
  14. package/build/cjs/lib/workbook-builder/default/sheet-name.js +10 -0
  15. package/build/cjs/lib/workbook-builder/index.js +18 -0
  16. package/build/cjs/lib/workbook-builder/merge-cells/add.js +72 -0
  17. package/build/cjs/lib/workbook-builder/merge-cells/helpers/index.js +18 -0
  18. package/build/cjs/lib/workbook-builder/merge-cells/helpers/ranges-equal.js +17 -0
  19. package/build/cjs/lib/workbook-builder/merge-cells/helpers/ranges-intersect.js +17 -0
  20. package/build/cjs/lib/workbook-builder/merge-cells/index.js +18 -0
  21. package/build/cjs/lib/workbook-builder/merge-cells/remove.js +60 -0
  22. package/build/cjs/lib/workbook-builder/shared-string-ref/add.js +24 -0
  23. package/build/cjs/lib/workbook-builder/shared-string-ref/index.js +19 -0
  24. package/build/cjs/lib/workbook-builder/shared-string-ref/remove-all-from-sheet.js +66 -0
  25. package/build/cjs/lib/workbook-builder/shared-string-ref/remove.js +66 -0
  26. package/build/cjs/lib/workbook-builder/style-ref/add-or-get.js +94 -0
  27. package/build/cjs/lib/workbook-builder/style-ref/helpers/add-num-fmt.js +25 -0
  28. package/build/cjs/lib/workbook-builder/style-ref/helpers/border-to-xml.js +49 -0
  29. package/build/cjs/lib/workbook-builder/style-ref/helpers/fill-to-xml.js +51 -0
  30. package/build/cjs/lib/workbook-builder/style-ref/helpers/font-to-xml.js +112 -0
  31. package/build/cjs/lib/workbook-builder/style-ref/helpers/index.js +21 -0
  32. package/build/cjs/lib/workbook-builder/style-ref/helpers/reindex-style-map-after-removal.js +30 -0
  33. package/build/cjs/lib/workbook-builder/style-ref/index.js +19 -0
  34. package/build/cjs/lib/workbook-builder/style-ref/remove-all-from-sheet.js +26 -0
  35. package/build/cjs/lib/workbook-builder/style-ref/remove.js +52 -0
  36. package/build/cjs/lib/workbook-builder/types/app-xml-options.js +2 -0
  37. package/build/cjs/lib/workbook-builder/types/border-style.js +2 -0
  38. package/build/cjs/lib/workbook-builder/types/cell-data.js +2 -0
  39. package/build/cjs/lib/workbook-builder/types/cell-style.js +2 -0
  40. package/build/cjs/lib/workbook-builder/types/cell-type.js +2 -0
  41. package/build/cjs/lib/workbook-builder/types/cell-value.js +2 -0
  42. package/build/cjs/lib/workbook-builder/types/cell-xf.js +2 -0
  43. package/build/cjs/lib/workbook-builder/types/index.js +27 -0
  44. package/build/cjs/lib/workbook-builder/types/merge-cell.js +2 -0
  45. package/build/cjs/lib/workbook-builder/types/row-data.js +2 -0
  46. package/build/cjs/lib/workbook-builder/types/sheet-data.js +2 -0
  47. package/build/cjs/lib/workbook-builder/types/xml-node.js +2 -0
  48. package/build/cjs/lib/workbook-builder/utils/build-app-xml.js +51 -0
  49. package/build/cjs/lib/workbook-builder/utils/build-cell-children.js +59 -0
  50. package/build/cjs/lib/workbook-builder/utils/build-content-types-xml.js +42 -0
  51. package/build/cjs/lib/workbook-builder/utils/build-core-xml.js +27 -0
  52. package/build/cjs/lib/workbook-builder/utils/build-rels-xml.js +19 -0
  53. package/build/cjs/lib/workbook-builder/utils/build-shared-strings-xml.js +39 -0
  54. package/build/cjs/lib/workbook-builder/utils/build-styles-xml.js +178 -0
  55. package/build/cjs/lib/workbook-builder/utils/build-theme-xml.js +609 -0
  56. package/build/cjs/lib/workbook-builder/utils/build-workbook-rels-xml.js +58 -0
  57. package/build/cjs/lib/workbook-builder/utils/build-workbook-xml.js +26 -0
  58. package/build/cjs/lib/workbook-builder/utils/build-worksheet-xml.js +66 -0
  59. package/build/cjs/lib/workbook-builder/utils/build-xml.js +72 -0
  60. package/build/cjs/lib/workbook-builder/utils/constants.js +55 -0
  61. package/build/cjs/lib/workbook-builder/utils/date-to-excel-serial.js +16 -0
  62. package/build/cjs/lib/workbook-builder/utils/index.js +34 -0
  63. package/build/cjs/lib/workbook-builder/utils/initialize-files.js +40 -0
  64. package/build/cjs/lib/workbook-builder/utils/sheet.js +144 -0
  65. package/build/cjs/lib/workbook-builder/utils/write-shared-strings-xml.js +49 -0
  66. package/build/cjs/lib/workbook-builder/utils/write-styles-xml.js +196 -0
  67. package/build/cjs/lib/workbook-builder/utils/write-worksheet-xml.js +209 -0
  68. package/build/cjs/lib/workbook-builder/utils/write-xml.js +37 -0
  69. package/build/cjs/lib/workbook-builder/workbook-builder.js +414 -0
  70. package/build/esm/lib/template/template-fs.js +2 -1
  71. package/build/esm/lib/template/template-memory.js +2 -1
  72. package/build/esm/lib/template/utils/column-letter-to-index.js +12 -0
  73. package/build/esm/lib/template/utils/index.js +1 -1
  74. package/build/esm/lib/template/utils/prepare-row-to-cells.js +1 -1
  75. package/build/esm/lib/template/utils/validate-worksheet-xml.js +19 -9
  76. package/build/esm/lib/utils/index.js +2 -0
  77. package/build/esm/lib/utils/trim-and-join-multiline.js +29 -0
  78. package/build/esm/lib/workbook-builder/default/border.js +14 -0
  79. package/build/esm/lib/workbook-builder/default/cell-xf.js +11 -0
  80. package/build/esm/lib/workbook-builder/default/fill.js +14 -0
  81. package/build/esm/lib/workbook-builder/default/font.js +15 -0
  82. package/build/esm/lib/workbook-builder/default/index.js +5 -0
  83. package/build/esm/lib/workbook-builder/default/sheet-name.js +6 -0
  84. package/build/esm/lib/workbook-builder/index.js +2 -0
  85. package/build/esm/lib/workbook-builder/merge-cells/add.js +36 -0
  86. package/build/esm/lib/workbook-builder/merge-cells/helpers/index.js +2 -0
  87. package/build/esm/lib/workbook-builder/merge-cells/helpers/ranges-equal.js +14 -0
  88. package/build/esm/lib/workbook-builder/merge-cells/helpers/ranges-intersect.js +14 -0
  89. package/build/esm/lib/workbook-builder/merge-cells/index.js +2 -0
  90. package/build/esm/lib/workbook-builder/merge-cells/remove.js +24 -0
  91. package/build/esm/lib/workbook-builder/shared-string-ref/add.js +21 -0
  92. package/build/esm/lib/workbook-builder/shared-string-ref/index.js +3 -0
  93. package/build/esm/lib/workbook-builder/shared-string-ref/remove-all-from-sheet.js +63 -0
  94. package/build/esm/lib/workbook-builder/shared-string-ref/remove.js +63 -0
  95. package/build/esm/lib/workbook-builder/style-ref/add-or-get.js +58 -0
  96. package/build/esm/lib/workbook-builder/style-ref/helpers/add-num-fmt.js +21 -0
  97. package/build/esm/lib/workbook-builder/style-ref/helpers/border-to-xml.js +45 -0
  98. package/build/esm/lib/workbook-builder/style-ref/helpers/fill-to-xml.js +47 -0
  99. package/build/esm/lib/workbook-builder/style-ref/helpers/font-to-xml.js +75 -0
  100. package/build/esm/lib/workbook-builder/style-ref/helpers/index.js +5 -0
  101. package/build/esm/lib/workbook-builder/style-ref/helpers/reindex-style-map-after-removal.js +26 -0
  102. package/build/esm/lib/workbook-builder/style-ref/index.js +3 -0
  103. package/build/esm/lib/workbook-builder/style-ref/remove-all-from-sheet.js +23 -0
  104. package/build/esm/lib/workbook-builder/style-ref/remove.js +49 -0
  105. package/build/esm/lib/workbook-builder/types/app-xml-options.js +1 -0
  106. package/build/esm/lib/workbook-builder/types/border-style.js +1 -0
  107. package/build/esm/lib/workbook-builder/types/cell-data.js +1 -0
  108. package/build/esm/lib/workbook-builder/types/cell-style.js +1 -0
  109. package/build/esm/lib/workbook-builder/types/cell-type.js +1 -0
  110. package/build/esm/lib/workbook-builder/types/cell-value.js +1 -0
  111. package/build/esm/lib/workbook-builder/types/cell-xf.js +1 -0
  112. package/build/esm/lib/workbook-builder/types/index.js +11 -0
  113. package/build/esm/lib/workbook-builder/types/merge-cell.js +1 -0
  114. package/build/esm/lib/workbook-builder/types/row-data.js +1 -0
  115. package/build/esm/lib/workbook-builder/types/sheet-data.js +1 -0
  116. package/build/esm/lib/workbook-builder/types/xml-node.js +1 -0
  117. package/build/esm/lib/workbook-builder/utils/build-app-xml.js +48 -0
  118. package/build/esm/lib/workbook-builder/utils/build-cell-children.js +56 -0
  119. package/build/esm/lib/workbook-builder/utils/build-content-types-xml.js +39 -0
  120. package/build/esm/lib/workbook-builder/utils/build-core-xml.js +24 -0
  121. package/build/esm/lib/workbook-builder/utils/build-rels-xml.js +16 -0
  122. package/build/esm/lib/workbook-builder/utils/build-shared-strings-xml.js +36 -0
  123. package/build/esm/lib/workbook-builder/utils/build-styles-xml.js +142 -0
  124. package/build/esm/lib/workbook-builder/utils/build-theme-xml.js +606 -0
  125. package/build/esm/lib/workbook-builder/utils/build-workbook-rels-xml.js +55 -0
  126. package/build/esm/lib/workbook-builder/utils/build-workbook-xml.js +23 -0
  127. package/build/esm/lib/workbook-builder/utils/build-worksheet-xml.js +63 -0
  128. package/build/esm/lib/workbook-builder/utils/build-xml.js +69 -0
  129. package/build/esm/lib/workbook-builder/utils/constants.js +52 -0
  130. package/build/esm/lib/workbook-builder/utils/date-to-excel-serial.js +13 -0
  131. package/build/esm/lib/workbook-builder/utils/index.js +18 -0
  132. package/build/esm/lib/workbook-builder/utils/initialize-files.js +36 -0
  133. package/build/esm/lib/workbook-builder/utils/sheet.js +141 -0
  134. package/build/esm/lib/workbook-builder/utils/write-shared-strings-xml.js +43 -0
  135. package/build/esm/lib/workbook-builder/utils/write-styles-xml.js +157 -0
  136. package/build/esm/lib/workbook-builder/utils/write-worksheet-xml.js +203 -0
  137. package/build/esm/lib/workbook-builder/utils/write-xml.js +34 -0
  138. package/build/esm/lib/workbook-builder/workbook-builder.js +374 -0
  139. package/build/types/lib/template/utils/column-letter-to-index.d.ts +1 -0
  140. package/build/types/lib/template/utils/index.d.ts +1 -1
  141. package/build/types/lib/utils/index.d.ts +2 -0
  142. package/build/types/lib/utils/trim-and-join-multiline.d.ts +23 -0
  143. package/build/types/lib/workbook-builder/default/border.d.ts +7 -0
  144. package/build/types/lib/workbook-builder/default/cell-xf.d.ts +7 -0
  145. package/build/types/lib/workbook-builder/default/fill.d.ts +7 -0
  146. package/build/types/lib/workbook-builder/default/font.d.ts +21 -0
  147. package/build/types/lib/workbook-builder/default/index.d.ts +5 -0
  148. package/build/types/lib/workbook-builder/default/sheet-name.d.ts +6 -0
  149. package/build/types/lib/workbook-builder/index.d.ts +2 -0
  150. package/build/types/lib/workbook-builder/merge-cells/add.d.ts +15 -0
  151. package/build/types/lib/workbook-builder/merge-cells/helpers/index.d.ts +2 -0
  152. package/build/types/lib/workbook-builder/merge-cells/helpers/ranges-equal.d.ts +10 -0
  153. package/build/types/lib/workbook-builder/merge-cells/helpers/ranges-intersect.d.ts +10 -0
  154. package/build/types/lib/workbook-builder/merge-cells/index.d.ts +2 -0
  155. package/build/types/lib/workbook-builder/merge-cells/remove.d.ts +15 -0
  156. package/build/types/lib/workbook-builder/shared-string-ref/add.d.ts +13 -0
  157. package/build/types/lib/workbook-builder/shared-string-ref/index.d.ts +3 -0
  158. package/build/types/lib/workbook-builder/shared-string-ref/remove-all-from-sheet.d.ts +10 -0
  159. package/build/types/lib/workbook-builder/shared-string-ref/remove.d.ts +13 -0
  160. package/build/types/lib/workbook-builder/style-ref/add-or-get.d.ts +16 -0
  161. package/build/types/lib/workbook-builder/style-ref/helpers/add-num-fmt.d.ts +17 -0
  162. package/build/types/lib/workbook-builder/style-ref/helpers/border-to-xml.d.ts +16 -0
  163. package/build/types/lib/workbook-builder/style-ref/helpers/fill-to-xml.d.ts +17 -0
  164. package/build/types/lib/workbook-builder/style-ref/helpers/font-to-xml.d.ts +18 -0
  165. package/build/types/lib/workbook-builder/style-ref/helpers/index.d.ts +5 -0
  166. package/build/types/lib/workbook-builder/style-ref/helpers/reindex-style-map-after-removal.d.ts +15 -0
  167. package/build/types/lib/workbook-builder/style-ref/index.d.ts +3 -0
  168. package/build/types/lib/workbook-builder/style-ref/remove-all-from-sheet.d.ts +4 -0
  169. package/build/types/lib/workbook-builder/style-ref/remove.d.ts +18 -0
  170. package/build/types/lib/workbook-builder/types/app-xml-options.d.ts +9 -0
  171. package/build/types/lib/workbook-builder/types/border-style.d.ts +5 -0
  172. package/build/types/lib/workbook-builder/types/cell-data.d.ts +10 -0
  173. package/build/types/lib/workbook-builder/types/cell-style.d.ts +32 -0
  174. package/build/types/lib/workbook-builder/types/cell-type.d.ts +11 -0
  175. package/build/types/lib/workbook-builder/types/cell-value.d.ts +2 -0
  176. package/build/types/lib/workbook-builder/types/cell-xf.d.ts +13 -0
  177. package/build/types/lib/workbook-builder/types/index.d.ts +11 -0
  178. package/build/types/lib/workbook-builder/types/merge-cell.d.ts +6 -0
  179. package/build/types/lib/workbook-builder/types/row-data.d.ts +5 -0
  180. package/build/types/lib/workbook-builder/types/sheet-data.d.ts +13 -0
  181. package/build/types/lib/workbook-builder/types/xml-node.d.ts +11 -0
  182. package/build/types/lib/workbook-builder/utils/build-app-xml.d.ts +2 -0
  183. package/build/types/lib/workbook-builder/utils/build-cell-children.d.ts +9 -0
  184. package/build/types/lib/workbook-builder/utils/build-content-types-xml.d.ts +1 -0
  185. package/build/types/lib/workbook-builder/utils/build-core-xml.d.ts +1 -0
  186. package/build/types/lib/workbook-builder/utils/build-rels-xml.d.ts +1 -0
  187. package/build/types/lib/workbook-builder/utils/build-shared-strings-xml.d.ts +10 -0
  188. package/build/types/lib/workbook-builder/utils/build-styles-xml.d.ts +23 -0
  189. package/build/types/lib/workbook-builder/utils/build-theme-xml.d.ts +1 -0
  190. package/build/types/lib/workbook-builder/utils/build-workbook-rels-xml.d.ts +9 -0
  191. package/build/types/lib/workbook-builder/utils/build-workbook-xml.d.ts +3 -0
  192. package/build/types/lib/workbook-builder/utils/build-worksheet-xml.d.ts +2 -0
  193. package/build/types/lib/workbook-builder/utils/build-xml.d.ts +50 -0
  194. package/build/types/lib/workbook-builder/utils/constants.d.ts +47 -0
  195. package/build/types/lib/workbook-builder/utils/date-to-excel-serial.d.ts +9 -0
  196. package/build/types/lib/workbook-builder/utils/index.d.ts +18 -0
  197. package/build/types/lib/workbook-builder/utils/initialize-files.d.ts +13 -0
  198. package/build/types/lib/workbook-builder/utils/sheet.d.ts +21 -0
  199. package/build/types/lib/workbook-builder/utils/write-shared-strings-xml.d.ts +11 -0
  200. package/build/types/lib/workbook-builder/utils/write-styles-xml.d.ts +24 -0
  201. package/build/types/lib/workbook-builder/utils/write-worksheet-xml.d.ts +14 -0
  202. package/build/types/lib/workbook-builder/utils/write-xml.d.ts +3 -0
  203. package/build/types/lib/workbook-builder/workbook-builder.d.ts +110 -0
  204. package/package.json +1 -1
  205. /package/build/cjs/lib/{template/utils → utils}/escape-xml.js +0 -0
  206. /package/build/esm/lib/{template/utils → utils}/escape-xml.js +0 -0
  207. /package/build/types/lib/{template/utils → utils}/escape-xml.d.ts +0 -0
@@ -0,0 +1,55 @@
1
+ import { RELATIONSHIP_TYPES, XML_DECLARATION, XML_NAMESPACES } from "./constants.js";
2
+ import { buildXml } from "./build-xml.js";
3
+ /**
4
+ * Builds the `_rels/workbook.xml.rels` content for the given number of sheets.
5
+ *
6
+ * Relationships are created for each worksheet and then for styles, theme, and shared strings.
7
+ *
8
+ * @param sheetsCount - Number of worksheets in the workbook
9
+ * @returns XML string for the workbook relationships part
10
+ */
11
+ export function buildWorkbookRels(sheetsCount) {
12
+ // Create relationships for each worksheet
13
+ const sheetRels = Array.from({ length: sheetsCount }, (_, i) => ({
14
+ attrs: {
15
+ Id: `rId${i + 1}`,
16
+ Target: `worksheets/sheet${i + 1}.xml`,
17
+ Type: RELATIONSHIP_TYPES.WORKSHEET,
18
+ },
19
+ tag: "Relationship",
20
+ }));
21
+ // Ids for styles, theme, and sharedStrings follow after the worksheets
22
+ const stylesRel = {
23
+ attrs: {
24
+ Id: `rId${sheetsCount + 1}`,
25
+ Target: "styles.xml",
26
+ Type: RELATIONSHIP_TYPES.STYLES,
27
+ },
28
+ tag: "Relationship",
29
+ };
30
+ const themeRel = {
31
+ attrs: {
32
+ Id: `rId${sheetsCount + 2}`,
33
+ Target: "theme/theme1.xml",
34
+ Type: RELATIONSHIP_TYPES.THEME,
35
+ },
36
+ tag: "Relationship",
37
+ };
38
+ const sharedStringsRel = {
39
+ attrs: {
40
+ Id: `rId${sheetsCount + 3}`,
41
+ Target: "sharedStrings.xml",
42
+ Type: RELATIONSHIP_TYPES.SHARED_STRINGS,
43
+ },
44
+ tag: "Relationship",
45
+ };
46
+ const allRels = [...sheetRels, stylesRel, themeRel, sharedStringsRel];
47
+ return [
48
+ XML_DECLARATION,
49
+ buildXml({
50
+ attrs: { xmlns: XML_NAMESPACES.PACKAGE_RELATIONSHIPS },
51
+ children: allRels,
52
+ tag: "Relationships",
53
+ }),
54
+ ].join("\n");
55
+ }
@@ -0,0 +1,23 @@
1
+ import { XML_DECLARATION, XML_NAMESPACES } from "./constants.js";
2
+ import { buildXml } from "./build-xml.js";
3
+ export function buildWorkbookXml(sheets) {
4
+ return [
5
+ XML_DECLARATION,
6
+ buildXml({
7
+ attrs: {
8
+ xmlns: XML_NAMESPACES.SPREADSHEET_ML,
9
+ "xmlns:r": XML_NAMESPACES.OFFICE_DOCUMENT,
10
+ },
11
+ children: [
12
+ {
13
+ children: sheets.map((sheet, i) => ({
14
+ attrs: { name: sheet.name, "r:id": `rId${i + 1}`, sheetId: (i + 1).toString() },
15
+ tag: "sheet",
16
+ })),
17
+ tag: "sheets",
18
+ },
19
+ ],
20
+ tag: "workbook",
21
+ }),
22
+ ].join("\n");
23
+ }
@@ -0,0 +1,63 @@
1
+ import { XML_DECLARATION, XML_NAMESPACES } from "./constants.js";
2
+ import { buildCellChildren } from "./build-cell-children.js";
3
+ import { buildXml } from "./build-xml.js";
4
+ export function buildWorksheetXml(rows = new Map(), merges = []) {
5
+ const typeSetSkipping = new Set(["n"]);
6
+ const children = [
7
+ {
8
+ attrs: { ref: "A1:A1" },
9
+ tag: "dimension",
10
+ },
11
+ {
12
+ children: [{ attrs: { workbookViewId: "0" }, tag: "sheetView" }],
13
+ tag: "sheetViews",
14
+ },
15
+ {
16
+ attrs: { defaultRowHeight: "15" },
17
+ tag: "sheetFormatPr",
18
+ },
19
+ {
20
+ children: Array.from(rows.entries()).map(([rowNumber, row]) => ({
21
+ attrs: { r: rowNumber.toString() },
22
+ children: Array.from(row.cells.entries()).map(([colNumber, cell]) => {
23
+ const cellRef = `${colNumber}${rowNumber}`;
24
+ const attrT = (cell.type && typeSetSkipping.has(cell.type))
25
+ ? undefined
26
+ : cell.type;
27
+ return {
28
+ attrs: {
29
+ r: cellRef,
30
+ s: cell.style?.index,
31
+ t: attrT,
32
+ },
33
+ children: buildCellChildren(cell),
34
+ tag: "c",
35
+ };
36
+ }),
37
+ tag: "row",
38
+ })),
39
+ tag: "sheetData",
40
+ },
41
+ ];
42
+ if (merges.length > 0) {
43
+ children.push({
44
+ attrs: { count: merges.length.toString() },
45
+ children: merges.map((ref) => ({
46
+ attrs: { ref },
47
+ tag: "mergeCell",
48
+ })),
49
+ tag: "mergeCells",
50
+ });
51
+ }
52
+ return [
53
+ XML_DECLARATION,
54
+ buildXml({
55
+ attrs: {
56
+ xmlns: XML_NAMESPACES.SPREADSHEET_ML,
57
+ "xmlns:r": XML_NAMESPACES.OFFICE_DOCUMENT,
58
+ },
59
+ children,
60
+ tag: "worksheet",
61
+ }),
62
+ ].join("\n");
63
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Builds XML string from an XmlNode structure.
3
+ *
4
+ * @param node - The XML node to convert to string
5
+ * @param level - The indentation level for formatting (default: 0)
6
+ *
7
+ * @returns The formatted XML string
8
+ */
9
+ export function buildXml(node, level = 0) {
10
+ const { attrs = {}, children = [], tag } = node;
11
+ const attrStr = Object.entries(attrs)
12
+ .filter(attr => ((attr[1] !== undefined) && (attr[1] !== null)))
13
+ .map(([k, v]) => ` ${k}="${v}"`)
14
+ .join("");
15
+ const gap = " ".repeat(level);
16
+ // No children → self-closing tag
17
+ if (!children.length) {
18
+ return `${gap}<${tag}${attrStr}/>`;
19
+ }
20
+ // Single text child → inline formatting
21
+ if (children.length === 1 && typeof children[0] === "string" && !children[0].includes("<")) {
22
+ return `${gap}<${tag}${attrStr}>${children[0].trimEnd()}</${tag}>`;
23
+ }
24
+ // Has children → recursive rendering
25
+ const inner = children
26
+ .map(c => typeof c === "string" ? `${" ".repeat(level + 1)}${c.trimEnd()}` : buildXml(c, level + 1))
27
+ .join("\n");
28
+ return `${gap}<${tag}${attrStr}>\n${inner}\n${gap}</${tag}>`;
29
+ }
30
+ /**
31
+ * Cell XML Structure Documentation
32
+ *
33
+ * Reference: https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.cell?view=openxml-3.0.1
34
+ *
35
+ * Parent Elements:
36
+ * - row
37
+ *
38
+ * Child Elements:
39
+ * - extLst (Future Feature Data Storage Area)
40
+ * - f (Formula)
41
+ * - is (Rich Text Inline)
42
+ * - v (Cell Value)
43
+ *
44
+ * Attributes:
45
+ * - cm (Cell Metadata Index): The zero-based index of the cell metadata record associated with this cell.
46
+ * Metadata information is found in the Metadata Part. Cell metadata is extra information stored at the
47
+ * cell level, and is attached to the cell (travels through moves, copy / paste, clear, etc).
48
+ * Cell metadata is not accessible via formula reference.
49
+ * The possible values for this attribute are defined by the W3C XML Schema unsignedInt datatype.
50
+ *
51
+ * - ph (Show Phonetic): A Boolean value indicating if the spreadsheet application should show phonetic
52
+ * information. Phonetic information is displayed in the same cell across the top of the cell and serves
53
+ * as a 'hint' which indicates how the text should be pronounced. This should only be used for East Asian languages.
54
+ * The possible values for this attribute are defined by the W3C XML Schema boolean datatype.
55
+ *
56
+ * - r (Reference): An A1 style reference to the location of this cell
57
+ * The possible values for this attribute are defined by the ST_CellRef simple type.
58
+ *
59
+ * - s (Style Index): The index of this cell's style. Style records are stored in the Styles Part.
60
+ * The possible values for this attribute are defined by the W3C XML Schema unsignedInt datatype.
61
+ *
62
+ * - t (Cell Data Type): An enumeration representing the cell's data type.
63
+ * The possible values for this attribute are defined by the ST_CellType simple type.
64
+ *
65
+ * - vm (Value Metadata Index): The zero-based index of the value metadata record associated with this cell's value.
66
+ * Metadata records are stored in the Metadata Part. Value metadata is extra information stored at the cell level,
67
+ * but associated with the value rather than the cell itself. Value metadata is accessible via formula reference.
68
+ * The possible values for this attribute are defined by the W3C XML Schema unsignedInt datatype.
69
+ */
@@ -0,0 +1,52 @@
1
+ // Content Types
2
+ export const CONTENT_TYPES = {
3
+ APP: "application/vnd.openxmlformats-officedocument.extended-properties+xml",
4
+ CORE: "application/vnd.openxmlformats-package.core-properties+xml",
5
+ RELATIONSHIPS: "application/vnd.openxmlformats-package.relationships+xml",
6
+ SHARED_STRINGS: "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
7
+ STYLES: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
8
+ THEME: "application/vnd.openxmlformats-officedocument.theme+xml",
9
+ WORKBOOK: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
10
+ WORKSHEET: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
11
+ XML: "application/xml",
12
+ };
13
+ // Default file paths
14
+ export const FILE_PATHS = {
15
+ APP: "docProps/app.xml",
16
+ CONTENT_TYPES: "[Content_Types].xml",
17
+ CORE: "docProps/core.xml",
18
+ RELS: "_rels/.rels",
19
+ SHARED_STRINGS: "xl/sharedStrings.xml",
20
+ STYLES: "xl/styles.xml",
21
+ THEME: "xl/theme/theme1.xml",
22
+ WORKBOOK: "xl/workbook.xml",
23
+ WORKBOOK_RELS: "xl/_rels/workbook.xml.rels",
24
+ WORKSHEET: "xl/worksheets/sheet1.xml",
25
+ };
26
+ // Relationship Types
27
+ export const RELATIONSHIP_TYPES = {
28
+ APP: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",
29
+ CORE: "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties",
30
+ OFFICE_DOCUMENT: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
31
+ SHARED_STRINGS: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings",
32
+ STYLES: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",
33
+ THEME: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme",
34
+ WORKSHEET: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet",
35
+ };
36
+ // XML Declarations
37
+ export const XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
38
+ // XML Namespaces
39
+ export const XML_NAMESPACES = {
40
+ CONTENT_TYPES: "http://schemas.openxmlformats.org/package/2006/content-types",
41
+ CORE_PROPERTIES: "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
42
+ DC: "http://purl.org/dc/elements/1.1/",
43
+ DCMITYPE: "http://purl.org/dc/dcmitype/",
44
+ DCTERMS: "http://purl.org/dc/terms/",
45
+ DOC_PROPS_VTYPES: "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes",
46
+ DRAWINGML: "http://schemas.openxmlformats.org/drawingml/2006/main",
47
+ EXTENDED_PROPERTIES: "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties",
48
+ OFFICE_DOCUMENT: "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
49
+ PACKAGE_RELATIONSHIPS: "http://schemas.openxmlformats.org/package/2006/relationships",
50
+ SPREADSHEET_ML: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
51
+ XSI: "http://www.w3.org/2001/XMLSchema-instance",
52
+ };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Converts a JavaScript Date object to Excel serial number format.
3
+ * Excel stores dates as serial numbers where 1 represents January 1, 1900.
4
+ *
5
+ * @param date - The JavaScript Date object to convert
6
+ *
7
+ * @returns The Excel serial number as a floating-point number
8
+ */
9
+ export function dateToExcelSerial(date) {
10
+ const msPerDay = 24 * 60 * 60 * 1000;
11
+ const excelEpoch = Date.UTC(1899, 11, 30); // Excel "day 0"
12
+ return (date.getTime() - excelEpoch) / msPerDay;
13
+ }
@@ -0,0 +1,18 @@
1
+ export * from "./build-app-xml.js";
2
+ export * from "./build-cell-children.js";
3
+ export * from "./build-content-types-xml.js";
4
+ export * from "./build-shared-strings-xml.js";
5
+ export * from "./build-styles-xml.js";
6
+ export * from "./build-theme-xml.js";
7
+ export * from "./build-workbook-rels-xml.js";
8
+ export * from "./build-workbook-xml.js";
9
+ export * from "./build-worksheet-xml.js";
10
+ export * from "./build-xml.js";
11
+ export * from "./constants.js";
12
+ export * from "./date-to-excel-serial.js";
13
+ export * from "./initialize-files.js";
14
+ export * from "./sheet.js";
15
+ export * from "./write-shared-strings-xml.js";
16
+ export * from "./write-styles-xml.js";
17
+ export * from "./write-worksheet-xml.js";
18
+ export * from "./write-xml.js";
@@ -0,0 +1,36 @@
1
+ import { buildAppXml } from "./build-app-xml.js";
2
+ import { buildContentTypesXml } from "./build-content-types-xml.js";
3
+ import { buildCoreXml } from "./build-core-xml.js";
4
+ import { buildRelsXml } from "./build-rels-xml.js";
5
+ import { buildSharedStringsXml } from "./build-shared-strings-xml.js";
6
+ import { buildStylesXml } from "./build-styles-xml.js";
7
+ import { buildThemeXml } from "./build-theme-xml.js";
8
+ import { buildWorkbookRels } from "./build-workbook-rels-xml.js";
9
+ import { buildWorkbookXml } from "./build-workbook-xml.js";
10
+ import { buildWorksheetXml } from "./build-worksheet-xml.js";
11
+ import { FILE_PATHS } from "./constants.js";
12
+ export const initializeFiles = (sheetName) => {
13
+ const sheetsCount = 1;
14
+ const contentTypesXml = buildContentTypesXml(sheetsCount);
15
+ const relsXml = buildRelsXml();
16
+ const appXml = buildAppXml({ sheetNames: [sheetName] });
17
+ const coreXml = buildCoreXml();
18
+ const workbookRelsXml = buildWorkbookRels(sheetsCount);
19
+ const stylesXml = buildStylesXml();
20
+ const sharedStringsXml = buildSharedStringsXml();
21
+ const themeXml = buildThemeXml();
22
+ const workbookXml = buildWorkbookXml([{ name: sheetName }]);
23
+ const worksheetXml = buildWorksheetXml();
24
+ return {
25
+ [FILE_PATHS.CONTENT_TYPES]: contentTypesXml,
26
+ [FILE_PATHS.RELS]: relsXml,
27
+ [FILE_PATHS.APP]: appXml,
28
+ [FILE_PATHS.CORE]: coreXml,
29
+ [FILE_PATHS.WORKBOOK_RELS]: workbookRelsXml,
30
+ [FILE_PATHS.STYLES]: stylesXml,
31
+ [FILE_PATHS.SHARED_STRINGS]: sharedStringsXml,
32
+ [FILE_PATHS.THEME]: themeXml,
33
+ [FILE_PATHS.WORKBOOK]: workbookXml,
34
+ [FILE_PATHS.WORKSHEET]: worksheetXml,
35
+ };
36
+ };
@@ -0,0 +1,141 @@
1
+ import { columnIndexToLetter, columnLetterToIndex } from "../../template/utils/index.js";
2
+ import { dateToExcelSerial } from "./date-to-excel-serial.js";
3
+ /** Maximum number of columns supported by Excel (XFD). */
4
+ const MAX_COLUMNS = 16384;
5
+ /** Maximum number of rows supported by Excel (1,048,576). */
6
+ const MAX_ROWS = 1_048_576;
7
+ /**
8
+ * Factory for creating a new sheet with bound helpers.
9
+ *
10
+ * @param name - Sheet name
11
+ * @param fn.addMerge - Function to add a merge range (bound to workbook)
12
+ * @param fn.removeMerge - Function to remove a merge range (bound to workbook)
13
+ * @param fn.addOrGetStyle - Function to add or get a style index
14
+ * @param fn.addSharedString - Function to add a shared string and return its index
15
+ * @returns SheetData instance with helpers
16
+ */
17
+ export function createSheet(name, fn) {
18
+ const { addMerge, addOrGetStyle, addSharedString, removeMerge, } = fn;
19
+ const rows = new Map();
20
+ return {
21
+ name,
22
+ rows,
23
+ addMerge(mergeCell) {
24
+ return addMerge({ ...mergeCell, sheetName: name });
25
+ },
26
+ removeMerge(mergeCell) {
27
+ return removeMerge({ ...mergeCell, sheetName: name });
28
+ },
29
+ setCell(rowIndex, column, cell) {
30
+ if (rowIndex <= 0) {
31
+ throw new Error("Invalid rowIndex");
32
+ }
33
+ if (!Number.isInteger(rowIndex) || rowIndex <= 0) {
34
+ throw new Error("Invalid rowIndex: must be a positive integer");
35
+ }
36
+ if (rowIndex > MAX_ROWS) {
37
+ throw new Error(`Invalid rowIndex: exceeds Excel max rows (${MAX_ROWS})`);
38
+ }
39
+ if (!rows.has(rowIndex)) {
40
+ rows.set(rowIndex, { cells: new Map() });
41
+ }
42
+ const letterColumn = typeof column === "number"
43
+ ? columnIndexToLetter(column)
44
+ : column;
45
+ if (!isValidColumn(letterColumn)) {
46
+ throw new Error(`Invalid column string: "${letterColumn}"`);
47
+ }
48
+ // if is Date
49
+ if (cell.value instanceof Date) {
50
+ cell.value = dateToExcelSerial(cell.value);
51
+ }
52
+ if (cell.isFormula) {
53
+ cell.type = undefined;
54
+ }
55
+ else {
56
+ if (cell.type === "str") {
57
+ throw new Error(`Cell type: "${cell.type}" valid only for formula cells`);
58
+ }
59
+ // If type is not provided — detect automatically
60
+ cell.type = detectCellType(cell.value, cell.type);
61
+ }
62
+ // Handle shared string
63
+ if (cell.type === "s") {
64
+ const idx = addSharedString(String(cell.value ?? ""), name);
65
+ cell = { ...cell, value: idx };
66
+ }
67
+ if (cell.style) {
68
+ const styleIndex = addOrGetStyle(cell.style, name);
69
+ cell.style.index = styleIndex;
70
+ }
71
+ rows.get(rowIndex)?.cells.set(letterColumn, cell);
72
+ },
73
+ getCell(rowIndex, column) {
74
+ if (typeof column === "number") {
75
+ if (column < 0 || column > MAX_COLUMNS) {
76
+ throw new Error("Invalid column number");
77
+ }
78
+ return rows.get(rowIndex)?.cells.get(columnIndexToLetter(column));
79
+ }
80
+ else {
81
+ if (!isValidColumn(column)) {
82
+ throw new Error(`Invalid column string: "${column}"`);
83
+ }
84
+ return rows.get(rowIndex)?.cells.get(column);
85
+ }
86
+ },
87
+ removeCell(rowIndex, column) {
88
+ if (rowIndex <= 0) {
89
+ throw new Error("Invalid rowIndex");
90
+ }
91
+ if (!Number.isInteger(rowIndex) || rowIndex <= 0) {
92
+ throw new Error("Invalid rowIndex: must be a positive integer");
93
+ }
94
+ if (rowIndex > MAX_ROWS) {
95
+ throw new Error(`Invalid rowIndex: exceeds Excel max rows (${MAX_ROWS})`);
96
+ }
97
+ const letterColumn = typeof column === "number"
98
+ ? columnIndexToLetter(column)
99
+ : column;
100
+ if (!isValidColumn(letterColumn)) {
101
+ throw new Error(`Invalid column string: "${letterColumn}"`);
102
+ }
103
+ return rows.get(rowIndex)?.cells.delete(letterColumn) ?? false;
104
+ },
105
+ };
106
+ }
107
+ /** Validates an Excel column string (A-Z, AA, ..., XFD). */
108
+ function isValidColumn(column) {
109
+ if (!/^[A-Z]+$/.test(column))
110
+ return false;
111
+ const idx = columnLetterToIndex(column);
112
+ return idx > 0 && idx <= MAX_COLUMNS;
113
+ }
114
+ /**
115
+ * Detects the appropriate cell type based on the value when not explicitly specified.
116
+ *
117
+ * @param value - Cell value
118
+ * @param explicitType - Explicitly provided type, if any
119
+ * @returns CellType inferred or the explicit type
120
+ */
121
+ function detectCellType(value, explicitType) {
122
+ if (explicitType) {
123
+ return explicitType;
124
+ }
125
+ if (value === null || value === undefined) {
126
+ // For empty cells we default to numeric type with empty value
127
+ return "n";
128
+ }
129
+ if (typeof value === "number") {
130
+ return "n";
131
+ }
132
+ if (typeof value === "boolean") {
133
+ return "b";
134
+ }
135
+ if (typeof value === "string") {
136
+ // Default to inlineStr for plain strings
137
+ return "inlineStr";
138
+ }
139
+ // Fallback to inlineStr
140
+ return "inlineStr";
141
+ }
@@ -0,0 +1,43 @@
1
+ import fs from "node:fs";
2
+ import fsPromises from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { escapeXml } from "../../utils/index.js";
5
+ import { XML_DECLARATION, XML_NAMESPACES } from "./constants.js";
6
+ /**
7
+ * Writes the `sharedStrings.xml` content to a file at the given destination.
8
+ *
9
+ * Uses a file write stream with backpressure control to avoid buffering large
10
+ * content in memory.
11
+ *
12
+ * @param destination - Absolute or relative file path to write
13
+ * @param strings - Array of unique strings used in the workbook
14
+ * @returns Promise that resolves when the write stream finishes
15
+ */
16
+ export async function writeSharedStringsXml(destination, strings = []) {
17
+ // Ensure destination folder exists
18
+ await fsPromises.mkdir(path.dirname(destination), { recursive: true });
19
+ const stream = fs.createWriteStream(destination, { encoding: "utf-8" });
20
+ try {
21
+ // Document header
22
+ stream.write(XML_DECLARATION + "\n");
23
+ stream.write(`<sst xmlns="${XML_NAMESPACES.SPREADSHEET_ML}" count="${strings.length}" uniqueCount="${strings.length}">\n`);
24
+ // Main string items
25
+ for (const s of strings) {
26
+ const preserve = /^\s|\s$/.test(s) ? " xml:space=\"preserve\"" : "";
27
+ const siXml = `<si><t${preserve}>${escapeXml(s)}</t></si>\n`;
28
+ // Write with backpressure control
29
+ if (!stream.write(siXml)) {
30
+ await new Promise(resolve => stream.once("drain", () => resolve()));
31
+ }
32
+ }
33
+ // Closing tag
34
+ stream.write("</sst>");
35
+ }
36
+ finally {
37
+ stream.end();
38
+ }
39
+ return new Promise((resolve, reject) => {
40
+ stream.on("error", reject);
41
+ stream.on("finish", resolve);
42
+ });
43
+ }
@@ -0,0 +1,157 @@
1
+ import fs from "node:fs";
2
+ import fsPromises from "node:fs/promises";
3
+ import path from "node:path";
4
+ import * as Default from "../default/index.js";
5
+ import { XML_DECLARATION, XML_NAMESPACES } from "./constants.js";
6
+ import { writeXml } from "./write-xml.js";
7
+ /**
8
+ * Writes the `styles.xml` part to a file at the given destination using a write stream.
9
+ * Falls back to default font/fill/border collections when none are provided.
10
+ *
11
+ * @param destination - Absolute or relative file path to write
12
+ * @param data - Style collections used to construct the stylesheet
13
+ * @param data.borders - Array of border XmlNodes
14
+ * @param data.cellXfs - Array of cell format records
15
+ * @param data.fills - Array of fill XmlNodes
16
+ * @param data.fonts - Array of font XmlNodes
17
+ * @param data.numFmts - Array of custom number formats (formatCode and id)
18
+ * @returns Promise that resolves when the write stream finishes
19
+ */
20
+ export async function writeStylesXml(destination, data) {
21
+ // Ensure destination folder exists
22
+ await fsPromises.mkdir(path.dirname(destination), { recursive: true });
23
+ const stream = fs.createWriteStream(destination, { encoding: "utf-8" });
24
+ try {
25
+ const { borders = [], cellXfs = [], fills = [], fonts = [], numFmts = [], } = data || {};
26
+ const children = [];
27
+ if (numFmts.length) {
28
+ children.push({
29
+ attrs: { count: String(numFmts.length) },
30
+ children: numFmts.map(nf => ({
31
+ attrs: {
32
+ formatCode: nf.formatCode,
33
+ numFmtId: String(nf.id),
34
+ },
35
+ tag: "numFmt",
36
+ })),
37
+ tag: "numFmts",
38
+ });
39
+ }
40
+ if (fonts.length) {
41
+ children.push({
42
+ attrs: { count: String(fonts.length) },
43
+ children: fonts,
44
+ tag: "fonts",
45
+ });
46
+ }
47
+ else {
48
+ children.push({
49
+ attrs: { count: "1" },
50
+ children: [Default.font()],
51
+ tag: "fonts",
52
+ });
53
+ }
54
+ if (fills.length) {
55
+ children.push({
56
+ attrs: { count: String(fills.length) },
57
+ children: fills,
58
+ tag: "fills",
59
+ });
60
+ }
61
+ else {
62
+ children.push({
63
+ attrs: { count: "1" },
64
+ children: [Default.fill()],
65
+ tag: "fills",
66
+ });
67
+ }
68
+ if (borders.length) {
69
+ children.push({
70
+ attrs: { count: String(borders.length) },
71
+ children: borders,
72
+ tag: "borders",
73
+ });
74
+ }
75
+ else {
76
+ children.push({
77
+ attrs: { count: "1" },
78
+ children: [Default.border()],
79
+ tag: "borders",
80
+ });
81
+ }
82
+ children.push({
83
+ attrs: { count: "1" },
84
+ children: [{
85
+ attrs: { borderId: "0", fillId: "0", fontId: "0", numFmtId: "0" },
86
+ tag: "xf",
87
+ }],
88
+ tag: "cellStyleXfs",
89
+ });
90
+ if (cellXfs.length) {
91
+ children.push({
92
+ attrs: { count: String(cellXfs.length) },
93
+ children: cellXfs.map((xf, i) => {
94
+ const isBaseXf = i === 0;
95
+ const hasAlignment = !!xf.alignment;
96
+ const xfChildren = [];
97
+ if (hasAlignment) {
98
+ xfChildren.push({
99
+ attrs: {
100
+ ...(xf.alignment?.horizontal ? { horizontal: xf.alignment.horizontal } : {}),
101
+ ...(xf.alignment?.vertical ? { vertical: xf.alignment.vertical } : {}),
102
+ ...(xf.alignment?.wrapText ? { wrapText: "1" } : {}),
103
+ ...(xf.alignment?.indent !== undefined ? { indent: String(xf.alignment.indent) } : {}),
104
+ },
105
+ tag: "alignment",
106
+ });
107
+ }
108
+ return {
109
+ attrs: {
110
+ ...(isBaseXf
111
+ ? {}
112
+ : {
113
+ applyBorder: "1",
114
+ applyFill: "1",
115
+ applyFont: "1",
116
+ applyNumberFormat: xf.numFmtId ? "1" : "0",
117
+ }),
118
+ ...(hasAlignment ? { applyAlignment: "1" } : {}),
119
+ borderId: String(xf.borderId),
120
+ fillId: String(xf.fillId),
121
+ fontId: String(xf.fontId),
122
+ numFmtId: String(xf.numFmtId ?? 0),
123
+ xfId: "0",
124
+ },
125
+ children: xfChildren,
126
+ tag: "xf",
127
+ };
128
+ }),
129
+ tag: "cellXfs",
130
+ });
131
+ }
132
+ else {
133
+ // Base style without fill
134
+ children.push({
135
+ attrs: { count: "1" },
136
+ children: [
137
+ { attrs: { borderId: "0", fillId: "0", fontId: "0", numFmtId: "0", xfId: "0" }, tag: "xf" },
138
+ ],
139
+ tag: "cellXfs",
140
+ });
141
+ }
142
+ // XML declaration
143
+ stream.write(XML_DECLARATION + "\n");
144
+ await writeXml({
145
+ attrs: { xmlns: XML_NAMESPACES.SPREADSHEET_ML },
146
+ children,
147
+ tag: "styleSheet",
148
+ }, stream);
149
+ }
150
+ finally {
151
+ stream.end();
152
+ }
153
+ return new Promise((resolve, reject) => {
154
+ stream.on("error", reject);
155
+ stream.on("finish", resolve);
156
+ });
157
+ }