@cj-tech-master/excelts 4.2.3 → 5.0.0-canary.20260123012457.1fdf506

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 (84) hide show
  1. package/dist/browser/modules/csv/csv-core.d.ts +0 -9
  2. package/dist/browser/modules/csv/csv.browser.js +3 -3
  3. package/dist/browser/modules/excel/column.d.ts +5 -0
  4. package/dist/browser/modules/excel/column.js +10 -2
  5. package/dist/browser/modules/excel/row.d.ts +2 -0
  6. package/dist/browser/modules/excel/row.js +3 -1
  7. package/dist/browser/modules/excel/utils/parse-sax.d.ts +0 -3
  8. package/dist/browser/modules/excel/utils/parse-sax.js +13 -32
  9. package/dist/browser/modules/excel/utils/passthrough-manager.d.ts +77 -0
  10. package/dist/browser/modules/excel/utils/passthrough-manager.js +129 -0
  11. package/dist/browser/modules/excel/workbook.d.ts +12 -0
  12. package/dist/browser/modules/excel/workbook.js +12 -1
  13. package/dist/browser/modules/excel/worksheet.d.ts +4 -0
  14. package/dist/browser/modules/excel/worksheet.js +4 -1
  15. package/dist/browser/modules/excel/xlsx/xform/base-xform.js +68 -1
  16. package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +16 -10
  17. package/dist/browser/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.d.ts +35 -11
  18. package/dist/browser/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +271 -94
  19. package/dist/browser/modules/excel/xlsx/xform/sheet/row-xform.d.ts +1 -0
  20. package/dist/browser/modules/excel/xlsx/xform/sheet/row-xform.js +7 -1
  21. package/dist/browser/modules/excel/xlsx/xform/sheet/sheet-format-properties-xform.d.ts +1 -0
  22. package/dist/browser/modules/excel/xlsx/xform/sheet/sheet-format-properties-xform.js +9 -4
  23. package/dist/browser/modules/excel/xlsx/xform/sheet/sheet-view-xform.js +4 -2
  24. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +40 -12
  25. package/dist/browser/modules/excel/xlsx/xform/style/style-xform.d.ts +7 -0
  26. package/dist/browser/modules/excel/xlsx/xform/style/style-xform.js +26 -6
  27. package/dist/browser/modules/excel/xlsx/xform/style/styles-xform.d.ts +6 -0
  28. package/dist/browser/modules/excel/xlsx/xform/style/styles-xform.js +52 -4
  29. package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +36 -1
  30. package/dist/browser/modules/excel/xlsx/xlsx.browser.js +220 -131
  31. package/dist/browser/modules/stream/streams.browser.js +0 -3
  32. package/dist/cjs/modules/csv/csv.browser.js +3 -3
  33. package/dist/cjs/modules/excel/column.js +10 -2
  34. package/dist/cjs/modules/excel/row.js +3 -1
  35. package/dist/cjs/modules/excel/utils/parse-sax.js +13 -32
  36. package/dist/cjs/modules/excel/utils/passthrough-manager.js +133 -0
  37. package/dist/cjs/modules/excel/workbook.js +12 -1
  38. package/dist/cjs/modules/excel/worksheet.js +4 -1
  39. package/dist/cjs/modules/excel/xlsx/xform/base-xform.js +68 -1
  40. package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +16 -10
  41. package/dist/cjs/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +271 -94
  42. package/dist/cjs/modules/excel/xlsx/xform/sheet/row-xform.js +7 -1
  43. package/dist/cjs/modules/excel/xlsx/xform/sheet/sheet-format-properties-xform.js +9 -4
  44. package/dist/cjs/modules/excel/xlsx/xform/sheet/sheet-view-xform.js +4 -2
  45. package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +40 -12
  46. package/dist/cjs/modules/excel/xlsx/xform/style/style-xform.js +26 -6
  47. package/dist/cjs/modules/excel/xlsx/xform/style/styles-xform.js +52 -4
  48. package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +220 -131
  49. package/dist/cjs/modules/stream/streams.browser.js +0 -3
  50. package/dist/esm/modules/csv/csv.browser.js +3 -3
  51. package/dist/esm/modules/excel/column.js +10 -2
  52. package/dist/esm/modules/excel/row.js +3 -1
  53. package/dist/esm/modules/excel/utils/parse-sax.js +13 -32
  54. package/dist/esm/modules/excel/utils/passthrough-manager.js +129 -0
  55. package/dist/esm/modules/excel/workbook.js +12 -1
  56. package/dist/esm/modules/excel/worksheet.js +4 -1
  57. package/dist/esm/modules/excel/xlsx/xform/base-xform.js +68 -1
  58. package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +16 -10
  59. package/dist/esm/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +271 -94
  60. package/dist/esm/modules/excel/xlsx/xform/sheet/row-xform.js +7 -1
  61. package/dist/esm/modules/excel/xlsx/xform/sheet/sheet-format-properties-xform.js +9 -4
  62. package/dist/esm/modules/excel/xlsx/xform/sheet/sheet-view-xform.js +4 -2
  63. package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +40 -12
  64. package/dist/esm/modules/excel/xlsx/xform/style/style-xform.js +26 -6
  65. package/dist/esm/modules/excel/xlsx/xform/style/styles-xform.js +52 -4
  66. package/dist/esm/modules/excel/xlsx/xlsx.browser.js +220 -131
  67. package/dist/esm/modules/stream/streams.browser.js +0 -3
  68. package/dist/iife/excelts.iife.js +1009 -650
  69. package/dist/iife/excelts.iife.js.map +1 -1
  70. package/dist/iife/excelts.iife.min.js +25 -52
  71. package/dist/types/modules/csv/csv-core.d.ts +0 -9
  72. package/dist/types/modules/excel/column.d.ts +5 -0
  73. package/dist/types/modules/excel/row.d.ts +2 -0
  74. package/dist/types/modules/excel/utils/parse-sax.d.ts +0 -3
  75. package/dist/types/modules/excel/utils/passthrough-manager.d.ts +77 -0
  76. package/dist/types/modules/excel/workbook.d.ts +12 -0
  77. package/dist/types/modules/excel/worksheet.d.ts +4 -0
  78. package/dist/types/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.d.ts +35 -11
  79. package/dist/types/modules/excel/xlsx/xform/sheet/row-xform.d.ts +1 -0
  80. package/dist/types/modules/excel/xlsx/xform/sheet/sheet-format-properties-xform.d.ts +1 -0
  81. package/dist/types/modules/excel/xlsx/xform/style/style-xform.d.ts +7 -0
  82. package/dist/types/modules/excel/xlsx/xform/style/styles-xform.d.ts +6 -0
  83. package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +36 -1
  84. package/package.json +15 -15
