@microsoft/connected-workbooks 3.3.2-beta → 3.4.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 (37) hide show
  1. package/dist/utils/constants.js +87 -49
  2. package/dist/utils/documentUtils.js +1 -1
  3. package/dist/utils/gridUtils.js +8 -8
  4. package/dist/utils/mashupDocumentParser.js +1 -1
  5. package/dist/utils/pqUtils.js +3 -3
  6. package/dist/utils/tableUtils.js +11 -4
  7. package/dist/utils/xmlInnerPartsUtils.js +245 -13
  8. package/dist/utils/xmlPartsUtils.js +74 -4
  9. package/dist/workbookManager.js +3 -3
  10. package/package.json +7 -3
  11. package/dist/src/generators.js +0 -15
  12. package/dist/src/types.js +0 -28
  13. package/dist/src/utils/arrayUtils.js +0 -51
  14. package/dist/src/utils/constants.js +0 -175
  15. package/dist/src/utils/documentUtils.js +0 -167
  16. package/dist/src/utils/gridUtils.js +0 -103
  17. package/dist/src/utils/htmlUtils.js +0 -19
  18. package/dist/src/utils/index.js +0 -24
  19. package/dist/src/utils/mashupDocumentParser.js +0 -188
  20. package/dist/src/utils/pqUtils.js +0 -194
  21. package/dist/src/utils/tableUtils.js +0 -233
  22. package/dist/src/utils/xmlInnerPartsUtils.js +0 -431
  23. package/dist/src/utils/xmlPartsUtils.js +0 -178
  24. package/dist/src/workbookTemplate.js +0 -9
  25. package/dist/tests/arrayUtils.test.js +0 -66
  26. package/dist/tests/documentUtils.test.js +0 -70
  27. package/dist/tests/gridUtils.test.js +0 -214
  28. package/dist/tests/htmlUtils.test.js +0 -111
  29. package/dist/tests/mashupDocumentParser.test.js +0 -113
  30. package/dist/tests/mocks/PqMock.js +0 -7
  31. package/dist/tests/mocks/index.js +0 -24
  32. package/dist/tests/mocks/section1mSimpleQueryMock.js +0 -8
  33. package/dist/tests/mocks/xmlMocks.js +0 -14
  34. package/dist/tests/tableUtils.test.js +0 -70
  35. package/dist/tests/workbookQueryTemplate.test.js +0 -218
  36. package/dist/tests/workbookTableTemplate.test.js +0 -126
  37. package/dist/tests/xmlInnerPartsUtils.test.js +0 -273
