@js-ak/excel-toolbox 1.8.2 → 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 (210) 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/cjs/lib/zip/utils/to-bytes.js +19 -11
  71. package/build/esm/lib/template/template-fs.js +2 -1
  72. package/build/esm/lib/template/template-memory.js +2 -1
  73. package/build/esm/lib/template/utils/column-letter-to-index.js +12 -0
  74. package/build/esm/lib/template/utils/index.js +1 -1
  75. package/build/esm/lib/template/utils/prepare-row-to-cells.js +1 -1
  76. package/build/esm/lib/template/utils/validate-worksheet-xml.js +19 -9
  77. package/build/esm/lib/utils/index.js +2 -0
  78. package/build/esm/lib/utils/trim-and-join-multiline.js +29 -0
  79. package/build/esm/lib/workbook-builder/default/border.js +14 -0
  80. package/build/esm/lib/workbook-builder/default/cell-xf.js +11 -0
  81. package/build/esm/lib/workbook-builder/default/fill.js +14 -0
  82. package/build/esm/lib/workbook-builder/default/font.js +15 -0
  83. package/build/esm/lib/workbook-builder/default/index.js +5 -0
  84. package/build/esm/lib/workbook-builder/default/sheet-name.js +6 -0
  85. package/build/esm/lib/workbook-builder/index.js +2 -0
  86. package/build/esm/lib/workbook-builder/merge-cells/add.js +36 -0
  87. package/build/esm/lib/workbook-builder/merge-cells/helpers/index.js +2 -0
  88. package/build/esm/lib/workbook-builder/merge-cells/helpers/ranges-equal.js +14 -0
  89. package/build/esm/lib/workbook-builder/merge-cells/helpers/ranges-intersect.js +14 -0
  90. package/build/esm/lib/workbook-builder/merge-cells/index.js +2 -0
  91. package/build/esm/lib/workbook-builder/merge-cells/remove.js +24 -0
  92. package/build/esm/lib/workbook-builder/shared-string-ref/add.js +21 -0
  93. package/build/esm/lib/workbook-builder/shared-string-ref/index.js +3 -0
  94. package/build/esm/lib/workbook-builder/shared-string-ref/remove-all-from-sheet.js +63 -0
  95. package/build/esm/lib/workbook-builder/shared-string-ref/remove.js +63 -0
  96. package/build/esm/lib/workbook-builder/style-ref/add-or-get.js +58 -0
  97. package/build/esm/lib/workbook-builder/style-ref/helpers/add-num-fmt.js +21 -0
  98. package/build/esm/lib/workbook-builder/style-ref/helpers/border-to-xml.js +45 -0
  99. package/build/esm/lib/workbook-builder/style-ref/helpers/fill-to-xml.js +47 -0
  100. package/build/esm/lib/workbook-builder/style-ref/helpers/font-to-xml.js +75 -0
  101. package/build/esm/lib/workbook-builder/style-ref/helpers/index.js +5 -0
  102. package/build/esm/lib/workbook-builder/style-ref/helpers/reindex-style-map-after-removal.js +26 -0
  103. package/build/esm/lib/workbook-builder/style-ref/index.js +3 -0
  104. package/build/esm/lib/workbook-builder/style-ref/remove-all-from-sheet.js +23 -0
  105. package/build/esm/lib/workbook-builder/style-ref/remove.js +49 -0
  106. package/build/esm/lib/workbook-builder/types/app-xml-options.js +1 -0
  107. package/build/esm/lib/workbook-builder/types/border-style.js +1 -0
  108. package/build/esm/lib/workbook-builder/types/cell-data.js +1 -0
  109. package/build/esm/lib/workbook-builder/types/cell-style.js +1 -0
  110. package/build/esm/lib/workbook-builder/types/cell-type.js +1 -0
  111. package/build/esm/lib/workbook-builder/types/cell-value.js +1 -0
  112. package/build/esm/lib/workbook-builder/types/cell-xf.js +1 -0
  113. package/build/esm/lib/workbook-builder/types/index.js +11 -0
  114. package/build/esm/lib/workbook-builder/types/merge-cell.js +1 -0
  115. package/build/esm/lib/workbook-builder/types/row-data.js +1 -0
  116. package/build/esm/lib/workbook-builder/types/sheet-data.js +1 -0
  117. package/build/esm/lib/workbook-builder/types/xml-node.js +1 -0
  118. package/build/esm/lib/workbook-builder/utils/build-app-xml.js +48 -0
  119. package/build/esm/lib/workbook-builder/utils/build-cell-children.js +56 -0
  120. package/build/esm/lib/workbook-builder/utils/build-content-types-xml.js +39 -0
  121. package/build/esm/lib/workbook-builder/utils/build-core-xml.js +24 -0
  122. package/build/esm/lib/workbook-builder/utils/build-rels-xml.js +16 -0
  123. package/build/esm/lib/workbook-builder/utils/build-shared-strings-xml.js +36 -0
  124. package/build/esm/lib/workbook-builder/utils/build-styles-xml.js +142 -0
  125. package/build/esm/lib/workbook-builder/utils/build-theme-xml.js +606 -0
  126. package/build/esm/lib/workbook-builder/utils/build-workbook-rels-xml.js +55 -0
  127. package/build/esm/lib/workbook-builder/utils/build-workbook-xml.js +23 -0
  128. package/build/esm/lib/workbook-builder/utils/build-worksheet-xml.js +63 -0
  129. package/build/esm/lib/workbook-builder/utils/build-xml.js +69 -0
  130. package/build/esm/lib/workbook-builder/utils/constants.js +52 -0
  131. package/build/esm/lib/workbook-builder/utils/date-to-excel-serial.js +13 -0
  132. package/build/esm/lib/workbook-builder/utils/index.js +18 -0
  133. package/build/esm/lib/workbook-builder/utils/initialize-files.js +36 -0
  134. package/build/esm/lib/workbook-builder/utils/sheet.js +141 -0
  135. package/build/esm/lib/workbook-builder/utils/write-shared-strings-xml.js +43 -0
  136. package/build/esm/lib/workbook-builder/utils/write-styles-xml.js +157 -0
  137. package/build/esm/lib/workbook-builder/utils/write-worksheet-xml.js +203 -0
  138. package/build/esm/lib/workbook-builder/utils/write-xml.js +34 -0
  139. package/build/esm/lib/workbook-builder/workbook-builder.js +374 -0
  140. package/build/esm/lib/zip/utils/to-bytes.js +19 -11
  141. package/build/types/lib/template/utils/column-letter-to-index.d.ts +1 -0
  142. package/build/types/lib/template/utils/index.d.ts +1 -1
  143. package/build/types/lib/utils/index.d.ts +2 -0
  144. package/build/types/lib/utils/trim-and-join-multiline.d.ts +23 -0
  145. package/build/types/lib/workbook-builder/default/border.d.ts +7 -0
  146. package/build/types/lib/workbook-builder/default/cell-xf.d.ts +7 -0
  147. package/build/types/lib/workbook-builder/default/fill.d.ts +7 -0
  148. package/build/types/lib/workbook-builder/default/font.d.ts +21 -0
  149. package/build/types/lib/workbook-builder/default/index.d.ts +5 -0
  150. package/build/types/lib/workbook-builder/default/sheet-name.d.ts +6 -0
  151. package/build/types/lib/workbook-builder/index.d.ts +2 -0
  152. package/build/types/lib/workbook-builder/merge-cells/add.d.ts +15 -0
  153. package/build/types/lib/workbook-builder/merge-cells/helpers/index.d.ts +2 -0
  154. package/build/types/lib/workbook-builder/merge-cells/helpers/ranges-equal.d.ts +10 -0
  155. package/build/types/lib/workbook-builder/merge-cells/helpers/ranges-intersect.d.ts +10 -0
  156. package/build/types/lib/workbook-builder/merge-cells/index.d.ts +2 -0
  157. package/build/types/lib/workbook-builder/merge-cells/remove.d.ts +15 -0
  158. package/build/types/lib/workbook-builder/shared-string-ref/add.d.ts +13 -0
  159. package/build/types/lib/workbook-builder/shared-string-ref/index.d.ts +3 -0
  160. package/build/types/lib/workbook-builder/shared-string-ref/remove-all-from-sheet.d.ts +10 -0
  161. package/build/types/lib/workbook-builder/shared-string-ref/remove.d.ts +13 -0
  162. package/build/types/lib/workbook-builder/style-ref/add-or-get.d.ts +16 -0
  163. package/build/types/lib/workbook-builder/style-ref/helpers/add-num-fmt.d.ts +17 -0
  164. package/build/types/lib/workbook-builder/style-ref/helpers/border-to-xml.d.ts +16 -0
  165. package/build/types/lib/workbook-builder/style-ref/helpers/fill-to-xml.d.ts +17 -0
  166. package/build/types/lib/workbook-builder/style-ref/helpers/font-to-xml.d.ts +18 -0
  167. package/build/types/lib/workbook-builder/style-ref/helpers/index.d.ts +5 -0
  168. package/build/types/lib/workbook-builder/style-ref/helpers/reindex-style-map-after-removal.d.ts +15 -0
  169. package/build/types/lib/workbook-builder/style-ref/index.d.ts +3 -0
  170. package/build/types/lib/workbook-builder/style-ref/remove-all-from-sheet.d.ts +4 -0
  171. package/build/types/lib/workbook-builder/style-ref/remove.d.ts +18 -0
  172. package/build/types/lib/workbook-builder/types/app-xml-options.d.ts +9 -0
  173. package/build/types/lib/workbook-builder/types/border-style.d.ts +5 -0
  174. package/build/types/lib/workbook-builder/types/cell-data.d.ts +10 -0
  175. package/build/types/lib/workbook-builder/types/cell-style.d.ts +32 -0
  176. package/build/types/lib/workbook-builder/types/cell-type.d.ts +11 -0
  177. package/build/types/lib/workbook-builder/types/cell-value.d.ts +2 -0
  178. package/build/types/lib/workbook-builder/types/cell-xf.d.ts +13 -0
  179. package/build/types/lib/workbook-builder/types/index.d.ts +11 -0
  180. package/build/types/lib/workbook-builder/types/merge-cell.d.ts +6 -0
  181. package/build/types/lib/workbook-builder/types/row-data.d.ts +5 -0
  182. package/build/types/lib/workbook-builder/types/sheet-data.d.ts +13 -0
  183. package/build/types/lib/workbook-builder/types/xml-node.d.ts +11 -0
  184. package/build/types/lib/workbook-builder/utils/build-app-xml.d.ts +2 -0
  185. package/build/types/lib/workbook-builder/utils/build-cell-children.d.ts +9 -0
  186. package/build/types/lib/workbook-builder/utils/build-content-types-xml.d.ts +1 -0
  187. package/build/types/lib/workbook-builder/utils/build-core-xml.d.ts +1 -0
  188. package/build/types/lib/workbook-builder/utils/build-rels-xml.d.ts +1 -0
  189. package/build/types/lib/workbook-builder/utils/build-shared-strings-xml.d.ts +10 -0
  190. package/build/types/lib/workbook-builder/utils/build-styles-xml.d.ts +23 -0
  191. package/build/types/lib/workbook-builder/utils/build-theme-xml.d.ts +1 -0
  192. package/build/types/lib/workbook-builder/utils/build-workbook-rels-xml.d.ts +9 -0
  193. package/build/types/lib/workbook-builder/utils/build-workbook-xml.d.ts +3 -0
  194. package/build/types/lib/workbook-builder/utils/build-worksheet-xml.d.ts +2 -0
  195. package/build/types/lib/workbook-builder/utils/build-xml.d.ts +50 -0
  196. package/build/types/lib/workbook-builder/utils/constants.d.ts +47 -0
  197. package/build/types/lib/workbook-builder/utils/date-to-excel-serial.d.ts +9 -0
  198. package/build/types/lib/workbook-builder/utils/index.d.ts +18 -0
  199. package/build/types/lib/workbook-builder/utils/initialize-files.d.ts +13 -0
  200. package/build/types/lib/workbook-builder/utils/sheet.d.ts +21 -0
  201. package/build/types/lib/workbook-builder/utils/write-shared-strings-xml.d.ts +11 -0
  202. package/build/types/lib/workbook-builder/utils/write-styles-xml.d.ts +24 -0
  203. package/build/types/lib/workbook-builder/utils/write-worksheet-xml.d.ts +14 -0
  204. package/build/types/lib/workbook-builder/utils/write-xml.d.ts +3 -0
  205. package/build/types/lib/workbook-builder/workbook-builder.d.ts +110 -0
  206. package/build/types/lib/zip/utils/to-bytes.d.ts +2 -2
  207. package/package.json +4 -2
  208. /package/build/cjs/lib/{template/utils → utils}/escape-xml.js +0 -0
  209. /package/build/esm/lib/{template/utils → utils}/escape-xml.js +0 -0
  210. /package/build/types/lib/{template/utils → utils}/escape-xml.d.ts +0 -0