@@ -142,12 +142,6 @@ const XML_ENTITIES = {
142
142
  quot: '"',
143
143
  apos: "'"
144
144
  };
145
- // HAN CELL namespace prefix normalization
146
- // HAN CELL uses non-standard namespace prefixes (ep:, cp:, dc:, etc.)
147
- // The x: prefix for spreadsheetml is detected dynamically from xmlns declarations
148
- // See: https://github.com/exceljs/exceljs/issues/3014
149
- const HAN_CELL_PREFIXES = /^(ep|cp|dc|dcterms|dcmitype|vt):/;
150
- const SPREADSHEETML_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
151
145
  // ============================================================================
152
146
  // Parser States
153
147
  // ============================================================================
@@ -208,8 +202,6 @@ export class SaxesParser {
208
202
  this.chunkPosition = 0;
209
203
  // Entity storage
210
204
  this.ENTITIES = { ...XML_ENTITIES };
211
- // HAN CELL compatibility: spreadsheetml namespace prefix (e.g., "x")
212
- this.nsPrefix = null;
213
205
  this.trackPosition = opt?.position !== false;
214
206
  this.fileName = opt?.fileName;
215
207
  this.fragment = opt?.fragment ?? false;
@@ -244,14 +236,6 @@ export class SaxesParser {
244
236
  this.chunk = "";
245
237
  this.i = 0;
246
238
  this.prevI = 0;
247
- this.nsPrefix = null;
248
- }
249
- // Strip HAN CELL namespace prefixes from element names
250
- stripNsPrefix(name) {
251
- const n = name.replace(HAN_CELL_PREFIXES, "");
252
- return this.nsPrefix && n.startsWith(this.nsPrefix + ":")
253
- ? n.slice(this.nsPrefix.length + 1)
254
- : n;
255
239
  }
256
240
  on(name, handler) {
257
241
  switch (name) {
@@ -667,8 +651,9 @@ export class SaxesParser {
667
651
  this.name += charFromCode(c);
668
652
  return;
669
653
  }
654
+ // Tag name complete
670
655
  this.tag = {
671
- name: this.stripNsPrefix(this.name),
656
+ name: this.name,
672
657
  attributes: Object.create(null),
673
658
  isSelfClosing: false
674
659
  };
@@ -1107,7 +1092,11 @@ export class SaxesParser {
1107
1092
  openTag() {
1108
1093
  const tag = this.tag;
1109
1094
  tag.isSelfClosing = false;
1110
- this.processAttributes(tag);
1095
+ // Copy attributes from list to object
1096
+ for (const { name, value } of this.attribList) {
1097
+ tag.attributes[name] = value;
1098
+ }
1099
+ this.attribList = [];
1111
1100
  this.openTagHandler?.(tag);
1112
1101
  this.tags.push(tag);
1113
1102
  this.name = "";
@@ -1116,7 +1105,11 @@ export class SaxesParser {
1116
1105
  openSelfClosingTag() {
1117
1106
  const tag = this.tag;
1118
1107
  tag.isSelfClosing = true;
1119
- this.processAttributes(tag);
1108
+ // Copy attributes from list to object
1109
+ for (const { name, value } of this.attribList) {
1110
+ tag.attributes[name] = value;
1111
+ }
1112
+ this.attribList = [];
1120
1113
  this.openTagHandler?.(tag);
1121
1114
  this.closeTagHandler?.(tag);
1122
1115
  if (this.tags.length === 0) {
@@ -1125,20 +1118,8 @@ export class SaxesParser {
1125
1118
  this.name = "";
1126
1119
  this.state = S_TEXT;
1127
1120
  }
1128
- // Process attributes and detect spreadsheetml namespace prefix
1129
- processAttributes(tag) {
1130
- for (const { name, value } of this.attribList) {
1131
- tag.attributes[name] = value;
1132
- if (name.startsWith("xmlns:") && value === SPREADSHEETML_NS) {
1133
- this.nsPrefix = name.slice(6);
1134
- tag.name = this.stripNsPrefix(tag.name);
1135
- }
1136
- }
1137
- this.attribList = [];
1138
- }
1139
1121
  closeTag() {
1140
- const { tags } = this;
1141
- const name = this.stripNsPrefix(this.name);
1122
+ const { tags, name } = this;
1142
1123
  this.state = S_TEXT;
1143
1124
  this.name = "";
1144
1125
  if (name === "") {
@@ -0,0 +1,129 @@
1
+ /**
2
+ * PassthroughManager - Manages passthrough files for round-trip preservation
3
+ *
4
+ * This module handles files that are not fully parsed by the library but need to be
5
+ * preserved during read/write cycles (e.g., charts, sparklines, slicers).
6
+ */
7
+ // Pre-compiled regex patterns for content type detection (performance optimization)
8
+ const chartXmlRegex = /^xl\/charts\/chart\d+\.xml$/;
9
+ const chartStyleXmlRegex = /^xl\/charts\/style\d+\.xml$/;
10
+ const chartColorsXmlRegex = /^xl\/charts\/colors\d+\.xml$/;
11
+ /**
12
+ * Content type definitions for passthrough files
13
+ */
14
+ const PASSTHROUGH_CONTENT_TYPES = new Map([
15
+ [chartXmlRegex, "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"],
16
+ [chartStyleXmlRegex, "application/vnd.ms-office.chartstyle+xml"],
17
+ [chartColorsXmlRegex, "application/vnd.ms-office.chartcolorstyle+xml"]
18
+ ]);
19
+ /**
20
+ * Passthrough path prefixes that should be preserved
21
+ */
22
+ const PASSTHROUGH_PREFIXES = ["xl/charts/"];
23
+ /**
24
+ * PassthroughManager handles storage and retrieval of passthrough files
25
+ * that need to be preserved during Excel read/write cycles.
26
+ */
27
+ export class PassthroughManager {
28
+ constructor() {
29
+ this.files = new Map();
30
+ }
31
+ /**
32
+ * Check if a path should be treated as passthrough
33
+ */
34
+ static isPassthroughPath(path) {
35
+ return PASSTHROUGH_PREFIXES.some(prefix => path.startsWith(prefix));
36
+ }
37
+ /**
38
+ * Get the content type for a passthrough file path
39
+ * @returns Content type string or undefined if unknown
40
+ */
41
+ static getContentType(path) {
42
+ // Chart relationships are handled by Default extension="rels"
43
+ if (path.startsWith("xl/charts/_rels/")) {
44
+ return undefined;
45
+ }
46
+ for (const [regex, contentType] of PASSTHROUGH_CONTENT_TYPES) {
47
+ if (regex.test(path)) {
48
+ return contentType;
49
+ }
50
+ }
51
+ return undefined;
52
+ }
53
+ /**
54
+ * Add a file to passthrough storage
55
+ */
56
+ add(path, data) {
57
+ this.files.set(path, data);
58
+ }
59
+ /**
60
+ * Get a file from passthrough storage
61
+ */
62
+ get(path) {
63
+ return this.files.get(path);
64
+ }
65
+ /**
66
+ * Check if a file exists in passthrough storage
67
+ */
68
+ has(path) {
69
+ return this.files.has(path);
70
+ }
71
+ /**
72
+ * Get all stored paths
73
+ */
74
+ getPaths() {
75
+ return [...this.files.keys()];
76
+ }
77
+ /**
78
+ * Get all files as a record (for serialization)
79
+ */
80
+ toRecord() {
81
+ const record = {};
82
+ for (const [path, data] of this.files) {
83
+ record[path] = data;
84
+ }
85
+ return record;
86
+ }
87
+ /**
88
+ * Load files from a record (for deserialization)
89
+ */
90
+ fromRecord(record) {
91
+ this.files.clear();
92
+ for (const [path, data] of Object.entries(record)) {
93
+ this.files.set(path, data);
94
+ }
95
+ }
96
+ /**
97
+ * Get content types for all stored files that have known types
98
+ */
99
+ getContentTypes() {
100
+ const contentTypes = [];
101
+ for (const path of this.files.keys()) {
102
+ const contentType = PassthroughManager.getContentType(path);
103
+ if (contentType) {
104
+ contentTypes.push({ partName: path, contentType });
105
+ }
106
+ }
107
+ return contentTypes;
108
+ }
109
+ /**
110
+ * Write all passthrough files to a ZIP writer
111
+ */
112
+ writeToZip(zip) {
113
+ for (const [path, data] of this.files) {
114
+ zip.append(data, { name: path });
115
+ }
116
+ }
117
+ /**
118
+ * Clear all stored files
119
+ */
120
+ clear() {
121
+ this.files.clear();
122
+ }
123
+ /**
124
+ * Get the number of stored files
125
+ */
126
+ get size() {
127
+ return this.files.size;
128
+ }
129
+ }
@@ -38,6 +38,8 @@ class Workbook {
38
38
  this.views = [];
39
39
  this.media = [];
40
40
  this.pivotTables = [];
41
+ this._passthrough = {};
42
+ this._rawDrawings = {};
41
43
  this._definedNames = new DefinedNames();
42
44
  }
43
45
  // ===========================================================================
@@ -251,7 +253,10 @@ class Workbook {
251
253
  themes: this._themes,
252
254
  media: this.media,
253
255
  pivotTables: this.pivotTables,
254
- calcProperties: this.calcProperties
256
+ calcProperties: this.calcProperties,
257
+ passthrough: this._passthrough,
258
+ rawDrawings: this._rawDrawings,
259
+ defaultFont: this._defaultFont
255
260
  };
256
261
  }
257
262
  set model(value) {
@@ -292,6 +297,12 @@ class Workbook {
292
297
  // Handle pivot tables - either newly created or loaded from file
293
298
  // Loaded pivot tables come from loadedPivotTables after reconciliation
294
299
  this.pivotTables = value.pivotTables || value.loadedPivotTables || [];
300
+ // Preserve passthrough files (charts, etc.) for round-trip preservation
301
+ this._passthrough = value.passthrough || {};
302
+ // Preserve raw drawing data for drawings with chart references
303
+ this._rawDrawings = value.rawDrawings || {};
304
+ // Preserve default font for round-trip fidelity
305
+ this._defaultFont = value.defaultFont;
295
306
  }
296
307
  }
297
308
  // ===========================================================================
@@ -897,7 +897,8 @@ class Worksheet {
897
897
  tables: Object.values(this.tables).map(table => table.model),
898
898
  pivotTables: this.pivotTables,
899
899
  conditionalFormattings: this.conditionalFormattings,
900
- formControls: this.formControls.map(fc => fc.model)
900
+ formControls: this.formControls.map(fc => fc.model),
901
+ drawing: this._drawing
901
902
  };
902
903
  // =================================================
903
904
  // columns
@@ -965,6 +966,8 @@ class Worksheet {
965
966
  this.conditionalFormattings = value.conditionalFormattings;
966
967
  // Form controls are currently write-only (not parsed from XLSX)
967
968
  this.formControls = [];
969
+ // Preserve loaded drawing data (charts, etc.)
970
+ this._drawing = value.drawing;
968
971
  }
969
972
  }
970
973
  export { Worksheet };
@@ -1,5 +1,41 @@
1
1
  import { parseSax } from "../../utils/parse-sax.js";
2
2
  import { XmlStream } from "../../utils/xml-stream.js";
3
+ // HAN CELL namespace prefix normalization
4
+ // HAN CELL uses non-standard namespace prefixes (ep:, cp:, dc:, etc.)
5
+ // See: https://github.com/exceljs/exceljs/issues/3014
6
+ const HAN_CELL_PREFIXES = new Set(["ep", "cp", "dc", "dcterms", "dcmitype", "vt"]);
7
+ const SPREADSHEETML_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
8
+ // Detect HAN CELL mode from first tag. Returns:
9
+ // - undefined: normal file (no prefix handling needed)
10
+ // - null: HAN CELL file without spreadsheetml prefix (uses static prefixes only)
11
+ // - string: HAN CELL file with spreadsheetml prefix (e.g., "x")
12
+ function detectHanCellPrefix(tagName, attrs) {
13
+ for (const key in attrs) {
14
+ if (key.length > 6 && key.startsWith("xmlns:")) {
15
+ const prefix = key.slice(6);
16
+ // Check for spreadsheetml namespace prefix
17
+ if (attrs[key] === SPREADSHEETML_NS) {
18
+ return prefix;
19
+ }
20
+ // Check if xmlns declares a known HAN CELL prefix (e.g., xmlns:dc, xmlns:dcterms)
21
+ if (HAN_CELL_PREFIXES.has(prefix)) {
22
+ return null;
23
+ }
24
+ }
25
+ }
26
+ // Check if tag name has a known static prefix
27
+ const i = tagName.indexOf(":");
28
+ return i !== -1 && HAN_CELL_PREFIXES.has(tagName.slice(0, i)) ? null : undefined;
29
+ }
30
+ // Strip known namespace prefix from element name
31
+ function stripPrefix(name, nsPrefix) {
32
+ const i = name.indexOf(":");
33
+ if (i === -1) {
34
+ return name;
35
+ }
36
+ const p = name.slice(0, i);
37
+ return p === nsPrefix || HAN_CELL_PREFIXES.has(p) ? name.slice(i + 1) : name;
38
+ }
3
39
  // Base class for Xforms
4
40
  class BaseXform {
5
41
  // ============================================================
@@ -51,19 +87,50 @@ class BaseXform {
51
87
  // destroys the underlying stream and can surface as AbortError (ABORT_ERR).
52
88
  let done = false;
53
89
  let finalModel;
90
+ // HAN CELL compatibility: 0 = not checked, 1 = normal file, 2 = HAN CELL file
91
+ let nsMode = 0;
92
+ let nsPrefix = null;
54
93
  for await (const events of saxParser) {
55
94
  if (done) {
56
95
  continue;
57
96
  }
58
97
  for (const { eventType, value } of events) {
59
98
  if (eventType === "opentag") {
99
+ // Fast path for normal Excel files (majority case)
100
+ if (nsMode === 1) {
101
+ this.parseOpen(value);
102
+ continue;
103
+ }
104
+ // First tag - detect mode
105
+ if (nsMode === 0) {
106
+ const prefix = detectHanCellPrefix(value.name, value.attributes);
107
+ if (prefix === undefined) {
108
+ nsMode = 1;
109
+ this.parseOpen(value);
110
+ continue;
111
+ }
112
+ nsMode = 2;
113
+ nsPrefix = prefix;
114
+ }
115
+ // HAN CELL mode - strip prefix
116
+ value.name = stripPrefix(value.name, nsPrefix);
60
117
  this.parseOpen(value);
61
118
  }
62
119
  else if (eventType === "text") {
63
120
  this.parseText(value);
64
121
  }
65
122
  else if (eventType === "closetag") {
66
- if (!this.parseClose(value.name)) {
123
+ // Fast path for normal files
124
+ if (nsMode === 1) {
125
+ if (!this.parseClose(value.name)) {
126
+ done = true;
127
+ finalModel = this.model;
128
+ break;
129
+ }
130
+ continue;
131
+ }
132
+ // HAN CELL mode - strip prefix
133
+ if (!this.parseClose(stripPrefix(value.name, nsPrefix))) {
67
134
  done = true;
68
135
  finalModel = this.model;
69
136
  break;
@@ -93,11 +93,16 @@ class ContentTypesXform extends BaseXform {
93
93
  });
94
94
  });
95
95
  }
96
- if (model.commentRefs) {
96
+ // VML extension is needed for comments or form controls
97
+ const hasComments = model.commentRefs && model.commentRefs.length > 0;
98
+ const hasFormControls = model.formControlRefs && model.formControlRefs.length > 0;
99
+ if (hasComments || hasFormControls) {
97
100
  xmlStream.leafNode("Default", {
98
101
  Extension: "vml",
99
102
  ContentType: "application/vnd.openxmlformats-officedocument.vmlDrawing"
100
103
  });
104
+ }
105
+ if (hasComments) {
101
106
  model.commentRefs.forEach(({ commentName }) => {
102
107
  xmlStream.leafNode("Override", {
103
108
  PartName: toContentTypesPartName(commentsPathFromName(commentName)),
@@ -105,15 +110,7 @@ class ContentTypesXform extends BaseXform {
105
110
  });
106
111
  });
107
112
  }
108
- // Add form control (ctrlProps) content types
109
- if (model.formControlRefs) {
110
- // Ensure vml extension is declared (may already be declared for comments)
111
- if (!model.commentRefs) {
112
- xmlStream.leafNode("Default", {
113
- Extension: "vml",
114
- ContentType: "application/vnd.openxmlformats-officedocument.vmlDrawing"
115
- });
116
- }
113
+ if (hasFormControls) {
117
114
  for (const ctrlPropId of model.formControlRefs) {
118
115
  xmlStream.leafNode("Override", {
119
116
  PartName: toContentTypesPartName(ctrlPropPath(ctrlPropId)),
@@ -121,6 +118,15 @@ class ContentTypesXform extends BaseXform {
121
118
  });
122
119
  }
123
120
  }
121
+ // Add passthrough content types (charts, etc.)
122
+ if (model.passthroughContentTypes) {
123
+ for (const { partName, contentType } of model.passthroughContentTypes) {
124
+ xmlStream.leafNode("Override", {
125
+ PartName: toContentTypesPartName(partName),
126
+ ContentType: contentType
127
+ });
128
+ }
129
+ }
124
130
  xmlStream.leafNode("Override", {
125
131
  PartName: toContentTypesPartName(OOXML_PATHS.docPropsCore),
126
132
  ContentType: "application/vnd.openxmlformats-package.core-properties+xml"