@microsoft/connected-workbooks 3.3.1-beta → 3.4.0-beta
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.
- package/README.md +3 -3
- package/dist/types.d.ts +2 -1
- package/dist/utils/constants.js +94 -47
- package/dist/utils/documentUtils.js +2 -2
- package/dist/utils/gridUtils.js +4 -4
- package/dist/utils/mashupDocumentParser.js +1 -1
- package/dist/utils/pqUtils.js +3 -3
- package/dist/utils/tableUtils.js +11 -4
- package/dist/utils/xmlInnerPartsUtils.js +294 -31
- package/dist/utils/xmlPartsUtils.js +93 -19
- package/dist/workbookManager.js +3 -3
- package/dist/workbookTemplate.js +2 -1
- package/package.json +5 -3
- package/dist/src/generators.js +0 -15
- package/dist/src/types.js +0 -28
- package/dist/src/utils/arrayUtils.js +0 -51
- package/dist/src/utils/constants.js +0 -166
- package/dist/src/utils/documentUtils.js +0 -167
- package/dist/src/utils/gridUtils.js +0 -103
- package/dist/src/utils/htmlUtils.js +0 -19
- package/dist/src/utils/index.js +0 -24
- package/dist/src/utils/mashupDocumentParser.js +0 -188
- package/dist/src/utils/pqUtils.js +0 -194
- package/dist/src/utils/tableUtils.js +0 -233
- package/dist/src/utils/xmlInnerPartsUtils.js +0 -400
- package/dist/src/utils/xmlPartsUtils.js +0 -174
- package/dist/src/workbookTemplate.js +0 -8
- package/dist/tests/arrayUtils.test.js +0 -66
- package/dist/tests/documentUtils.test.js +0 -70
- package/dist/tests/gridUtils.test.js +0 -214
- package/dist/tests/htmlUtils.test.js +0 -111
- package/dist/tests/mashupDocumentParser.test.js +0 -113
- package/dist/tests/mocks/PqMock.js +0 -7
- package/dist/tests/mocks/index.js +0 -24
- package/dist/tests/mocks/section1mSimpleQueryMock.js +0 -8
- package/dist/tests/mocks/xmlMocks.js +0 -14
- package/dist/tests/tableUtils.test.js +0 -70
- package/dist/tests/workbookQueryTemplate.test.js +0 -218
- package/dist/tests/workbookTableTemplate.test.js +0 -126
- package/dist/tests/xmlInnerPartsUtils.test.js +0 -133
|
@@ -45,6 +45,23 @@ var types_1 = require("../types");
|
|
|
45
45
|
var constants_1 = require("./constants");
|
|
46
46
|
var documentUtils_1 = __importDefault(require("./documentUtils"));
|
|
47
47
|
var xmldom_qsa_1 = require("xmldom-qsa");
|
|
48
|
+
/**
|
|
49
|
+
* Helper function to check for XML parser errors without using querySelector
|
|
50
|
+
* @param doc - The parsed XML document
|
|
51
|
+
* @param context - Context string for error message
|
|
52
|
+
* @throws {Error} If parser error is detected
|
|
53
|
+
*/
|
|
54
|
+
var checkParserError = function (doc, context) {
|
|
55
|
+
if (!doc || !doc.documentElement) {
|
|
56
|
+
throw new Error("".concat(context, ": ").concat(constants_1.Errors.xmlParse));
|
|
57
|
+
}
|
|
58
|
+
// Check for parsererror elements using getElementsByTagName
|
|
59
|
+
var errorElements = doc.getElementsByTagName("parsererror");
|
|
60
|
+
if (errorElements && errorElements.length > 0) {
|
|
61
|
+
var errorText = errorElements[0].textContent || "Unknown parser error";
|
|
62
|
+
throw new Error("".concat(context, ": ").concat(errorText));
|
|
63
|
+
}
|
|
64
|
+
};
|
|
48
65
|
var updateDocProps = function (zip, docProps) {
|
|
49
66
|
if (docProps === void 0) { docProps = {}; }
|
|
50
67
|
return __awaiter(void 0, void 0, void 0, function () {
|
|
@@ -76,33 +93,61 @@ var updateDocProps = function (zip, docProps) {
|
|
|
76
93
|
});
|
|
77
94
|
});
|
|
78
95
|
};
|
|
96
|
+
var removeLabelInfoRelationship = function (doc, relationships) {
|
|
97
|
+
// Find and remove LabelInfo.xml relationship
|
|
98
|
+
var relationshipElements = doc.getElementsByTagName(constants_1.element.relationship);
|
|
99
|
+
for (var i = 0; i < relationshipElements.length; i++) {
|
|
100
|
+
var rel = relationshipElements[i];
|
|
101
|
+
if (rel.getAttribute(constants_1.elementAttributes.target) === constants_1.labelInfoXmlPath) {
|
|
102
|
+
relationships.removeChild(rel);
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
var updateRelationshipIds = function (doc) {
|
|
108
|
+
// Update relationship IDs
|
|
109
|
+
var relationshipElements = doc.getElementsByTagName(constants_1.element.relationship);
|
|
110
|
+
for (var i = 0; i < relationshipElements.length; i++) {
|
|
111
|
+
var rel = relationshipElements[i];
|
|
112
|
+
var target = rel.getAttribute(constants_1.elementAttributes.target);
|
|
113
|
+
if (target === constants_1.workbookXmlPath) {
|
|
114
|
+
rel.setAttribute(constants_1.elementAttributes.Id, constants_1.elementAttributes.relationId1);
|
|
115
|
+
}
|
|
116
|
+
else if (target === constants_1.docPropsCoreXmlPath) {
|
|
117
|
+
rel.setAttribute(constants_1.elementAttributes.Id, constants_1.elementAttributes.relationId2);
|
|
118
|
+
}
|
|
119
|
+
else if (target === constants_1.docPropsAppXmlPath) {
|
|
120
|
+
rel.setAttribute(constants_1.elementAttributes.Id, constants_1.elementAttributes.relationId3);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
};
|
|
79
124
|
var clearLabelInfo = function (zip) { return __awaiter(void 0, void 0, void 0, function () {
|
|
80
|
-
var relsString, parser, doc,
|
|
81
|
-
var _a
|
|
82
|
-
return __generator(this, function (
|
|
83
|
-
switch (
|
|
125
|
+
var relsString, parser, doc, relationshipsList, relationships, serializer, newDoc;
|
|
126
|
+
var _a;
|
|
127
|
+
return __generator(this, function (_b) {
|
|
128
|
+
switch (_b.label) {
|
|
84
129
|
case 0:
|
|
85
130
|
// remove docMetadata folder that contains only LabelInfo.xml in template file.
|
|
86
131
|
zip.remove(constants_1.docMetadataXmlPath);
|
|
87
132
|
return [4 /*yield*/, ((_a = zip.file(constants_1.relsXmlPath)) === null || _a === void 0 ? void 0 : _a.async(constants_1.textResultType))];
|
|
88
133
|
case 1:
|
|
89
|
-
relsString =
|
|
134
|
+
relsString = _b.sent();
|
|
90
135
|
if (relsString === undefined) {
|
|
91
|
-
throw new Error(constants_1.
|
|
136
|
+
throw new Error(constants_1.Errors.relsNotFound);
|
|
92
137
|
}
|
|
93
138
|
parser = new xmldom_qsa_1.DOMParser();
|
|
94
139
|
doc = parser.parseFromString(relsString, constants_1.xmlTextResultType);
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
140
|
+
checkParserError(doc, constants_1.Errors.relsParse);
|
|
141
|
+
relationshipsList = doc.getElementsByTagName(constants_1.element.relationships);
|
|
142
|
+
if (!relationshipsList || relationshipsList.length === 0) {
|
|
143
|
+
throw new Error(constants_1.Errors.relationship);
|
|
98
144
|
}
|
|
99
|
-
|
|
100
|
-
if (
|
|
101
|
-
|
|
145
|
+
relationships = relationshipsList[0];
|
|
146
|
+
if (!relationships) {
|
|
147
|
+
throw new Error(constants_1.Errors.relationship);
|
|
102
148
|
}
|
|
103
|
-
(
|
|
104
|
-
(
|
|
105
|
-
(_d = relationships.querySelector('Relationship[Target="docProps/app.xml"]')) === null || _d === void 0 ? void 0 : _d.setAttribute("Id", "rId3");
|
|
149
|
+
removeLabelInfoRelationship(doc, relationships);
|
|
150
|
+
updateRelationshipIds(doc);
|
|
106
151
|
serializer = new xmldom_qsa_1.XMLSerializer();
|
|
107
152
|
newDoc = serializer.serializeToString(doc);
|
|
108
153
|
zip.file(constants_1.relsXmlPath, newDoc);
|
|
@@ -116,6 +161,7 @@ var updateConnections = function (connectionsXmlString, queryName, refreshOnOpen
|
|
|
116
161
|
var serializer = new xmldom_qsa_1.XMLSerializer();
|
|
117
162
|
var refreshOnLoadValue = refreshOnOpen ? constants_1.trueValue : constants_1.falseValue;
|
|
118
163
|
var connectionsDoc = parser.parseFromString(connectionsXmlString, constants_1.xmlTextResultType);
|
|
164
|
+
checkParserError(connectionsDoc, constants_1.Errors.connectionsParse);
|
|
119
165
|
var connectionsProperties = connectionsDoc.getElementsByTagName(constants_1.element.databaseProperties);
|
|
120
166
|
var dbPr = connectionsProperties[0];
|
|
121
167
|
dbPr.setAttribute(constants_1.elementAttributes.refreshOnLoad, refreshOnLoadValue);
|
|
@@ -127,7 +173,7 @@ var updateConnections = function (connectionsXmlString, queryName, refreshOnOpen
|
|
|
127
173
|
var connectionId = (_c = dbPr.parentNode) === null || _c === void 0 ? void 0 : _c.getAttribute(constants_1.elementAttributes.id);
|
|
128
174
|
var connectionXmlFileString = serializer.serializeToString(connectionsDoc);
|
|
129
175
|
if (connectionId === null) {
|
|
130
|
-
throw new Error(constants_1.
|
|
176
|
+
throw new Error(constants_1.Errors.connectionsNotFound);
|
|
131
177
|
}
|
|
132
178
|
return { connectionId: connectionId, connectionXmlFileString: connectionXmlFileString };
|
|
133
179
|
};
|
|
@@ -135,9 +181,10 @@ var updateSharedStrings = function (sharedStringsXmlString, queryName) {
|
|
|
135
181
|
var parser = new xmldom_qsa_1.DOMParser();
|
|
136
182
|
var serializer = new xmldom_qsa_1.XMLSerializer();
|
|
137
183
|
var sharedStringsDoc = parser.parseFromString(sharedStringsXmlString, constants_1.xmlTextResultType);
|
|
184
|
+
checkParserError(sharedStringsDoc, constants_1.Errors.sharedStringsParse);
|
|
138
185
|
var sharedStringsTable = sharedStringsDoc.getElementsByTagName(constants_1.element.sharedStringTable)[0];
|
|
139
186
|
if (!sharedStringsTable) {
|
|
140
|
-
throw new Error(constants_1.
|
|
187
|
+
throw new Error(constants_1.Errors.sharedStringsNotFound);
|
|
141
188
|
}
|
|
142
189
|
var textElementCollection = sharedStringsDoc.getElementsByTagName(constants_1.element.text);
|
|
143
190
|
var textElement = null;
|
|
@@ -175,6 +222,7 @@ var updateWorksheet = function (sheetsXmlString, sharedStringIndex) {
|
|
|
175
222
|
var parser = new xmldom_qsa_1.DOMParser();
|
|
176
223
|
var serializer = new xmldom_qsa_1.XMLSerializer();
|
|
177
224
|
var sheetsDoc = parser.parseFromString(sheetsXmlString, constants_1.xmlTextResultType);
|
|
225
|
+
checkParserError(sheetsDoc, constants_1.Errors.worksheetParse);
|
|
178
226
|
sheetsDoc.getElementsByTagName(constants_1.element.cellValue)[0].innerHTML = sharedStringIndex.toString();
|
|
179
227
|
var newSheet = serializer.serializeToString(sheetsDoc);
|
|
180
228
|
return newSheet;
|
|
@@ -240,7 +288,7 @@ var updatePivotTablesandQueryTables = function (zip, queryName, refreshOnOpen, c
|
|
|
240
288
|
}
|
|
241
289
|
});
|
|
242
290
|
if (!found) {
|
|
243
|
-
throw new Error(constants_1.
|
|
291
|
+
throw new Error(constants_1.Errors.queryAndPivotTableNotFound);
|
|
244
292
|
}
|
|
245
293
|
return [2 /*return*/];
|
|
246
294
|
}
|
|
@@ -252,6 +300,7 @@ var updateQueryTable = function (tableXmlString, connectionId, refreshOnOpen) {
|
|
|
252
300
|
var parser = new xmldom_qsa_1.DOMParser();
|
|
253
301
|
var serializer = new xmldom_qsa_1.XMLSerializer();
|
|
254
302
|
var queryTableDoc = parser.parseFromString(tableXmlString, constants_1.xmlTextResultType);
|
|
303
|
+
checkParserError(queryTableDoc, constants_1.Errors.queryTableParse);
|
|
255
304
|
var queryTable = queryTableDoc.getElementsByTagName(constants_1.element.queryTable)[0];
|
|
256
305
|
var newQueryTable = constants_1.emptyValue;
|
|
257
306
|
if (queryTable.getAttribute(constants_1.elementAttributes.connectionId) == connectionId) {
|
|
@@ -267,6 +316,7 @@ var updatePivotTable = function (tableXmlString, connectionId, refreshOnOpen) {
|
|
|
267
316
|
var parser = new xmldom_qsa_1.DOMParser();
|
|
268
317
|
var serializer = new xmldom_qsa_1.XMLSerializer();
|
|
269
318
|
var pivotCacheDoc = parser.parseFromString(tableXmlString, constants_1.xmlTextResultType);
|
|
319
|
+
checkParserError(pivotCacheDoc, constants_1.Errors.pivotTableParse);
|
|
270
320
|
var cacheSource = pivotCacheDoc.getElementsByTagName(constants_1.element.cacheSource)[0];
|
|
271
321
|
var newPivotTable = constants_1.emptyValue;
|
|
272
322
|
if (cacheSource.getAttribute(constants_1.elementAttributes.connectionId) == connectionId) {
|
|
@@ -282,25 +332,30 @@ var updatePivotTable = function (tableXmlString, connectionId, refreshOnOpen) {
|
|
|
282
332
|
*/
|
|
283
333
|
function getSheetPathFromXlRelId(zip, rId) {
|
|
284
334
|
return __awaiter(this, void 0, void 0, function () {
|
|
285
|
-
var relsFile, relsString, relsDoc,
|
|
335
|
+
var relsFile, relsString, relsDoc, relationships, target, i, el;
|
|
286
336
|
return __generator(this, function (_a) {
|
|
287
337
|
switch (_a.label) {
|
|
288
338
|
case 0:
|
|
289
339
|
relsFile = zip.file(constants_1.workbookRelsXmlPath);
|
|
290
340
|
if (!relsFile) {
|
|
291
|
-
throw new Error(constants_1.
|
|
341
|
+
throw new Error(constants_1.Errors.xlRelsNotFound);
|
|
292
342
|
}
|
|
293
343
|
return [4 /*yield*/, relsFile.async(constants_1.textResultType)];
|
|
294
344
|
case 1:
|
|
295
345
|
relsString = _a.sent();
|
|
296
346
|
relsDoc = new xmldom_qsa_1.DOMParser().parseFromString(relsString, constants_1.xmlTextResultType);
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
347
|
+
checkParserError(relsDoc, constants_1.Errors.workbookRelsParse);
|
|
348
|
+
relationships = relsDoc.getElementsByTagName("Relationship");
|
|
349
|
+
target = null;
|
|
350
|
+
for (i = 0; i < relationships.length; i++) {
|
|
351
|
+
el = relationships[i];
|
|
352
|
+
if (el && el.getAttribute && el.getAttribute("Id") === rId) {
|
|
353
|
+
target = el.getAttribute(constants_1.elementAttributes.target);
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
300
356
|
}
|
|
301
|
-
target = relationship.getAttribute(constants_1.elementAttributes.target);
|
|
302
357
|
if (!target) {
|
|
303
|
-
throw new Error("
|
|
358
|
+
throw new Error("Relationship not found or missing Target for Id: ".concat(rId));
|
|
304
359
|
}
|
|
305
360
|
return [2 /*return*/, target];
|
|
306
361
|
}
|
|
@@ -317,10 +372,11 @@ var getSheetPathByNameFromZip = function (zip, sheetName) { return __awaiter(voi
|
|
|
317
372
|
case 1:
|
|
318
373
|
workbookXmlString = _b.sent();
|
|
319
374
|
if (!workbookXmlString) {
|
|
320
|
-
throw new Error(constants_1.
|
|
375
|
+
throw new Error(constants_1.Errors.workbookNotFound);
|
|
321
376
|
}
|
|
322
377
|
parser = new xmldom_qsa_1.DOMParser();
|
|
323
378
|
doc = parser.parseFromString(workbookXmlString, constants_1.xmlTextResultType);
|
|
379
|
+
checkParserError(doc, constants_1.Errors.workbookParse);
|
|
324
380
|
sheetElements = doc.getElementsByTagName(constants_1.element.sheet);
|
|
325
381
|
for (i = 0; i < sheetElements.length; i++) {
|
|
326
382
|
if (sheetElements[i].getAttribute(constants_1.elementAttributes.name) === sheetName) {
|
|
@@ -344,14 +400,15 @@ var getReferenceFromTable = function (zip, tablePath) { return __awaiter(void 0,
|
|
|
344
400
|
case 1:
|
|
345
401
|
tableXmlString = _c.sent();
|
|
346
402
|
if (!tableXmlString) {
|
|
347
|
-
throw new Error(constants_1.
|
|
403
|
+
throw new Error(constants_1.Errors.workbookNotFound);
|
|
348
404
|
}
|
|
349
405
|
parser = new xmldom_qsa_1.DOMParser();
|
|
350
406
|
doc = parser.parseFromString(tableXmlString, constants_1.xmlTextResultType);
|
|
407
|
+
checkParserError(doc, constants_1.Errors.tableParse);
|
|
351
408
|
tableElements = doc.getElementsByTagName(constants_1.element.table);
|
|
352
409
|
reference = (_b = tableElements[0]) === null || _b === void 0 ? void 0 : _b.getAttribute(constants_1.elementAttributes.reference);
|
|
353
410
|
if (!reference) {
|
|
354
|
-
throw new Error(constants_1.
|
|
411
|
+
throw new Error(constants_1.Errors.tableReferenceNotFound);
|
|
355
412
|
}
|
|
356
413
|
return [2 /*return*/, reference.split(":")[0]]; // Return the start cell reference (e.g., "A1" from "A1:B10")
|
|
357
414
|
}
|
|
@@ -362,9 +419,9 @@ var findTablePathFromZip = function (zip, targetTableName) { return __awaiter(vo
|
|
|
362
419
|
return __generator(this, function (_b) {
|
|
363
420
|
switch (_b.label) {
|
|
364
421
|
case 0:
|
|
365
|
-
tablesFolder = zip.folder(
|
|
422
|
+
tablesFolder = zip.folder(constants_1.tablesFolderPath);
|
|
366
423
|
if (!tablesFolder)
|
|
367
|
-
return [2 /*return*/,
|
|
424
|
+
return [2 /*return*/, constants_1.emptyValue];
|
|
368
425
|
tableFilePromises = [];
|
|
369
426
|
tablesFolder.forEach(function (relativePath, file) {
|
|
370
427
|
tableFilePromises.push(file.async(constants_1.textResultType).then(function (content) { return ({ path: relativePath, content: content }); }));
|
|
@@ -376,15 +433,216 @@ var findTablePathFromZip = function (zip, targetTableName) { return __awaiter(vo
|
|
|
376
433
|
for (_i = 0, tableFiles_1 = tableFiles; _i < tableFiles_1.length; _i++) {
|
|
377
434
|
_a = tableFiles_1[_i], path = _a.path, content = _a.content;
|
|
378
435
|
doc = parser.parseFromString(content, constants_1.xmlTextResultType);
|
|
436
|
+
checkParserError(doc, "".concat(constants_1.Errors.tablePathParse, " ").concat(path));
|
|
379
437
|
tableElem = doc.getElementsByTagName(constants_1.element.table)[0];
|
|
380
438
|
if (tableElem && tableElem.getAttribute(constants_1.elementAttributes.name) === targetTableName) {
|
|
381
439
|
return [2 /*return*/, path];
|
|
382
440
|
}
|
|
383
441
|
}
|
|
384
|
-
throw new Error(constants_1.
|
|
442
|
+
throw new Error(constants_1.Errors.tableNotFound);
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
}); };
|
|
446
|
+
/**
|
|
447
|
+
* Determines the next available item number for a custom XML item in the Excel workbook.
|
|
448
|
+
* Scans the customXml folder to find existing item files and returns the next sequential number.
|
|
449
|
+
*
|
|
450
|
+
* @param zip - The JSZip instance containing the Excel workbook structure
|
|
451
|
+
* @returns Promise resolving to the next available item number (starting from 1 if no items exist)
|
|
452
|
+
*
|
|
453
|
+
* @example
|
|
454
|
+
* // If customXml folder contains item1.xml, item2.xml, returns 3
|
|
455
|
+
* const nextNumber = await getCustomXmlItemNumber(zip);
|
|
456
|
+
*/
|
|
457
|
+
var getCustomXmlItemNumber = function (zip) { return __awaiter(void 0, void 0, void 0, function () {
|
|
458
|
+
var customXmlFolder, re, matches, max, _i, matches_1, f, m, n;
|
|
459
|
+
return __generator(this, function (_a) {
|
|
460
|
+
customXmlFolder = zip.folder(constants_1.customXmlXmlPath);
|
|
461
|
+
if (!customXmlFolder) {
|
|
462
|
+
return [2 /*return*/, 1]; // start from 1 if folder doesn't exist
|
|
463
|
+
}
|
|
464
|
+
re = new RegExp("^".concat(constants_1.customXmlXmlPath, "/").concat(constants_1.customXML.itemNumberPattern.source, "$"));
|
|
465
|
+
matches = zip.file(re);
|
|
466
|
+
max = 0;
|
|
467
|
+
// Iterate through all matching files to find the highest item number
|
|
468
|
+
for (_i = 0, matches_1 = matches; _i < matches_1.length; _i++) {
|
|
469
|
+
f = matches_1[_i];
|
|
470
|
+
m = f.name.match(constants_1.customXML.itemNumberPattern);
|
|
471
|
+
if (m) {
|
|
472
|
+
n = parseInt(m[1], 10);
|
|
473
|
+
if (!Number.isNaN(n) && n > max) {
|
|
474
|
+
max = n;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return [2 /*return*/, max + 1]; // Return next available number
|
|
479
|
+
});
|
|
480
|
+
}); };
|
|
481
|
+
/**
|
|
482
|
+
* Checks if a custom XML item with connected-workbooks already exists in the Excel workbook.
|
|
483
|
+
* Searches through all custom XML files in the customXml folder to find a match with the expected content.
|
|
484
|
+
*
|
|
485
|
+
* @param zip - The JSZip instance containing the Excel workbook structure
|
|
486
|
+
* @returns Promise resolving to true if the custom XML item exists, false otherwise
|
|
487
|
+
*
|
|
488
|
+
* @example
|
|
489
|
+
* const exists = await isCustomXmlExists(zip);
|
|
490
|
+
* if (!exists) {
|
|
491
|
+
* // Add new custom XML item
|
|
492
|
+
* }
|
|
493
|
+
*/
|
|
494
|
+
var isCustomXmlExists = function (zip) { return __awaiter(void 0, void 0, void 0, function () {
|
|
495
|
+
var customXmlFolder, customXmlFiles, _i, customXmlFiles_1, file, content, error_1;
|
|
496
|
+
return __generator(this, function (_a) {
|
|
497
|
+
switch (_a.label) {
|
|
498
|
+
case 0:
|
|
499
|
+
customXmlFolder = zip.folder(constants_1.customXmlXmlPath);
|
|
500
|
+
if (!customXmlFolder) {
|
|
501
|
+
return [2 /*return*/, false]; // customXml folder does not exist
|
|
502
|
+
}
|
|
503
|
+
customXmlFiles = customXmlFolder.file(constants_1.customXML.itemFilePattern);
|
|
504
|
+
_i = 0, customXmlFiles_1 = customXmlFiles;
|
|
505
|
+
_a.label = 1;
|
|
506
|
+
case 1:
|
|
507
|
+
if (!(_i < customXmlFiles_1.length)) return [3 /*break*/, 6];
|
|
508
|
+
file = customXmlFiles_1[_i];
|
|
509
|
+
_a.label = 2;
|
|
510
|
+
case 2:
|
|
511
|
+
_a.trys.push([2, 4, , 5]);
|
|
512
|
+
return [4 /*yield*/, file.async(constants_1.textResultType)];
|
|
513
|
+
case 3:
|
|
514
|
+
content = _a.sent();
|
|
515
|
+
if (content.includes(constants_1.customXML.connectedWorkbookTag)) {
|
|
516
|
+
return [2 /*return*/, true]; // Found matching custom XML item
|
|
517
|
+
}
|
|
518
|
+
return [3 /*break*/, 5];
|
|
519
|
+
case 4:
|
|
520
|
+
error_1 = _a.sent();
|
|
521
|
+
// Skip files that can't be read and continue with the next file
|
|
522
|
+
return [3 /*break*/, 5];
|
|
523
|
+
case 5:
|
|
524
|
+
_i++;
|
|
525
|
+
return [3 /*break*/, 1];
|
|
526
|
+
case 6: return [2 /*return*/, false]; // No matching custom XML item found
|
|
385
527
|
}
|
|
386
528
|
});
|
|
387
529
|
}); };
|
|
530
|
+
/**
|
|
531
|
+
* Adds a content type override entry to the [Content_Types].xml file for a custom XML item.
|
|
532
|
+
* This registration is required for Excel to recognize and process the custom XML item.
|
|
533
|
+
*
|
|
534
|
+
* @param zip - The JSZip instance containing the Excel workbook structure
|
|
535
|
+
* @param itemIndex - The index/number of the custom XML item to register
|
|
536
|
+
* @throws {Error} When the [Content_Types].xml file is not found or cannot be parsed
|
|
537
|
+
*
|
|
538
|
+
* @example
|
|
539
|
+
* await addToContentType(zip, "1"); // Registers customXml/item1.xml in content types
|
|
540
|
+
*/
|
|
541
|
+
var addToContentType = function (zip, itemIndex) { return __awaiter(void 0, void 0, void 0, function () {
|
|
542
|
+
var contentTypesXmlString, parser, doc, partName, contentTypeValue, typesElement, ns, overrideEl, serializer, newDoc;
|
|
543
|
+
var _a;
|
|
544
|
+
return __generator(this, function (_b) {
|
|
545
|
+
switch (_b.label) {
|
|
546
|
+
case 0: return [4 /*yield*/, ((_a = zip.file(constants_1.contentTypesXmlPath)) === null || _a === void 0 ? void 0 : _a.async(constants_1.textResultType))];
|
|
547
|
+
case 1:
|
|
548
|
+
contentTypesXmlString = _b.sent();
|
|
549
|
+
if (!contentTypesXmlString) {
|
|
550
|
+
throw new Error(constants_1.Errors.contentTypesNotFound);
|
|
551
|
+
}
|
|
552
|
+
parser = new xmldom_qsa_1.DOMParser();
|
|
553
|
+
doc = parser.parseFromString(contentTypesXmlString, constants_1.xmlTextResultType);
|
|
554
|
+
checkParserError(doc, constants_1.Errors.contentTypesParse);
|
|
555
|
+
partName = constants_1.customXML.itemPropsPartNameTemplate(itemIndex);
|
|
556
|
+
contentTypeValue = constants_1.customXML.contentType;
|
|
557
|
+
typesElement = doc.documentElement;
|
|
558
|
+
if (!typesElement) {
|
|
559
|
+
throw new Error(constants_1.Errors.contentTypesElementNotFound);
|
|
560
|
+
}
|
|
561
|
+
ns = doc.documentElement.namespaceURI;
|
|
562
|
+
overrideEl = ns ? doc.createElementNS(ns, constants_1.element.override) : doc.createElement(constants_1.element.override);
|
|
563
|
+
overrideEl.setAttribute(constants_1.elementAttributes.partName, partName);
|
|
564
|
+
overrideEl.setAttribute(constants_1.elementAttributes.contentType, contentTypeValue);
|
|
565
|
+
typesElement.appendChild(overrideEl);
|
|
566
|
+
serializer = new xmldom_qsa_1.XMLSerializer();
|
|
567
|
+
newDoc = serializer.serializeToString(doc);
|
|
568
|
+
zip.file(constants_1.contentTypesXmlPath, newDoc);
|
|
569
|
+
return [2 /*return*/];
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
}); };
|
|
573
|
+
/**
|
|
574
|
+
* Adds a relationship entry to the workbook relationships file for a custom XML item.
|
|
575
|
+
* Creates a new relationship that links the workbook to the custom XML item.
|
|
576
|
+
*
|
|
577
|
+
* @param zip - The JSZip instance containing the Excel workbook structure
|
|
578
|
+
* @param itemIndex - The index/number of the custom XML item to create a relationship for
|
|
579
|
+
* @throws {Error} When the workbook relationships file is not found or cannot be parsed
|
|
580
|
+
*
|
|
581
|
+
* @example
|
|
582
|
+
* await addCustomXmlToRels(zip, "1"); // Creates relationship to customXml/item1.xml
|
|
583
|
+
*/
|
|
584
|
+
var addCustomXmlToRels = function (zip, itemIndex) { return __awaiter(void 0, void 0, void 0, function () {
|
|
585
|
+
var relsXmlString, parser, doc, relationshipsElements, relationshipsElement, highestRid, newRid, target, type, ns, relationshipEl, serializer, newDoc;
|
|
586
|
+
var _a;
|
|
587
|
+
return __generator(this, function (_b) {
|
|
588
|
+
switch (_b.label) {
|
|
589
|
+
case 0: return [4 /*yield*/, ((_a = zip.file(constants_1.workbookRelsXmlPath)) === null || _a === void 0 ? void 0 : _a.async(constants_1.textResultType))];
|
|
590
|
+
case 1:
|
|
591
|
+
relsXmlString = _b.sent();
|
|
592
|
+
if (!relsXmlString) {
|
|
593
|
+
throw new Error(constants_1.Errors.relsNotFound);
|
|
594
|
+
}
|
|
595
|
+
parser = new xmldom_qsa_1.DOMParser();
|
|
596
|
+
doc = parser.parseFromString(relsXmlString, constants_1.xmlTextResultType);
|
|
597
|
+
checkParserError(doc, constants_1.Errors.workbookRelsParse);
|
|
598
|
+
relationshipsElements = doc.getElementsByTagName(constants_1.element.relationships);
|
|
599
|
+
if (!relationshipsElements || relationshipsElements.length === 0) {
|
|
600
|
+
throw new Error(constants_1.Errors.relationship);
|
|
601
|
+
}
|
|
602
|
+
relationshipsElement = relationshipsElements[0];
|
|
603
|
+
highestRid = getHighestRelationshipId(relationshipsElement);
|
|
604
|
+
newRid = "".concat(constants_1.elementAttributes.relationshipIdPrefix).concat(highestRid + 1);
|
|
605
|
+
target = constants_1.customXML.relativeItemPathTemplate(itemIndex);
|
|
606
|
+
type = constants_1.customXML.relationshipType;
|
|
607
|
+
ns = doc.documentElement.namespaceURI;
|
|
608
|
+
relationshipEl = ns ? doc.createElementNS(ns, constants_1.element.relationship) : doc.createElement(constants_1.element.relationship);
|
|
609
|
+
relationshipEl.setAttribute(constants_1.elementAttributes.Id, newRid);
|
|
610
|
+
relationshipEl.setAttribute(constants_1.elementAttributes.type, type);
|
|
611
|
+
relationshipEl.setAttribute(constants_1.elementAttributes.target, target);
|
|
612
|
+
relationshipsElement.appendChild(relationshipEl);
|
|
613
|
+
serializer = new xmldom_qsa_1.XMLSerializer();
|
|
614
|
+
newDoc = serializer.serializeToString(doc);
|
|
615
|
+
zip.file(constants_1.workbookRelsXmlPath, newDoc);
|
|
616
|
+
return [2 /*return*/];
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
}); };
|
|
620
|
+
/**
|
|
621
|
+
* Finds the highest relationship ID number from existing relationships in a relationships element.
|
|
622
|
+
* Scans all relationship elements and extracts the numeric part from rId attributes.
|
|
623
|
+
*
|
|
624
|
+
* @param relationshipsElement - The relationships XML element containing relationship elements
|
|
625
|
+
* @returns The highest relationship ID number found, or 0 if none exist
|
|
626
|
+
*
|
|
627
|
+
* @example
|
|
628
|
+
* // If relationships contain rId1, rId3, rId7, returns 7
|
|
629
|
+
* const highestRid = getHighestRelationshipId(relationshipsElement);
|
|
630
|
+
*/
|
|
631
|
+
var getHighestRelationshipId = function (relationshipsElement) {
|
|
632
|
+
var relationships = relationshipsElement.getElementsByTagName(constants_1.element.relationship);
|
|
633
|
+
var highestRid = 0;
|
|
634
|
+
for (var i = 0; i < relationships.length; i++) {
|
|
635
|
+
var idAttr = relationships[i].getAttribute(constants_1.elementAttributes.Id);
|
|
636
|
+
if (idAttr && idAttr.startsWith(constants_1.elementAttributes.relationshipIdPrefix)) {
|
|
637
|
+
// Extract numeric part from rId (e.g., "rId5" -> 5, "rId123" -> 123)
|
|
638
|
+
var ridNumber = parseInt(idAttr.substring(constants_1.elementAttributes.relationshipIdPrefix.length), 10);
|
|
639
|
+
if (!isNaN(ridNumber) && ridNumber > highestRid) {
|
|
640
|
+
highestRid = ridNumber;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
return highestRid;
|
|
645
|
+
};
|
|
388
646
|
exports.default = {
|
|
389
647
|
updateDocProps: updateDocProps,
|
|
390
648
|
clearLabelInfo: clearLabelInfo,
|
|
@@ -397,4 +655,9 @@ exports.default = {
|
|
|
397
655
|
getSheetPathByNameFromZip: getSheetPathByNameFromZip,
|
|
398
656
|
getReferenceFromTable: getReferenceFromTable,
|
|
399
657
|
findTablePathFromZip: findTablePathFromZip,
|
|
658
|
+
getCustomXmlItemNumber: getCustomXmlItemNumber,
|
|
659
|
+
isCustomXmlExists: isCustomXmlExists,
|
|
660
|
+
addToContentType: addToContentType,
|
|
661
|
+
addCustomXmlToRels: addCustomXmlToRels,
|
|
662
|
+
checkParserError: checkParserError,
|
|
400
663
|
};
|
|
@@ -47,12 +47,78 @@ var pqUtils_1 = __importDefault(require("./pqUtils"));
|
|
|
47
47
|
var tableUtils_1 = __importDefault(require("./tableUtils"));
|
|
48
48
|
var xmlInnerPartsUtils_1 = __importDefault(require("./xmlInnerPartsUtils"));
|
|
49
49
|
var documentUtils_1 = __importDefault(require("./documentUtils"));
|
|
50
|
+
var addCustomXMLToWorkbook = function (zip) { return __awaiter(void 0, void 0, void 0, function () {
|
|
51
|
+
var customXmlItemNumber, backupData, contentTypesPath, workbookRelsPath, _a, _b, _c, _d, error_1, _i, _e, _f, filePath, content;
|
|
52
|
+
var _g, _h;
|
|
53
|
+
return __generator(this, function (_j) {
|
|
54
|
+
switch (_j.label) {
|
|
55
|
+
case 0: return [4 /*yield*/, xmlInnerPartsUtils_1.default.isCustomXmlExists(zip)];
|
|
56
|
+
case 1:
|
|
57
|
+
if (_j.sent()) {
|
|
58
|
+
return [2 /*return*/, true];
|
|
59
|
+
}
|
|
60
|
+
return [4 /*yield*/, xmlInnerPartsUtils_1.default.getCustomXmlItemNumber(zip)];
|
|
61
|
+
case 2:
|
|
62
|
+
customXmlItemNumber = _j.sent();
|
|
63
|
+
backupData = {};
|
|
64
|
+
contentTypesPath = "[Content_Types].xml";
|
|
65
|
+
workbookRelsPath = "xl/_rels/workbook.xml.rels";
|
|
66
|
+
_j.label = 3;
|
|
67
|
+
case 3:
|
|
68
|
+
_j.trys.push([3, 8, , 9]);
|
|
69
|
+
// Backup existing files
|
|
70
|
+
_a = backupData;
|
|
71
|
+
_b = contentTypesPath;
|
|
72
|
+
return [4 /*yield*/, ((_g = zip.file(contentTypesPath)) === null || _g === void 0 ? void 0 : _g.async("text"))];
|
|
73
|
+
case 4:
|
|
74
|
+
// Backup existing files
|
|
75
|
+
_a[_b] = (_j.sent()) || null;
|
|
76
|
+
_c = backupData;
|
|
77
|
+
_d = workbookRelsPath;
|
|
78
|
+
return [4 /*yield*/, ((_h = zip.file(workbookRelsPath)) === null || _h === void 0 ? void 0 : _h.async("text"))];
|
|
79
|
+
case 5:
|
|
80
|
+
_c[_d] = (_j.sent()) || null;
|
|
81
|
+
// Perform modifications
|
|
82
|
+
return [4 /*yield*/, xmlInnerPartsUtils_1.default.addToContentType(zip, customXmlItemNumber.toString())];
|
|
83
|
+
case 6:
|
|
84
|
+
// Perform modifications
|
|
85
|
+
_j.sent();
|
|
86
|
+
return [4 /*yield*/, xmlInnerPartsUtils_1.default.addCustomXmlToRels(zip, customXmlItemNumber.toString())];
|
|
87
|
+
case 7:
|
|
88
|
+
_j.sent();
|
|
89
|
+
// Adding the custom XML files
|
|
90
|
+
zip.file(constants_1.customXML.itemPathTemplate(customXmlItemNumber), constants_1.customXML.customXMLItemContent);
|
|
91
|
+
zip.file(constants_1.customXML.itemPropsPathTemplate(customXmlItemNumber), constants_1.customXML.customXMLItemPropsContent);
|
|
92
|
+
zip.file(constants_1.customXML.itemRelsPathTemplate(customXmlItemNumber), constants_1.customXML.customXMLRelationships(customXmlItemNumber));
|
|
93
|
+
return [3 /*break*/, 9];
|
|
94
|
+
case 8:
|
|
95
|
+
error_1 = _j.sent();
|
|
96
|
+
// Rollback: restore backed up files
|
|
97
|
+
for (_i = 0, _e = Object.entries(backupData); _i < _e.length; _i++) {
|
|
98
|
+
_f = _e[_i], filePath = _f[0], content = _f[1];
|
|
99
|
+
if (content !== null) {
|
|
100
|
+
zip.file(filePath, content);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
// If file didn't exist before, remove it
|
|
104
|
+
zip.remove(filePath);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Remove any custom XML files that might have been added
|
|
108
|
+
zip.remove(constants_1.customXML.itemPathTemplate(customXmlItemNumber));
|
|
109
|
+
zip.remove(constants_1.customXML.itemPropsPathTemplate(customXmlItemNumber));
|
|
110
|
+
zip.remove(constants_1.customXML.itemRelsPathTemplate(customXmlItemNumber));
|
|
111
|
+
return [2 /*return*/, false];
|
|
112
|
+
case 9: return [2 /*return*/, true];
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}); };
|
|
50
116
|
var updateWorkbookDataAndConfigurations = function (zip, fileConfigs, tableData, updateQueryTable) {
|
|
51
117
|
if (updateQueryTable === void 0) { updateQueryTable = false; }
|
|
52
118
|
return __awaiter(void 0, void 0, void 0, function () {
|
|
53
|
-
var sheetName, tablePath, sheetPath, templateSettings, sheetLocation, _a, cellRangeRef;
|
|
54
|
-
return __generator(this, function (
|
|
55
|
-
switch (
|
|
119
|
+
var sheetName, tablePath, sheetPath, templateSettings, sheetLocation, _a, cellRangeRef, _b, row, column, endColumn, endRow;
|
|
120
|
+
return __generator(this, function (_c) {
|
|
121
|
+
switch (_c.label) {
|
|
56
122
|
case 0:
|
|
57
123
|
sheetName = constants_1.defaults.sheetName;
|
|
58
124
|
tablePath = constants_1.tableXmlPath;
|
|
@@ -62,41 +128,48 @@ var updateWorkbookDataAndConfigurations = function (zip, fileConfigs, tableData,
|
|
|
62
128
|
if (!((templateSettings === null || templateSettings === void 0 ? void 0 : templateSettings.sheetName) !== undefined)) return [3 /*break*/, 2];
|
|
63
129
|
return [4 /*yield*/, xmlInnerPartsUtils_1.default.getSheetPathByNameFromZip(zip, templateSettings.sheetName)];
|
|
64
130
|
case 1:
|
|
65
|
-
sheetLocation =
|
|
131
|
+
sheetLocation = _c.sent();
|
|
66
132
|
sheetName = templateSettings.sheetName;
|
|
67
133
|
sheetPath = "xl/" + sheetLocation;
|
|
68
|
-
|
|
134
|
+
_c.label = 2;
|
|
69
135
|
case 2:
|
|
70
136
|
if (!((templateSettings === null || templateSettings === void 0 ? void 0 : templateSettings.tableName) !== undefined)) return [3 /*break*/, 4];
|
|
71
137
|
_a = constants_1.tablesFolderPath;
|
|
72
138
|
return [4 /*yield*/, xmlInnerPartsUtils_1.default.findTablePathFromZip(zip, templateSettings === null || templateSettings === void 0 ? void 0 : templateSettings.tableName)];
|
|
73
139
|
case 3:
|
|
74
|
-
tablePath = _a + (
|
|
75
|
-
|
|
140
|
+
tablePath = _a + (_c.sent());
|
|
141
|
+
_c.label = 4;
|
|
76
142
|
case 4:
|
|
77
143
|
cellRangeRef = "A1";
|
|
78
|
-
if (!((fileConfigs === null || fileConfigs === void 0 ? void 0 : fileConfigs.templateFile)
|
|
144
|
+
if (!((fileConfigs === null || fileConfigs === void 0 ? void 0 : fileConfigs.templateFile) !== undefined)) return [3 /*break*/, 6];
|
|
79
145
|
return [4 /*yield*/, xmlInnerPartsUtils_1.default.getReferenceFromTable(zip, tablePath)];
|
|
80
146
|
case 5:
|
|
81
|
-
cellRangeRef =
|
|
82
|
-
|
|
147
|
+
cellRangeRef = _c.sent();
|
|
148
|
+
_c.label = 6;
|
|
83
149
|
case 6:
|
|
84
150
|
if (tableData) {
|
|
85
|
-
|
|
151
|
+
_b = documentUtils_1.default.GetStartPosition(cellRangeRef), row = _b.row, column = _b.column;
|
|
152
|
+
endColumn = column - 1 + tableData.columnNames.length;
|
|
153
|
+
endRow = row - 1 + tableData.rows.length;
|
|
154
|
+
// Extend the cell range to include the entire table span
|
|
155
|
+
cellRangeRef += ":".concat(documentUtils_1.default.getCellReferenceRelative(endColumn - 1, endRow + 1));
|
|
86
156
|
}
|
|
87
157
|
return [4 /*yield*/, xmlInnerPartsUtils_1.default.updateDocProps(zip, fileConfigs === null || fileConfigs === void 0 ? void 0 : fileConfigs.docProps)];
|
|
88
158
|
case 7:
|
|
89
|
-
|
|
159
|
+
_c.sent();
|
|
90
160
|
if (!((fileConfigs === null || fileConfigs === void 0 ? void 0 : fileConfigs.templateFile) === undefined)) return [3 /*break*/, 9];
|
|
91
161
|
// If we are using our base template, we need to clear label info
|
|
92
162
|
return [4 /*yield*/, xmlInnerPartsUtils_1.default.clearLabelInfo(zip)];
|
|
93
163
|
case 8:
|
|
94
164
|
// If we are using our base template, we need to clear label info
|
|
95
|
-
|
|
96
|
-
|
|
165
|
+
_c.sent();
|
|
166
|
+
_c.label = 9;
|
|
97
167
|
case 9: return [4 /*yield*/, tableUtils_1.default.updateTableInitialDataIfNeeded(zip, cellRangeRef, sheetPath, tablePath, sheetPath, tableData, updateQueryTable)];
|
|
98
168
|
case 10:
|
|
99
|
-
|
|
169
|
+
_c.sent();
|
|
170
|
+
return [4 /*yield*/, addCustomXMLToWorkbook(zip)];
|
|
171
|
+
case 11:
|
|
172
|
+
_c.sent();
|
|
100
173
|
return [2 /*return*/];
|
|
101
174
|
}
|
|
102
175
|
});
|
|
@@ -110,7 +183,7 @@ var updateWorkbookPowerQueryDocument = function (zip, queryName, queryMashupDoc)
|
|
|
110
183
|
case 1:
|
|
111
184
|
old_base64 = _a.sent();
|
|
112
185
|
if (!old_base64) {
|
|
113
|
-
throw new Error(constants_1.
|
|
186
|
+
throw new Error(constants_1.Errors.base64NotFound);
|
|
114
187
|
}
|
|
115
188
|
return [4 /*yield*/, (0, mashupDocumentParser_1.replaceSingleQuery)(old_base64, queryName, queryMashupDoc)];
|
|
116
189
|
case 2:
|
|
@@ -131,7 +204,7 @@ var updateWorkbookSingleQueryAttributes = function (zip, queryName, refreshOnOpe
|
|
|
131
204
|
case 1:
|
|
132
205
|
connectionsXmlString = _f.sent();
|
|
133
206
|
if (connectionsXmlString === undefined) {
|
|
134
|
-
throw new Error(constants_1.
|
|
207
|
+
throw new Error(constants_1.Errors.connectionsNotFound);
|
|
135
208
|
}
|
|
136
209
|
_a = xmlInnerPartsUtils_1.default.updateConnections(connectionsXmlString, queryName, refreshOnOpen), connectionId = _a.connectionId, connectionXmlFileString = _a.connectionXmlFileString;
|
|
137
210
|
zip.file(constants_1.connectionsXmlPath, connectionXmlFileString);
|
|
@@ -139,7 +212,7 @@ var updateWorkbookSingleQueryAttributes = function (zip, queryName, refreshOnOpe
|
|
|
139
212
|
case 2:
|
|
140
213
|
sharedStringsXmlString = _f.sent();
|
|
141
214
|
if (sharedStringsXmlString === undefined) {
|
|
142
|
-
throw new Error(constants_1.
|
|
215
|
+
throw new Error(constants_1.Errors.sharedStringsNotFound);
|
|
143
216
|
}
|
|
144
217
|
_b = xmlInnerPartsUtils_1.default.updateSharedStrings(sharedStringsXmlString, queryName), sharedStringIndex = _b.sharedStringIndex, newSharedStrings = _b.newSharedStrings;
|
|
145
218
|
zip.file(constants_1.sharedStringsXmlPath, newSharedStrings);
|
|
@@ -154,7 +227,7 @@ var updateWorkbookSingleQueryAttributes = function (zip, queryName, refreshOnOpe
|
|
|
154
227
|
case 5:
|
|
155
228
|
sheetsXmlString = _f.sent();
|
|
156
229
|
if (sheetsXmlString === undefined) {
|
|
157
|
-
throw new Error(constants_1.
|
|
230
|
+
throw new Error(constants_1.Errors.sheetsNotFound);
|
|
158
231
|
}
|
|
159
232
|
worksheetString = xmlInnerPartsUtils_1.default.updateWorksheet(sheetsXmlString, sharedStringIndex.toString());
|
|
160
233
|
zip.file(sheetPath, worksheetString);
|
|
@@ -171,4 +244,5 @@ exports.default = {
|
|
|
171
244
|
updateWorkbookDataAndConfigurations: updateWorkbookDataAndConfigurations,
|
|
172
245
|
updateWorkbookPowerQueryDocument: updateWorkbookPowerQueryDocument,
|
|
173
246
|
updateWorkbookSingleQueryAttributes: updateWorkbookSingleQueryAttributes,
|
|
247
|
+
addCustomXMLToWorkbook: addCustomXMLToWorkbook
|
|
174
248
|
};
|