@@ -0,0 +1,414 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.WorkbookBuilder = void 0;
40
+ const node_crypto_1 = __importDefault(require("node:crypto"));
41
+ const promises_1 = __importDefault(require("node:fs/promises"));
42
+ const node_os_1 = __importDefault(require("node:os"));
43
+ const node_path_1 = __importDefault(require("node:path"));
44
+ const Zip = __importStar(require("../zip/index.js"));
45
+ const index_js_1 = require("../template/utils/index.js");
46
+ const Utils = __importStar(require("./utils/index.js"));
47
+ const Default = __importStar(require("./default/index.js"));
48
+ const MergeCells = __importStar(require("./merge-cells/index.js"));
49
+ const SharedStringRef = __importStar(require("./shared-string-ref/index.js"));
50
+ const StyleRef = __importStar(require("./style-ref/index.js"));
51
+ /**
52
+ * Builds Excel workbooks by composing sheets, styles, shared strings and merges,
53
+ * and provides methods to save to file or stream.
54
+ *
55
+ * @experimental This API is experimental and might change in future versions.
56
+ */
57
+ class WorkbookBuilder {
58
+ /** In-memory representation of workbook files to be zipped. */
59
+ #files;
60
+ /** Collection of sheets keyed by sheet name. */
61
+ #sheets = new Map();
62
+ /** Shared strings storage used by cells of type "s". */
63
+ #sharedStrings = [];
64
+ /** Map for lookup of shared string indices (key = string, value = index). */
65
+ #sharedStringMap = new Map();
66
+ /** Workbook style collections. */
67
+ #borders;
68
+ #cellXfs;
69
+ #fills;
70
+ #fonts;
71
+ #numFmts;
72
+ /** Map of serialized style JSON to style index (xf). */
73
+ #styleMap = new Map();
74
+ /** Map caches for fast de-duplication of style components. */
75
+ #fontMap = new Map();
76
+ #fillMap = new Map();
77
+ #borderMap = new Map();
78
+ /** Merge cell ranges grouped by sheet name. */
79
+ #mergeCells = new Map();
80
+ /**
81
+ * Creates a new workbook with a default sheet and initial style collections.
82
+ *
83
+ * @param options.defaultSheetName - The name for the initial sheet
84
+ */
85
+ constructor({ defaultSheetName = Default.sheetName(), } = {}) {
86
+ this.#files = Utils.initializeFiles(defaultSheetName);
87
+ // Initialize base style collections
88
+ this.#borders = [Default.border()];
89
+ this.#fills = [Default.fill()];
90
+ this.#fonts = [Default.font()];
91
+ this.#numFmts = [];
92
+ this.#cellXfs = [Default.cellXf()];
93
+ // Seed component maps with defaults at index 0
94
+ this.#fontMap.set(JSON.stringify(this.#fonts[0]), 0);
95
+ this.#fillMap.set(JSON.stringify(this.#fills[0]), 0);
96
+ this.#borderMap.set(JSON.stringify(this.#borders[0]), 0);
97
+ const sheet = Utils.createSheet(defaultSheetName, {
98
+ addMerge: this.#addMerge.bind(this),
99
+ addOrGetStyle: this.#addOrGetStyle.bind(this),
100
+ addSharedString: this.#addSharedString.bind(this),
101
+ removeMerge: this.#removeMerge.bind(this),
102
+ });
103
+ this.#sheets.set(Default.sheetName(), sheet);
104
+ }
105
+ /** Returns the internal sheets map. */
106
+ get sheets() {
107
+ return this.#sheets;
108
+ }
109
+ /** Returns the shared strings array. */
110
+ get sharedStrings() {
111
+ return this.#sharedStrings;
112
+ }
113
+ /** Replaces the shared strings array. */
114
+ set sharedStrings(sharedStrings) {
115
+ this.#sharedStrings = sharedStrings;
116
+ }
117
+ /** Returns the shared string index map. */
118
+ get sharedStringMap() {
119
+ return this.#sharedStringMap;
120
+ }
121
+ /** Returns the borders collection. */
122
+ get borders() {
123
+ return this.#borders;
124
+ }
125
+ /** Returns the border cache map (serialized xml -> index). */
126
+ get bordersMap() {
127
+ return this.#borderMap;
128
+ }
129
+ /** Returns the cellXfs (style records). */
130
+ get cellXfs() {
131
+ return this.#cellXfs;
132
+ }
133
+ /** Returns the fills collection. */
134
+ get fills() {
135
+ return this.#fills;
136
+ }
137
+ /** Returns the fill cache map (serialized xml -> index). */
138
+ get fillsMap() {
139
+ return this.#fillMap;
140
+ }
141
+ /** Returns the fonts collection. */
142
+ get fonts() {
143
+ return this.#fonts;
144
+ }
145
+ /** Returns the font cache map (serialized xml -> index). */
146
+ get fontsMap() {
147
+ return this.#fontMap;
148
+ }
149
+ /** Returns the number formats collection. */
150
+ get numFmts() {
151
+ return this.#numFmts;
152
+ }
153
+ /** Returns the mapping from serialized style JSON to style index. */
154
+ get styleMap() {
155
+ return this.#styleMap;
156
+ }
157
+ /** Returns the merge ranges, grouped by sheet name. */
158
+ get mergeCells() {
159
+ return this.#mergeCells;
160
+ }
161
+ /** Shared strings */
162
+ /** Adds a shared string (or returns existing index) and tracks its usage by sheet. */
163
+ #addSharedString(str, sheetName) {
164
+ return SharedStringRef.add.bind(this)({ sheetName, str });
165
+ }
166
+ /** -------------- */
167
+ /** Style refs */
168
+ /** Adds a style or returns an existing style index. */
169
+ #addOrGetStyle(style) {
170
+ return StyleRef.addOrGet.bind(this)({ style });
171
+ }
172
+ ;
173
+ /** ---------- */
174
+ /** Merge cells */
175
+ /** Adds a merge range to a sheet. */
176
+ #addMerge(payload) {
177
+ return MergeCells.add.bind(this)(payload);
178
+ }
179
+ /** Removes a merge range from a sheet. */
180
+ #removeMerge(payload) {
181
+ return MergeCells.remove.bind(this)(payload);
182
+ }
183
+ /** Removes all merge ranges for a sheet. */
184
+ #removeSheetMerges(sheetName) {
185
+ this.mergeCells.delete(sheetName);
186
+ }
187
+ /** ----------- */
188
+ /** Adds or replaces a logical file content in the in-memory file map. */
189
+ #addFile(key, value) {
190
+ this.#files[key] = value;
191
+ }
192
+ /** Updates the docProps/app.xml content based on current sheet names. */
193
+ #updateAppXml() {
194
+ this.#addFile(Utils.FILE_PATHS.APP, Utils.buildAppXml({ sheetNames: Array.from(this.#sheets.keys()) }));
195
+ }
196
+ /** Updates the xl/workbook.xml content based on current sheets. */
197
+ #updateWorkbookXml() {
198
+ this.#addFile(Utils.FILE_PATHS.WORKBOOK, Utils.buildWorkbookXml(Array.from(this.#sheets.values())));
199
+ }
200
+ /** Updates the xl/_rels/workbook.xml.rels relationships for sheets. */
201
+ #updateWorkbookRels() {
202
+ this.#addFile(Utils.FILE_PATHS.WORKBOOK_RELS, Utils.buildWorkbookRels(this.#sheets.size));
203
+ }
204
+ /** Updates [Content_Types].xml with sheet overrides. */
205
+ #updateContentTypes() {
206
+ this.#addFile(Utils.FILE_PATHS.CONTENT_TYPES, Utils.buildContentTypesXml(this.#sheets.size));
207
+ }
208
+ /** Public methods */
209
+ /**
210
+ * Adds a new sheet to the workbook.
211
+ *
212
+ * @throws Error if a sheet with the same name already exists
213
+ * @param sheetName - Sheet name to add
214
+ * @returns The created sheet data
215
+ */
216
+ addSheet(sheetName) {
217
+ if (this.getSheet(sheetName)) {
218
+ throw new Error("Sheet with this name already exists");
219
+ }
220
+ const sheet = Utils.createSheet(sheetName, {
221
+ addMerge: this.#addMerge.bind(this),
222
+ addOrGetStyle: this.#addOrGetStyle.bind(this),
223
+ addSharedString: this.#addSharedString.bind(this),
224
+ removeMerge: this.#removeMerge.bind(this),
225
+ });
226
+ this.#sheets.set(sheetName, sheet);
227
+ // Add entry to app.xml
228
+ this.#updateAppXml();
229
+ // Add entry to workbook.xml
230
+ this.#updateWorkbookXml();
231
+ // Add relationship in workbook.xml.rels
232
+ this.#updateWorkbookRels();
233
+ // Add Override in [Content_Types].xml
234
+ this.#updateContentTypes();
235
+ return sheet;
236
+ }
237
+ /** Returns a sheet by name if it exists. */
238
+ getSheet(sheetName) {
239
+ return this.#sheets.get(sheetName);
240
+ }
241
+ /**
242
+ * Removes a sheet by name.
243
+ * If cleanup is enabled, also removes associated shared strings and styles.
244
+ *
245
+ * @param sheetName - Sheet name to remove
246
+ * @returns True if the sheet existed and was removed
247
+ */
248
+ removeSheet(sheetName) {
249
+ const sheet = this.#sheets.get(sheetName);
250
+ if (!sheet) {
251
+ throw new Error("Sheet not found: " + sheetName);
252
+ }
253
+ // Remove its merges
254
+ this.#removeSheetMerges(sheetName);
255
+ // Remove from collection
256
+ this.#sheets.delete(sheetName);
257
+ this.#updateAppXml();
258
+ this.#updateWorkbookXml();
259
+ this.#updateWorkbookRels();
260
+ this.#updateContentTypes();
261
+ return true;
262
+ }
263
+ /**
264
+ * Returns a snapshot of the workbook internals for inspection and tests.
265
+ * The returned structure is deeply frozen to avoid accidental mutations.
266
+ */
267
+ getInfo() {
268
+ function deepFreeze(obj) {
269
+ if (obj === null || obj === undefined) {
270
+ return obj;
271
+ }
272
+ if (typeof obj !== "object") {
273
+ // string | number | boolean | symbol
274
+ return obj;
275
+ }
276
+ if (Array.isArray(obj)) {
277
+ return Object.freeze(obj.map(item => deepFreeze(item)));
278
+ }
279
+ if (obj instanceof Map) {
280
+ const frozenMap = new Map(Array.from(obj.entries()).map(([k, v]) => [k, deepFreeze(v)]));
281
+ return Object.freeze(frozenMap);
282
+ }
283
+ if (obj instanceof Set) {
284
+ const frozenSet = new Set(Array.from(obj.values()).map(v => deepFreeze(v)));
285
+ return Object.freeze(frozenSet);
286
+ }
287
+ // XmlNode or generic object
288
+ const frozenObj = {};
289
+ for (const [k, v] of Object.entries(obj)) {
290
+ frozenObj[k] = deepFreeze(v);
291
+ }
292
+ return Object.freeze(frozenObj);
293
+ }
294
+ return deepFreeze({
295
+ mergeCells: new Map(this.#mergeCells),
296
+ sheetsNames: Array.from(this.#sheets.values()).map((sheet) => sheet.name),
297
+ sharedStringMap: new Map(this.#sharedStringMap),
298
+ sharedStrings: [...this.#sharedStrings],
299
+ styles: {
300
+ borders: [...this.#borders],
301
+ cellXfs: [...this.#cellXfs],
302
+ fills: [...this.#fills],
303
+ fonts: [...this.#fonts],
304
+ numFmts: [...this.#numFmts],
305
+ styleMap: new Map(this.#styleMap),
306
+ },
307
+ });
308
+ }
309
+ /**
310
+ * Generates workbook XML parts in-memory and writes a .xlsx zip to disk.
311
+ *
312
+ * @param path - Absolute or relative file path to write
313
+ */
314
+ async saveToFile(path) {
315
+ let index = 0;
316
+ for (const sheet of this.#sheets.values()) {
317
+ const merges = this.#mergeCells.get(sheet.name) || [];
318
+ const preparedMerges = merges.map(merge => `${(0, index_js_1.columnIndexToLetter)(merge.startCol)}${merge.startRow}:${(0, index_js_1.columnIndexToLetter)(merge.endCol)}${merge.endRow}`);
319
+ const xml = Utils.buildWorksheetXml(sheet.rows, preparedMerges);
320
+ const filePath = `xl/worksheets/sheet${++index}.xml`;
321
+ this.#addFile(filePath, (0, index_js_1.updateDimension)(xml));
322
+ }
323
+ if (this.#sharedStrings.length) {
324
+ const xml = Utils.buildSharedStringsXml(this.#sharedStrings);
325
+ this.#addFile(Utils.FILE_PATHS.SHARED_STRINGS, xml);
326
+ }
327
+ // Styles
328
+ this.#addFile(Utils.FILE_PATHS.STYLES, Utils.buildStylesXml({
329
+ borders: this.#borders,
330
+ cellXfs: this.#cellXfs,
331
+ fills: this.#fills,
332
+ fonts: this.#fonts,
333
+ numFmts: this.#numFmts,
334
+ }));
335
+ const zipBuffer = await Zip.create(this.#files);
336
+ await promises_1.default.writeFile(path, zipBuffer);
337
+ }
338
+ /**
339
+ * Saves the workbook to a writable stream using temporary files.
340
+ * This method creates temporary files from the in-memory data and streams them
341
+ * to the output stream, avoiding loading the entire file into memory.
342
+ *
343
+ * @param output - Writable stream to receive the Excel file
344
+ * @param options.destination - Optional existing directory to use instead of a system temp directory
345
+ * @param options.cleanup - Optional flag to cleanup the temporary directory after saving (default: true)
346
+ * @returns Promise that resolves when the file has been fully written
347
+ */
348
+ async saveToStream(output, options) {
349
+ const { cleanup = true, destination } = options ?? {};
350
+ // Determine a temp directory to assemble ZIP contents
351
+ let tempDir = "";
352
+ if (destination) {
353
+ // Create a random subdirectory inside provided destination
354
+ tempDir = node_path_1.default.join(destination, node_crypto_1.default.randomUUID());
355
+ await promises_1.default.mkdir(tempDir, { recursive: true });
356
+ }
357
+ else {
358
+ // Create a temp directory in OS temp
359
+ tempDir = await promises_1.default.mkdtemp(node_path_1.default.join(node_os_1.default.tmpdir(), "excel-toolbox-", node_crypto_1.default.randomUUID()));
360
+ }
361
+ let index = 0;
362
+ const usedFileKeys = [];
363
+ // Write "xl/worksheets/sheet*.xml"
364
+ for (const sheet of this.#sheets.values()) {
365
+ const merges = this.#mergeCells.get(sheet.name) || [];
366
+ const filePath = `xl/worksheets/sheet${++index}.xml`;
367
+ usedFileKeys.push(filePath);
368
+ const fullPath = node_path_1.default.join(tempDir, ...filePath.split("/"));
369
+ await Utils.writeWorksheetXml(fullPath, sheet.rows, merges);
370
+ this.#addFile(filePath, "");
371
+ }
372
+ // Write "xl/sharedStrings.xml"
373
+ if (this.#sharedStrings.length) {
374
+ usedFileKeys.push(Utils.FILE_PATHS.SHARED_STRINGS);
375
+ const fullPath = node_path_1.default.join(tempDir, ...Utils.FILE_PATHS.SHARED_STRINGS.split("/"));
376
+ await Utils.writeSharedStringsXml(fullPath, this.#sharedStrings);
377
+ }
378
+ // Write "xl/styles.xml"
379
+ {
380
+ usedFileKeys.push(Utils.FILE_PATHS.STYLES);
381
+ const fullPath = node_path_1.default.join(tempDir, ...Utils.FILE_PATHS.STYLES.split("/"));
382
+ await Utils.writeStylesXml(fullPath, {
383
+ borders: this.#borders,
384
+ cellXfs: this.#cellXfs,
385
+ fills: this.#fills,
386
+ fonts: this.#fonts,
387
+ numFmts: this.#numFmts,
388
+ });
389
+ }
390
+ try {
391
+ // Write all files from memory to temporary files
392
+ const fileKeys = [];
393
+ for (const [key, value] of Object.entries(this.#files)) {
394
+ if (usedFileKeys.includes(key)) {
395
+ fileKeys.push(key);
396
+ continue;
397
+ }
398
+ const fullPath = node_path_1.default.join(tempDir, ...key.split("/"));
399
+ await promises_1.default.mkdir(node_path_1.default.dirname(fullPath), { recursive: true });
400
+ await promises_1.default.writeFile(fullPath, value);
401
+ fileKeys.push(key);
402
+ }
403
+ // Create ZIP archive and stream to output
404
+ await Zip.createWithStream(fileKeys, tempDir, output);
405
+ }
406
+ finally {
407
+ // Clean up temporary files
408
+ if (cleanup) {
409
+ await promises_1.default.rm(tempDir, { force: true, recursive: true });
410
+ }
411
+ }
412
+ }
413
+ }
414
+ exports.WorkbookBuilder = WorkbookBuilder;
@@ -17,21 +17,29 @@ const node_buffer_1 = require("node:buffer");
17
17
  * @returns {Buffer} - A new Buffer of exactly `len` bytes containing:
18
18
  * 1. The value's bytes in little-endian order (least significant byte first)
19
19
  * 2. Zero padding in any remaining higher-order bytes
20
- * @throws {RangeError} - If the value requires more bytes than `len` to represent
21
- * (though this is currently not explicitly checked)
20
+ *
21
+ * @throws {RangeError} - If the length is not positive or the value is negative.
22
22
  */
23
23
  function toBytes(value, len) {
24
- // Allocate a new Buffer of the requested length, automatically zero-filled
24
+ if (len <= 0)
25
+ throw new RangeError("Length must be a positive integer");
26
+ if (value < 0)
27
+ throw new RangeError("Negative values are not supported");
28
+ if (!Number.isSafeInteger(value))
29
+ throw new RangeError("Value must be a safe integer");
30
+ // Use BigInt to correctly handle 53-bit values
31
+ let bigint = BigInt(value);
25
32
  const buf = node_buffer_1.Buffer.alloc(len);
26
- // Process each byte position from least significant to most significant
27
33
  for (let i = 0; i < len; i++) {
28
- // Store the least significant byte of the current value
29
- buf[i] = value & 0xff; // Mask to get bottom 8 bits
30
- // Right-shift the value by 8 bits to process the next byte
31
- // Note: This uses unsigned right shift (>>> would be signed)
32
- value >>= 8;
33
- // If the loop completes with value != 0, we've overflowed the buffer length,
34
- // but this isn't currently checked/handled
34
+ // Extract the least significant byte and assign to buffer
35
+ buf[i] = Number(bigint & 0xffn);
36
+ bigint >>= 8n;
37
+ // Stop early if all remaining bits are zero
38
+ if (bigint === 0n)
39
+ break;
35
40
  }
41
+ // If bigint is still non-zero, it means we overflowed the buffer length
42
+ if (bigint > 0n)
43
+ throw new RangeError("Value exceeds the maximum size for the specified length");
36
44
  return buf;
37
45
  }
@@ -3,6 +3,7 @@ import * as fsSync from "node:fs";
3
3
  import * as path from "node:path";
4
4
  import * as readline from "node:readline";
5
5
  import crypto from "node:crypto";
6
+ import * as SharedUtils from "../utils/index.js";
6
7
  import * as Xml from "../xml/index.js";
7
8
  import * as Zip from "../zip/index.js";
8
9
  import * as Utils from "./utils/index.js";
@@ -445,7 +446,7 @@ export class TemplateFs {
445
446
  const cellTags = Object.entries(cells).map(([col, value]) => {
446
447
  const colUpper = col.toUpperCase();
447
448
  const ref = `${colUpper}${rowNumber}`;
448
- return `<c r="${ref}" t="inlineStr"><is><t>${Utils.escapeXml(value)}</t></is></c>`;
449
+ return `<c r="${ref}" t="inlineStr"><is><t>${SharedUtils.escapeXml(value)}</t></is></c>`;
449
450
  }).join("");
450
451
  return `<row r="${rowNumber}">${cellTags}</row>`;
451
452
  }).join("");
@@ -1,4 +1,5 @@
1
1
  import * as fs from "node:fs/promises";
2
+ import * as SharedUtils from "../utils/index.js";
2
3
  import * as Xml from "../xml/index.js";
3
4
  import * as Zip from "../zip/index.js";
4
5
  import * as Utils from "./utils/index.js";
@@ -497,7 +498,7 @@ export class TemplateMemory {
497
498
  const cellTags = Object.entries(cells).map(([col, value]) => {
498
499
  const colUpper = col.toUpperCase();
499
500
  const ref = `${colUpper}${rowNumber}`;
500
- return `<c r="${ref}" t="inlineStr"><is><t>${Utils.escapeXml(value)}</t></is></c>`;
501
+ return `<c r="${ref}" t="inlineStr"><is><t>${SharedUtils.escapeXml(value)}</t></is></c>`;
501
502
  }).join("");
502
503
  return `<row r="${rowNumber}">${cellTags}</row>`;
503
504
  }).join("");
@@ -0,0 +1,12 @@
1
+ export function columnLetterToIndex(col) {
2
+ if (!col)
3
+ return -1;
4
+ let index = 0;
5
+ for (let i = 0; i < col.length; i++) {
6
+ const charCode = col.charCodeAt(i);
7
+ if (charCode < 65 || charCode > 90)
8
+ return -1; // не A-Z
9
+ index = index * 26 + (charCode - 64); // 'A' -> 1
10
+ }
11
+ return index;
12
+ }
@@ -4,8 +4,8 @@ export * from "./check-row.js";
4
4
  export * from "./check-rows.js";
5
5
  export * from "./check-start-row.js";
6
6
  export * from "./column-index-to-letter.js";
7
+ export * from "./column-letter-to-index.js";
7
8
  export * from "./compare-columns.js";
8
- export * from "./escape-xml.js";
9
9
  export * from "./extract-xml-declaration.js";
10
10
  export * from "./found-arrays-in-replacements.js";
11
11
  export * from "./get-by-path.js";
@@ -1,5 +1,5 @@
1
+ import { escapeXml } from "../../utils/index.js";
1
2
  import { columnIndexToLetter } from "./column-index-to-letter.js";
2
- import { escapeXml } from "./escape-xml.js";
3
3
  export function prepareRowToCells(row, rowNumber) {
4
4
  return row.map((value, colIndex) => {
5
5
  const colLetter = columnIndexToLetter(colIndex);
@@ -30,7 +30,7 @@ export function validateWorksheetXml(xml) {
30
30
  const requiredElements = [
31
31
  { name: "sheetViews", tag: "<sheetViews>" },
32
32
  { name: "sheetFormatPr", tag: "<sheetFormatPr" },
33
- { name: "sheetData", tag: "<sheetData>" },
33
+ { name: "sheetData", tag: "<sheetData" },
34
34
  ];
35
35
  for (const { name, tag } of requiredElements) {
36
36
  if (!xml.includes(tag)) {
@@ -38,16 +38,26 @@ export function validateWorksheetXml(xml) {
38
38
  }
39
39
  }
40
40
  // 3. Extract and validate sheetData
41
- const sheetDataStart = xml.indexOf("<sheetData>");
42
- const sheetDataEnd = xml.indexOf("</sheetData>");
43
- if (sheetDataStart === -1 || sheetDataEnd === -1) {
44
- return createError("Invalid sheetData structure");
41
+ // 3. Extract and validate sheetData
42
+ // Поддержка пустого <sheetData/> или обычного открывающего-закрывающего тега
43
+ const sheetDataMatch = xml.match(/<sheetData([^>]*)>/);
44
+ if (!sheetDataMatch) {
45
+ return createError("Missing sheetData element");
45
46
  }
46
- const sheetDataContent = xml.substring(sheetDataStart + 10, sheetDataEnd);
47
- const rows = sheetDataContent.split("</row>");
48
- if (rows.length < 2) {
49
- return createError("SheetData should contain at least one row");
47
+ const isSelfClosing = sheetDataMatch[1]?.includes("/"); // <sheetData/> самозакрывающийся
48
+ let sheetDataContent = "";
49
+ if (!isSelfClosing) {
50
+ const sheetDataStart = sheetDataMatch.index + sheetDataMatch[0].length;
51
+ const sheetDataEnd = xml.indexOf("</sheetData>", sheetDataStart);
52
+ if (sheetDataEnd === -1) {
53
+ return createError("Invalid sheetData structure: missing closing tag");
54
+ }
55
+ sheetDataContent = xml.substring(sheetDataStart, sheetDataEnd);
50
56
  }
57
+ // Разбиваем на строки, если есть содержимое
58
+ const rows = sheetDataContent
59
+ ? sheetDataContent.split("</row>").map(r => r.trim()).filter(r => r.length)
60
+ : [];
51
61
  // Collect information about all rows and cells
52
62
  const allRows = [];
53
63
  const allCells = [];
@@ -1,3 +1,4 @@
1
+ export * from "./escape-xml.js";
1
2
  export * from "./get-max-row-number.js";
2
3
  export * from "./is-same-buffer.js";
3
4
  export * from "./remove-sheet-by-name.js";
@@ -5,3 +6,4 @@ export * from "./remove-sheet-from-content-types.js";
5
6
  export * from "./remove-sheet-from-rels.js";
6
7
  export * from "./remove-sheet-from-workbook.js";
7
8
  export * from "./shift-cell-ref.js";
9
+ export * from "./trim-and-join-multiline.js";
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Trims whitespace from multiline strings and joins them with a specified separator.
3
+ *
4
+ * This function processes multiline text by:
5
+ * - Splitting the input string by line breaks (handles both \n and \r\n)
6
+ * - Trimming whitespace from each line
7
+ * - Optionally normalizing multiple spaces to single spaces
8
+ * - Optionally filtering out empty lines
9
+ * - Joining the processed lines with a custom separator
10
+ *
11
+ * @param options - Configuration object for processing the multiline string
12
+ * @param options.inputString - The multiline string to process
13
+ * @param options.keepEmptyLines - Whether to preserve empty lines in the output (default: false)
14
+ * @param options.normalizeSpaces - Whether to normalize multiple consecutive spaces to single spaces (default: true)
15
+ * @param options.separator - The string to use when joining lines (default: " ")
16
+ * @returns The processed string with lines joined by the separator
17
+ */
18
+ export function trimAndJoinMultiline(options) {
19
+ const { inputString, keepEmptyLines = false, normalizeSpaces = true, separator = " ", } = options;
20
+ const lines = inputString.split(/\r?\n/);
21
+ let trimmedLines = lines.map(line => line.trim());
22
+ if (normalizeSpaces) {
23
+ trimmedLines = trimmedLines.map(line => line.replace(/\s+/g, " "));
24
+ }
25
+ const filteredLines = keepEmptyLines
26
+ ? trimmedLines
27
+ : trimmedLines.filter(line => line.length > 0);
28
+ return filteredLines.join(separator);
29
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Creates a basic empty border XML node.
3
+ *
4
+ * @returns XML node representing an empty border with left, right, top, and bottom elements
5
+ */
6
+ export const border = () => ({
7
+ children: [
8
+ { tag: "left" },
9
+ { tag: "right" },
10
+ { tag: "top" },
11
+ { tag: "bottom" },
12
+ ],
13
+ tag: "border",
14
+ });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Creates a default cell formatting object.
3
+ *
4
+ * @returns Cell formatting object with default IDs
5
+ */
6
+ export const cellXf = () => ({
7
+ borderId: 0,
8
+ fillId: 0,
9
+ fontId: 0,
10
+ numFmtId: 0,
11
+ });
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Creates a basic fill XML node with no pattern.
3
+ *
4
+ * @returns XML node representing an empty pattern fill
5
+ */
6
+ export const fill = () => ({
7
+ children: [
8
+ {
9
+ attrs: { patternType: "none" },
10
+ tag: "patternFill",
11
+ },
12
+ ],
13
+ tag: "fill",
14
+ });
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Creates a default font XML node with Calibri font.
3
+ *
4
+ * @returns XML node representing a default font configuration
5
+ */
6
+ export const font = () => ({
7
+ children: [
8
+ { attrs: { val: "11" }, tag: "sz" },
9
+ { attrs: { theme: "1" }, tag: "color" },
10
+ { attrs: { val: "Calibri" }, tag: "name" },
11
+ { attrs: { val: "2" }, tag: "family" },
12
+ { attrs: { val: "minor" }, tag: "scheme" },
13
+ ],
14
+ tag: "font",
15
+ });