@@ -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 () {
@@ -116,17 +133,18 @@ var clearLabelInfo = function (zip) { return __awaiter(void 0, void 0, void 0, f
116
133
  case 1:
117
134
  relsString = _b.sent();
118
135
  if (relsString === undefined) {
119
- throw new Error(constants_1.relsNotFoundErr);
136
+ throw new Error(constants_1.Errors.relsNotFound);
120
137
  }
121
138
  parser = new xmldom_qsa_1.DOMParser();
122
139
  doc = parser.parseFromString(relsString, constants_1.xmlTextResultType);
140
+ checkParserError(doc, constants_1.Errors.relsParse);
123
141
  relationshipsList = doc.getElementsByTagName(constants_1.element.relationships);
124
142
  if (!relationshipsList || relationshipsList.length === 0) {
125
- throw new Error(constants_1.relationshipErr);
143
+ throw new Error(constants_1.Errors.relationship);
126
144
  }
127
145
  relationships = relationshipsList[0];
128
146
  if (!relationships) {
129
- throw new Error(constants_1.relationshipErr);
147
+ throw new Error(constants_1.Errors.relationship);
130
148
  }
131
149
  removeLabelInfoRelationship(doc, relationships);
132
150
  updateRelationshipIds(doc);
@@ -143,6 +161,7 @@ var updateConnections = function (connectionsXmlString, queryName, refreshOnOpen
143
161
  var serializer = new xmldom_qsa_1.XMLSerializer();
144
162
  var refreshOnLoadValue = refreshOnOpen ? constants_1.trueValue : constants_1.falseValue;
145
163
  var connectionsDoc = parser.parseFromString(connectionsXmlString, constants_1.xmlTextResultType);
164
+ checkParserError(connectionsDoc, constants_1.Errors.connectionsParse);
146
165
  var connectionsProperties = connectionsDoc.getElementsByTagName(constants_1.element.databaseProperties);
147
166
  var dbPr = connectionsProperties[0];
148
167
  dbPr.setAttribute(constants_1.elementAttributes.refreshOnLoad, refreshOnLoadValue);
@@ -154,7 +173,7 @@ var updateConnections = function (connectionsXmlString, queryName, refreshOnOpen
154
173
  var connectionId = (_c = dbPr.parentNode) === null || _c === void 0 ? void 0 : _c.getAttribute(constants_1.elementAttributes.id);
155
174
  var connectionXmlFileString = serializer.serializeToString(connectionsDoc);
156
175
  if (connectionId === null) {
157
- throw new Error(constants_1.connectionsNotFoundErr);
176
+ throw new Error(constants_1.Errors.connectionsNotFound);
158
177
  }
159
178
  return { connectionId: connectionId, connectionXmlFileString: connectionXmlFileString };
160
179
  };
@@ -162,9 +181,10 @@ var updateSharedStrings = function (sharedStringsXmlString, queryName) {
162
181
  var parser = new xmldom_qsa_1.DOMParser();
163
182
  var serializer = new xmldom_qsa_1.XMLSerializer();
164
183
  var sharedStringsDoc = parser.parseFromString(sharedStringsXmlString, constants_1.xmlTextResultType);
184
+ checkParserError(sharedStringsDoc, constants_1.Errors.sharedStringsParse);
165
185
  var sharedStringsTable = sharedStringsDoc.getElementsByTagName(constants_1.element.sharedStringTable)[0];
166
186
  if (!sharedStringsTable) {
167
- throw new Error(constants_1.sharedStringsNotFoundErr);
187
+ throw new Error(constants_1.Errors.sharedStringsNotFound);
168
188
  }
169
189
  var textElementCollection = sharedStringsDoc.getElementsByTagName(constants_1.element.text);
170
190
  var textElement = null;
@@ -202,6 +222,7 @@ var updateWorksheet = function (sheetsXmlString, sharedStringIndex) {
202
222
  var parser = new xmldom_qsa_1.DOMParser();
203
223
  var serializer = new xmldom_qsa_1.XMLSerializer();
204
224
  var sheetsDoc = parser.parseFromString(sheetsXmlString, constants_1.xmlTextResultType);
225
+ checkParserError(sheetsDoc, constants_1.Errors.worksheetParse);
205
226
  sheetsDoc.getElementsByTagName(constants_1.element.cellValue)[0].innerHTML = sharedStringIndex.toString();
206
227
  var newSheet = serializer.serializeToString(sheetsDoc);
207
228
  return newSheet;
@@ -267,7 +288,7 @@ var updatePivotTablesandQueryTables = function (zip, queryName, refreshOnOpen, c
267
288
  }
268
289
  });
269
290
  if (!found) {
270
- throw new Error(constants_1.queryAndPivotTableNotFoundErr);
291
+ throw new Error(constants_1.Errors.queryAndPivotTableNotFound);
271
292
  }
272
293
  return [2 /*return*/];
273
294
  }
@@ -279,6 +300,7 @@ var updateQueryTable = function (tableXmlString, connectionId, refreshOnOpen) {
279
300
  var parser = new xmldom_qsa_1.DOMParser();
280
301
  var serializer = new xmldom_qsa_1.XMLSerializer();
281
302
  var queryTableDoc = parser.parseFromString(tableXmlString, constants_1.xmlTextResultType);
303
+ checkParserError(queryTableDoc, constants_1.Errors.queryTableParse);
282
304
  var queryTable = queryTableDoc.getElementsByTagName(constants_1.element.queryTable)[0];
283
305
  var newQueryTable = constants_1.emptyValue;
284
306
  if (queryTable.getAttribute(constants_1.elementAttributes.connectionId) == connectionId) {
@@ -294,6 +316,7 @@ var updatePivotTable = function (tableXmlString, connectionId, refreshOnOpen) {
294
316
  var parser = new xmldom_qsa_1.DOMParser();
295
317
  var serializer = new xmldom_qsa_1.XMLSerializer();
296
318
  var pivotCacheDoc = parser.parseFromString(tableXmlString, constants_1.xmlTextResultType);
319
+ checkParserError(pivotCacheDoc, constants_1.Errors.pivotTableParse);
297
320
  var cacheSource = pivotCacheDoc.getElementsByTagName(constants_1.element.cacheSource)[0];
298
321
  var newPivotTable = constants_1.emptyValue;
299
322
  if (cacheSource.getAttribute(constants_1.elementAttributes.connectionId) == connectionId) {
@@ -315,12 +338,13 @@ function getSheetPathFromXlRelId(zip, rId) {
315
338
  case 0:
316
339
  relsFile = zip.file(constants_1.workbookRelsXmlPath);
317
340
  if (!relsFile) {
318
- throw new Error(constants_1.xlRelsNotFoundErr);
341
+ throw new Error(constants_1.Errors.xlRelsNotFound);
319
342
  }
320
343
  return [4 /*yield*/, relsFile.async(constants_1.textResultType)];
321
344
  case 1:
322
345
  relsString = _a.sent();
323
346
  relsDoc = new xmldom_qsa_1.DOMParser().parseFromString(relsString, constants_1.xmlTextResultType);
347
+ checkParserError(relsDoc, constants_1.Errors.workbookRelsParse);
324
348
  relationships = relsDoc.getElementsByTagName("Relationship");
325
349
  target = null;
326
350
  for (i = 0; i < relationships.length; i++) {
@@ -348,10 +372,11 @@ var getSheetPathByNameFromZip = function (zip, sheetName) { return __awaiter(voi
348
372
  case 1:
349
373
  workbookXmlString = _b.sent();
350
374
  if (!workbookXmlString) {
351
- throw new Error(constants_1.WorkbookNotFoundERR);
375
+ throw new Error(constants_1.Errors.workbookNotFound);
352
376
  }
353
377
  parser = new xmldom_qsa_1.DOMParser();
354
378
  doc = parser.parseFromString(workbookXmlString, constants_1.xmlTextResultType);
379
+ checkParserError(doc, constants_1.Errors.workbookParse);
355
380
  sheetElements = doc.getElementsByTagName(constants_1.element.sheet);
356
381
  for (i = 0; i < sheetElements.length; i++) {
357
382
  if (sheetElements[i].getAttribute(constants_1.elementAttributes.name) === sheetName) {
@@ -375,14 +400,15 @@ var getReferenceFromTable = function (zip, tablePath) { return __awaiter(void 0,
375
400
  case 1:
376
401
  tableXmlString = _c.sent();
377
402
  if (!tableXmlString) {
378
- throw new Error(constants_1.WorkbookNotFoundERR);
403
+ throw new Error(constants_1.Errors.workbookNotFound);
379
404
  }
380
405
  parser = new xmldom_qsa_1.DOMParser();
381
406
  doc = parser.parseFromString(tableXmlString, constants_1.xmlTextResultType);
407
+ checkParserError(doc, constants_1.Errors.tableParse);
382
408
  tableElements = doc.getElementsByTagName(constants_1.element.table);
383
409
  reference = (_b = tableElements[0]) === null || _b === void 0 ? void 0 : _b.getAttribute(constants_1.elementAttributes.reference);
384
410
  if (!reference) {
385
- throw new Error(constants_1.tableReferenceNotFoundErr);
411
+ throw new Error(constants_1.Errors.tableReferenceNotFound);
386
412
  }
387
413
  return [2 /*return*/, reference.split(":")[0]]; // Return the start cell reference (e.g., "A1" from "A1:B10")
388
414
  }
@@ -393,9 +419,9 @@ var findTablePathFromZip = function (zip, targetTableName) { return __awaiter(vo
393
419
  return __generator(this, function (_b) {
394
420
  switch (_b.label) {
395
421
  case 0:
396
- tablesFolder = zip.folder("xl/tables");
422
+ tablesFolder = zip.folder(constants_1.tablesFolderPath);
397
423
  if (!tablesFolder)
398
- return [2 /*return*/, ""];
424
+ return [2 /*return*/, constants_1.emptyValue];
399
425
  tableFilePromises = [];
400
426
  tablesFolder.forEach(function (relativePath, file) {
401
427
  tableFilePromises.push(file.async(constants_1.textResultType).then(function (content) { return ({ path: relativePath, content: content }); }));
@@ -407,15 +433,216 @@ var findTablePathFromZip = function (zip, targetTableName) { return __awaiter(vo
407
433
  for (_i = 0, tableFiles_1 = tableFiles; _i < tableFiles_1.length; _i++) {
408
434
  _a = tableFiles_1[_i], path = _a.path, content = _a.content;
409
435
  doc = parser.parseFromString(content, constants_1.xmlTextResultType);
436
+ checkParserError(doc, "".concat(constants_1.Errors.tablePathParse, " ").concat(path));
410
437
  tableElem = doc.getElementsByTagName(constants_1.element.table)[0];
411
438
  if (tableElem && tableElem.getAttribute(constants_1.elementAttributes.name) === targetTableName) {
412
439
  return [2 /*return*/, path];
413
440
  }
414
441
  }
415
- throw new Error(constants_1.tableNotFoundErr);
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
416
527
  }
417
528
  });
418
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
+ };
419
646
  exports.default = {
420
647
  updateDocProps: updateDocProps,
421
648
  clearLabelInfo: clearLabelInfo,
@@ -428,4 +655,9 @@ exports.default = {
428
655
  getSheetPathByNameFromZip: getSheetPathByNameFromZip,
429
656
  getReferenceFromTable: getReferenceFromTable,
430
657
  findTablePathFromZip: findTablePathFromZip,
658
+ getCustomXmlItemNumber: getCustomXmlItemNumber,
659
+ isCustomXmlExists: isCustomXmlExists,
660
+ addToContentType: addToContentType,
661
+ addCustomXmlToRels: addCustomXmlToRels,
662
+ checkParserError: checkParserError,
431
663
  };
@@ -47,6 +47,72 @@ 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 () {
@@ -100,6 +166,9 @@ var updateWorkbookDataAndConfigurations = function (zip, fileConfigs, tableData,
100
166
  _c.label = 9;
101
167
  case 9: return [4 /*yield*/, tableUtils_1.default.updateTableInitialDataIfNeeded(zip, cellRangeRef, sheetPath, tablePath, sheetPath, tableData, updateQueryTable)];
102
168
  case 10:
169
+ _c.sent();
170
+ return [4 /*yield*/, addCustomXMLToWorkbook(zip)];
171
+ case 11:
103
172
  _c.sent();
104
173
  return [2 /*return*/];
105
174
  }
@@ -114,7 +183,7 @@ var updateWorkbookPowerQueryDocument = function (zip, queryName, queryMashupDoc)
114
183
  case 1:
115
184
  old_base64 = _a.sent();
116
185
  if (!old_base64) {
117
- throw new Error(constants_1.base64NotFoundErr);
186
+ throw new Error(constants_1.Errors.base64NotFound);
118
187
  }
119
188
  return [4 /*yield*/, (0, mashupDocumentParser_1.replaceSingleQuery)(old_base64, queryName, queryMashupDoc)];
120
189
  case 2:
@@ -135,7 +204,7 @@ var updateWorkbookSingleQueryAttributes = function (zip, queryName, refreshOnOpe
135
204
  case 1:
136
205
  connectionsXmlString = _f.sent();
137
206
  if (connectionsXmlString === undefined) {
138
- throw new Error(constants_1.connectionsNotFoundErr);
207
+ throw new Error(constants_1.Errors.connectionsNotFound);
139
208
  }
140
209
  _a = xmlInnerPartsUtils_1.default.updateConnections(connectionsXmlString, queryName, refreshOnOpen), connectionId = _a.connectionId, connectionXmlFileString = _a.connectionXmlFileString;
141
210
  zip.file(constants_1.connectionsXmlPath, connectionXmlFileString);
@@ -143,7 +212,7 @@ var updateWorkbookSingleQueryAttributes = function (zip, queryName, refreshOnOpe
143
212
  case 2:
144
213
  sharedStringsXmlString = _f.sent();
145
214
  if (sharedStringsXmlString === undefined) {
146
- throw new Error(constants_1.sharedStringsNotFoundErr);
215
+ throw new Error(constants_1.Errors.sharedStringsNotFound);
147
216
  }
148
217
  _b = xmlInnerPartsUtils_1.default.updateSharedStrings(sharedStringsXmlString, queryName), sharedStringIndex = _b.sharedStringIndex, newSharedStrings = _b.newSharedStrings;
149
218
  zip.file(constants_1.sharedStringsXmlPath, newSharedStrings);
@@ -158,7 +227,7 @@ var updateWorkbookSingleQueryAttributes = function (zip, queryName, refreshOnOpe
158
227
  case 5:
159
228
  sheetsXmlString = _f.sent();
160
229
  if (sheetsXmlString === undefined) {
161
- throw new Error(constants_1.sheetsNotFoundErr);
230
+ throw new Error(constants_1.Errors.sheetsNotFound);
162
231
  }
163
232
  worksheetString = xmlInnerPartsUtils_1.default.updateWorksheet(sheetsXmlString, sharedStringIndex.toString());
164
233
  zip.file(sheetPath, worksheetString);
@@ -175,4 +244,5 @@ exports.default = {
175
244
  updateWorkbookDataAndConfigurations: updateWorkbookDataAndConfigurations,
176
245
  updateWorkbookPowerQueryDocument: updateWorkbookPowerQueryDocument,
177
246
  updateWorkbookSingleQueryAttributes: updateWorkbookSingleQueryAttributes,
247
+ addCustomXMLToWorkbook: addCustomXMLToWorkbook
178
248
  };
@@ -53,13 +53,13 @@ var generateSingleQueryWorkbook = function (query, initialDataGrid, fileConfigs)
53
53
  switch (_b.label) {
54
54
  case 0:
55
55
  if (!query.queryMashup) {
56
- throw new Error(constants_1.emptyQueryMashupErr);
56
+ throw new Error(constants_1.Errors.emptyQueryMashup);
57
57
  }
58
58
  if (!query.queryName) {
59
59
  query.queryName = constants_1.defaults.queryName;
60
60
  }
61
61
  if ((fileConfigs === null || fileConfigs === void 0 ? void 0 : fileConfigs.templateFile) !== undefined && initialDataGrid !== undefined) {
62
- throw new Error(constants_1.templateWithInitialDataErr);
62
+ throw new Error(constants_1.Errors.templateWithInitialData);
63
63
  }
64
64
  utils_1.pqUtils.validateQueryName(query.queryName);
65
65
  if (!((fileConfigs === null || fileConfigs === void 0 ? void 0 : fileConfigs.templateFile) === undefined)) return [3 /*break*/, 2];
@@ -110,7 +110,7 @@ var generateTableWorkbookFromGrid = function (grid, fileConfigs) { return __awai
110
110
  zip = _a;
111
111
  tableData = utils_1.gridUtils.parseToTableData(grid);
112
112
  if (tableData === undefined) {
113
- throw new Error(constants_1.tableNotFoundErr);
113
+ throw new Error(constants_1.Errors.tableNotFound);
114
114
  }
115
115
  return [4 /*yield*/, utils_1.xmlPartsUtils.updateWorkbookDataAndConfigurations(zip, fileConfigs, tableData)];
116
116
  case 5:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@microsoft/connected-workbooks",
3
- "version": "3.3.2-beta",
3
+ "version": "3.4.0",
4
4
  "description": "Microsoft backed, Excel advanced xlsx workbook generation JavaScript library",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -14,8 +14,12 @@
14
14
  "build": "tsc",
15
15
  "build-webpack-prod": "webpack --mode=production --node-env=production",
16
16
  "build-webpack-dev": "webpack --mode=development --node-env=development",
17
- "test": "tsc --project tsconfig.test.json && jest",
18
- "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\" --config .prettierrc"
17
+ "clean": "jest --clearCache",
18
+ "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\" --config .prettierrc",
19
+ "test:clean": "npm run clean && npm run test",
20
+ "test:node": "tsc && jest --config jest.config.node.js",
21
+ "test:jsdom": "tsc && jest --config jest.config.jsdom.js",
22
+ "test": "npm run test:jsdom && npm run test:node"
19
23
  },
20
24
  "repository": {
21
25
  "type": "git",
@@ -1,15 +0,0 @@
1
- "use strict";
2
- // Copyright (c) Microsoft Corporation.
3
- // Licensed under the MIT license.
4
- Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.generateCustomXmlFilePath = exports.generateSingleQueryMashup = exports.generateMashupXMLTemplate = void 0;
6
- var generateMashupXMLTemplate = function (base64) {
7
- return "<?xml version=\"1.0\" encoding=\"utf-16\"?><DataMashup xmlns=\"http://schemas.microsoft.com/DataMashup\">".concat(base64, "</DataMashup>");
8
- };
9
- exports.generateMashupXMLTemplate = generateMashupXMLTemplate;
10
- var generateSingleQueryMashup = function (queryName, query) {
11
- return "section Section1;\n \n shared #\"".concat(queryName, "\" = \n ").concat(query, ";");
12
- };
13
- exports.generateSingleQueryMashup = generateSingleQueryMashup;
14
- var generateCustomXmlFilePath = function (i) { return "customXml/item".concat(i, ".xml"); };
15
- exports.generateCustomXmlFilePath = generateCustomXmlFilePath;
package/dist/src/types.js DELETED
@@ -1,28 +0,0 @@
1
- "use strict";
2
- // Copyright (c) Microsoft Corporation.
3
- // Licensed under the MIT license.
4
- Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.DocPropsAutoUpdatedElements = exports.DocPropsModifiableElements = exports.DataTypes = void 0;
6
- var DataTypes;
7
- (function (DataTypes) {
8
- DataTypes[DataTypes["null"] = 0] = "null";
9
- DataTypes[DataTypes["string"] = 1] = "string";
10
- DataTypes[DataTypes["number"] = 2] = "number";
11
- DataTypes[DataTypes["boolean"] = 3] = "boolean";
12
- })(DataTypes = exports.DataTypes || (exports.DataTypes = {}));
13
- var DocPropsModifiableElements;
14
- (function (DocPropsModifiableElements) {
15
- DocPropsModifiableElements["title"] = "dc:title";
16
- DocPropsModifiableElements["subject"] = "dc:subject";
17
- DocPropsModifiableElements["keywords"] = "cp:keywords";
18
- DocPropsModifiableElements["createdBy"] = "dc:creator";
19
- DocPropsModifiableElements["description"] = "dc:description";
20
- DocPropsModifiableElements["lastModifiedBy"] = "cp:lastModifiedBy";
21
- DocPropsModifiableElements["category"] = "cp:category";
22
- DocPropsModifiableElements["revision"] = "cp:revision";
23
- })(DocPropsModifiableElements = exports.DocPropsModifiableElements || (exports.DocPropsModifiableElements = {}));
24
- var DocPropsAutoUpdatedElements;
25
- (function (DocPropsAutoUpdatedElements) {
26
- DocPropsAutoUpdatedElements["created"] = "dcterms:created";
27
- DocPropsAutoUpdatedElements["modified"] = "dcterms:modified";
28
- })(DocPropsAutoUpdatedElements = exports.DocPropsAutoUpdatedElements || (exports.DocPropsAutoUpdatedElements = {}));
@@ -1,51 +0,0 @@
1
- "use strict";
2
- // Copyright (c) Microsoft Corporation.
3
- // Licensed under the MIT license.
4
- Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.ArrayReader = void 0;
6
- var ArrayReader = /** @class */ (function () {
7
- function ArrayReader(array) {
8
- this._array = array;
9
- this._position = 0;
10
- }
11
- ArrayReader.prototype.getInt32 = function () {
12
- var retVal = new DataView(this._array, this._position, 4).getInt32(0, true);
13
- this._position += 4;
14
- return retVal;
15
- };
16
- ArrayReader.prototype.getBytes = function (bytes) {
17
- var retVal = this._array.slice(this._position, bytes ? bytes + this._position : bytes);
18
- this._position += retVal.byteLength;
19
- return new Uint8Array(retVal);
20
- };
21
- ArrayReader.prototype.reset = function () {
22
- this._position = 0;
23
- };
24
- return ArrayReader;
25
- }());
26
- exports.ArrayReader = ArrayReader;
27
- function getInt32Buffer(val) {
28
- var packageSizeBuffer = new ArrayBuffer(4);
29
- new DataView(packageSizeBuffer).setInt32(0, val, true);
30
- return new Uint8Array(packageSizeBuffer);
31
- }
32
- function concatArrays() {
33
- var args = [];
34
- for (var _i = 0; _i < arguments.length; _i++) {
35
- args[_i] = arguments[_i];
36
- }
37
- var size = 0;
38
- args.forEach(function (arr) { return (size += arr.byteLength); });
39
- var retVal = new Uint8Array(size);
40
- var position = 0;
41
- args.forEach(function (arr) {
42
- retVal.set(arr, position);
43
- position += arr.byteLength;
44
- });
45
- return retVal;
46
- }
47
- exports.default = {
48
- ArrayReader: ArrayReader,
49
- getInt32Buffer: getInt32Buffer,
50
- concatArrays: concatArrays,
51
- };