@microsoft/connected-workbooks
Version:
Microsoft backed, Excel advanced xlsx workbook generation JavaScript library
664 lines (663 loc) • 37.4 kB
JavaScript
;
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var types_1 = require("../types");
var constants_1 = require("./constants");
var documentUtils_1 = __importDefault(require("./documentUtils"));
var xmldom_qsa_1 = require("xmldom-qsa");
/**
* Helper function to check for XML parser errors without using querySelector
* @param doc - The parsed XML document
* @param context - Context string for error message
* @throws {Error} If parser error is detected
*/
var checkParserError = function (doc, context) {
if (!doc || !doc.documentElement) {
throw new Error("".concat(context, ": ").concat(constants_1.Errors.xmlParse));
}
// Check for parsererror elements using getElementsByTagName
var errorElements = doc.getElementsByTagName("parsererror");
if (errorElements && errorElements.length > 0) {
var errorText = errorElements[0].textContent || "Unknown parser error";
throw new Error("".concat(context, ": ").concat(errorText));
}
};
var updateDocProps = function (zip, docProps) {
if (docProps === void 0) { docProps = {}; }
return __awaiter(void 0, void 0, void 0, function () {
var _a, doc, properties, docPropsAutoUpdatedElementsArr, nowTime, docPropsModifiableElementsArr, serializer, newDoc;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, documentUtils_1.default.getDocPropsProperties(zip)];
case 1:
_a = _b.sent(), doc = _a.doc, properties = _a.properties;
docPropsAutoUpdatedElementsArr = Object.keys(types_1.DocPropsAutoUpdatedElements);
nowTime = new Date().toISOString();
docPropsAutoUpdatedElementsArr.forEach(function (tag) {
documentUtils_1.default.createOrUpdateProperty(doc, properties, types_1.DocPropsAutoUpdatedElements[tag], nowTime);
});
docPropsModifiableElementsArr = Object.keys(types_1.DocPropsModifiableElements);
docPropsModifiableElementsArr
.map(function (key) { return ({
name: types_1.DocPropsModifiableElements[key],
value: docProps[key],
}); })
.forEach(function (kvp) {
documentUtils_1.default.createOrUpdateProperty(doc, properties, kvp.name, kvp.value);
});
serializer = new xmldom_qsa_1.XMLSerializer();
newDoc = serializer.serializeToString(doc);
zip.file(constants_1.docPropsCoreXmlPath, newDoc);
return [2 /*return*/];
}
});
});
};
var removeLabelInfoRelationship = function (doc, relationships) {
// Find and remove LabelInfo.xml relationship
var relationshipElements = doc.getElementsByTagName(constants_1.element.relationship);
for (var i = 0; i < relationshipElements.length; i++) {
var rel = relationshipElements[i];
if (rel.getAttribute(constants_1.elementAttributes.target) === constants_1.labelInfoXmlPath) {
relationships.removeChild(rel);
break;
}
}
};
var updateRelationshipIds = function (doc) {
// Update relationship IDs
var relationshipElements = doc.getElementsByTagName(constants_1.element.relationship);
for (var i = 0; i < relationshipElements.length; i++) {
var rel = relationshipElements[i];
var target = rel.getAttribute(constants_1.elementAttributes.target);
if (target === constants_1.workbookXmlPath) {
rel.setAttribute(constants_1.elementAttributes.Id, constants_1.elementAttributes.relationId1);
}
else if (target === constants_1.docPropsCoreXmlPath) {
rel.setAttribute(constants_1.elementAttributes.Id, constants_1.elementAttributes.relationId2);
}
else if (target === constants_1.docPropsAppXmlPath) {
rel.setAttribute(constants_1.elementAttributes.Id, constants_1.elementAttributes.relationId3);
}
}
};
var clearLabelInfo = function (zip) { return __awaiter(void 0, void 0, void 0, function () {
var relsString, parser, doc, relationshipsList, relationships, serializer, newDoc;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
// remove docMetadata folder that contains only LabelInfo.xml in template file.
zip.remove(constants_1.docMetadataXmlPath);
return [4 /*yield*/, ((_a = zip.file(constants_1.relsXmlPath)) === null || _a === void 0 ? void 0 : _a.async(constants_1.textResultType))];
case 1:
relsString = _b.sent();
if (relsString === undefined) {
throw new Error(constants_1.Errors.relsNotFound);
}
parser = new xmldom_qsa_1.DOMParser();
doc = parser.parseFromString(relsString, constants_1.xmlTextResultType);
checkParserError(doc, constants_1.Errors.relsParse);
relationshipsList = doc.getElementsByTagName(constants_1.element.relationships);
if (!relationshipsList || relationshipsList.length === 0) {
throw new Error(constants_1.Errors.relationship);
}
relationships = relationshipsList[0];
if (!relationships) {
throw new Error(constants_1.Errors.relationship);
}
removeLabelInfoRelationship(doc, relationships);
updateRelationshipIds(doc);
serializer = new xmldom_qsa_1.XMLSerializer();
newDoc = serializer.serializeToString(doc);
zip.file(constants_1.relsXmlPath, newDoc);
return [2 /*return*/];
}
});
}); };
var updateConnections = function (connectionsXmlString, queryName, refreshOnOpen) {
var _a, _b, _c;
var parser = new xmldom_qsa_1.DOMParser();
var serializer = new xmldom_qsa_1.XMLSerializer();
var refreshOnLoadValue = refreshOnOpen ? constants_1.trueValue : constants_1.falseValue;
var connectionsDoc = parser.parseFromString(connectionsXmlString, constants_1.xmlTextResultType);
checkParserError(connectionsDoc, constants_1.Errors.connectionsParse);
var connectionsProperties = connectionsDoc.getElementsByTagName(constants_1.element.databaseProperties);
var dbPr = connectionsProperties[0];
dbPr.setAttribute(constants_1.elementAttributes.refreshOnLoad, refreshOnLoadValue);
// Update query details to match queryName
(_a = dbPr.parentNode) === null || _a === void 0 ? void 0 : _a.setAttribute(constants_1.elementAttributes.name, constants_1.elementAttributesValues.connectionName(queryName));
(_b = dbPr.parentNode) === null || _b === void 0 ? void 0 : _b.setAttribute(constants_1.elementAttributes.description, constants_1.elementAttributesValues.connectionDescription(queryName));
dbPr.setAttribute(constants_1.elementAttributes.connection, constants_1.elementAttributesValues.connection(queryName));
dbPr.setAttribute(constants_1.elementAttributes.command, constants_1.elementAttributesValues.connectionCommand(queryName));
var connectionId = (_c = dbPr.parentNode) === null || _c === void 0 ? void 0 : _c.getAttribute(constants_1.elementAttributes.id);
var connectionXmlFileString = serializer.serializeToString(connectionsDoc);
if (connectionId === null) {
throw new Error(constants_1.Errors.connectionsNotFound);
}
return { connectionId: connectionId, connectionXmlFileString: connectionXmlFileString };
};
var updateSharedStrings = function (sharedStringsXmlString, queryName) {
var parser = new xmldom_qsa_1.DOMParser();
var serializer = new xmldom_qsa_1.XMLSerializer();
var sharedStringsDoc = parser.parseFromString(sharedStringsXmlString, constants_1.xmlTextResultType);
checkParserError(sharedStringsDoc, constants_1.Errors.sharedStringsParse);
var sharedStringsTable = sharedStringsDoc.getElementsByTagName(constants_1.element.sharedStringTable)[0];
if (!sharedStringsTable) {
throw new Error(constants_1.Errors.sharedStringsNotFound);
}
var textElementCollection = sharedStringsDoc.getElementsByTagName(constants_1.element.text);
var textElement = null;
var sharedStringIndex = textElementCollection.length;
if (textElementCollection && textElementCollection.length) {
for (var i = 0; i < textElementCollection.length; i++) {
if (textElementCollection[i].textContent === queryName) {
textElement = textElementCollection[i];
sharedStringIndex = i + 1;
break;
}
}
}
if (textElement === null) {
if (sharedStringsDoc.documentElement.namespaceURI) {
textElement = sharedStringsDoc.createElementNS(sharedStringsDoc.documentElement.namespaceURI, constants_1.element.text);
textElement.textContent = queryName;
var siElement = sharedStringsDoc.createElementNS(sharedStringsDoc.documentElement.namespaceURI, constants_1.element.sharedStringItem);
siElement.appendChild(textElement);
sharedStringsDoc.getElementsByTagName(constants_1.element.sharedStringTable)[0].appendChild(siElement);
}
var value = sharedStringsTable.getAttribute(constants_1.elementAttributes.count);
if (value) {
sharedStringsTable.setAttribute(constants_1.elementAttributes.count, (parseInt(value) + 1).toString());
}
var uniqueValue = sharedStringsTable.getAttribute(constants_1.elementAttributes.uniqueCount);
if (uniqueValue) {
sharedStringsTable.setAttribute(constants_1.elementAttributes.uniqueCount, (parseInt(uniqueValue) + 1).toString());
}
}
var newSharedStrings = serializer.serializeToString(sharedStringsDoc);
return { sharedStringIndex: sharedStringIndex, newSharedStrings: newSharedStrings };
};
var updateWorksheet = function (sheetsXmlString, sharedStringIndex) {
var parser = new xmldom_qsa_1.DOMParser();
var serializer = new xmldom_qsa_1.XMLSerializer();
var sheetsDoc = parser.parseFromString(sheetsXmlString, constants_1.xmlTextResultType);
checkParserError(sheetsDoc, constants_1.Errors.worksheetParse);
sheetsDoc.getElementsByTagName(constants_1.element.cellValue)[0].innerHTML = sharedStringIndex.toString();
var newSheet = serializer.serializeToString(sheetsDoc);
return newSheet;
};
var updatePivotTablesandQueryTables = function (zip, queryName, refreshOnOpen, connectionId) { return __awaiter(void 0, void 0, void 0, function () {
var found, queryTablePromises, pivotCachePromises;
var _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
found = false;
queryTablePromises = [];
(_a = zip.folder(constants_1.queryTablesPath)) === null || _a === void 0 ? void 0 : _a.forEach(function (relativePath, queryTableFile) { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
queryTablePromises.push((function () {
return queryTableFile.async(constants_1.textResultType).then(function (queryTableString) {
return {
path: relativePath,
queryTableXmlString: queryTableString,
};
});
})());
return [2 /*return*/];
});
}); });
return [4 /*yield*/, Promise.all(queryTablePromises)];
case 1:
(_c.sent()).forEach(function (_a) {
var path = _a.path, queryTableXmlString = _a.queryTableXmlString;
var _b = updateQueryTable(queryTableXmlString, connectionId, refreshOnOpen), isQueryTableUpdated = _b.isQueryTableUpdated, newQueryTable = _b.newQueryTable;
zip.file(constants_1.queryTablesPath + path, newQueryTable);
if (isQueryTableUpdated) {
found = true;
}
});
if (found) {
return [2 /*return*/];
}
pivotCachePromises = [];
(_b = zip.folder(constants_1.pivotCachesPath)) === null || _b === void 0 ? void 0 : _b.forEach(function (relativePath, pivotCacheFile) { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
if (relativePath.startsWith(constants_1.pivotCachesPathPrefix)) {
pivotCachePromises.push((function () {
return pivotCacheFile.async(constants_1.textResultType).then(function (pivotCacheString) {
return {
path: relativePath,
pivotCacheXmlString: pivotCacheString,
};
});
})());
}
return [2 /*return*/];
});
}); });
return [4 /*yield*/, Promise.all(pivotCachePromises)];
case 2:
(_c.sent()).forEach(function (_a) {
var path = _a.path, pivotCacheXmlString = _a.pivotCacheXmlString;
var _b = updatePivotTable(pivotCacheXmlString, connectionId, refreshOnOpen), isPivotTableUpdated = _b.isPivotTableUpdated, newPivotTable = _b.newPivotTable;
zip.file(constants_1.pivotCachesPath + path, newPivotTable);
if (isPivotTableUpdated) {
found = true;
}
});
if (!found) {
throw new Error(constants_1.Errors.queryAndPivotTableNotFound);
}
return [2 /*return*/];
}
});
}); };
var updateQueryTable = function (tableXmlString, connectionId, refreshOnOpen) {
var refreshOnLoadValue = refreshOnOpen ? constants_1.trueValue : constants_1.falseValue;
var isQueryTableUpdated = false;
var parser = new xmldom_qsa_1.DOMParser();
var serializer = new xmldom_qsa_1.XMLSerializer();
var queryTableDoc = parser.parseFromString(tableXmlString, constants_1.xmlTextResultType);
checkParserError(queryTableDoc, constants_1.Errors.queryTableParse);
var queryTable = queryTableDoc.getElementsByTagName(constants_1.element.queryTable)[0];
var newQueryTable = constants_1.emptyValue;
if (queryTable.getAttribute(constants_1.elementAttributes.connectionId) == connectionId) {
queryTable.setAttribute(constants_1.elementAttributes.refreshOnLoad, refreshOnLoadValue);
newQueryTable = serializer.serializeToString(queryTableDoc);
isQueryTableUpdated = true;
}
return { isQueryTableUpdated: isQueryTableUpdated, newQueryTable: newQueryTable };
};
var updatePivotTable = function (tableXmlString, connectionId, refreshOnOpen) {
var refreshOnLoadValue = refreshOnOpen ? constants_1.trueValue : constants_1.falseValue;
var isPivotTableUpdated = false;
var parser = new xmldom_qsa_1.DOMParser();
var serializer = new xmldom_qsa_1.XMLSerializer();
var pivotCacheDoc = parser.parseFromString(tableXmlString, constants_1.xmlTextResultType);
checkParserError(pivotCacheDoc, constants_1.Errors.pivotTableParse);
var cacheSource = pivotCacheDoc.getElementsByTagName(constants_1.element.cacheSource)[0];
var newPivotTable = constants_1.emptyValue;
if (cacheSource.getAttribute(constants_1.elementAttributes.connectionId) == connectionId) {
cacheSource = cacheSource.parentElement;
cacheSource.setAttribute(constants_1.elementAttributes.refreshOnLoad, refreshOnLoadValue);
newPivotTable = serializer.serializeToString(pivotCacheDoc);
isPivotTableUpdated = true;
}
return { isPivotTableUpdated: isPivotTableUpdated, newPivotTable: newPivotTable };
};
/**
* Retrieves the target path of a sheet from workbook relationships by its relationship ID.
*/
function getSheetPathFromXlRelId(zip, rId) {
return __awaiter(this, void 0, void 0, function () {
var relsFile, relsString, relsDoc, relationships, target, i, el;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
relsFile = zip.file(constants_1.workbookRelsXmlPath);
if (!relsFile) {
throw new Error(constants_1.Errors.xlRelsNotFound);
}
return [4 /*yield*/, relsFile.async(constants_1.textResultType)];
case 1:
relsString = _a.sent();
relsDoc = new xmldom_qsa_1.DOMParser().parseFromString(relsString, constants_1.xmlTextResultType);
checkParserError(relsDoc, constants_1.Errors.workbookRelsParse);
relationships = relsDoc.getElementsByTagName("Relationship");
target = null;
for (i = 0; i < relationships.length; i++) {
el = relationships[i];
if (el && el.getAttribute && el.getAttribute("Id") === rId) {
target = el.getAttribute(constants_1.elementAttributes.target);
break;
}
}
if (!target) {
throw new Error("Relationship not found or missing Target for Id: ".concat(rId));
}
return [2 /*return*/, target];
}
});
});
}
// get sheet name from workbook
var getSheetPathByNameFromZip = function (zip, sheetName) { return __awaiter(void 0, void 0, void 0, function () {
var workbookXmlString, parser, doc, sheetElements, i, rId;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, ((_a = zip.file(constants_1.workbookXmlPath)) === null || _a === void 0 ? void 0 : _a.async("text"))];
case 1:
workbookXmlString = _b.sent();
if (!workbookXmlString) {
throw new Error(constants_1.Errors.workbookNotFound);
}
parser = new xmldom_qsa_1.DOMParser();
doc = parser.parseFromString(workbookXmlString, constants_1.xmlTextResultType);
checkParserError(doc, constants_1.Errors.workbookParse);
sheetElements = doc.getElementsByTagName(constants_1.element.sheet);
for (i = 0; i < sheetElements.length; i++) {
if (sheetElements[i].getAttribute(constants_1.elementAttributes.name) === sheetName) {
rId = sheetElements[i].getAttribute(constants_1.elementAttributes.relationId);
if (rId) {
return [2 /*return*/, getSheetPathFromXlRelId(zip, rId)];
}
}
}
throw new Error("Sheet with name ".concat(sheetName, " not found"));
}
});
}); };
// get definedName
var getReferenceFromTable = function (zip, tablePath) { return __awaiter(void 0, void 0, void 0, function () {
var tableXmlString, parser, doc, tableElements, reference;
var _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0: return [4 /*yield*/, ((_a = zip.file(tablePath)) === null || _a === void 0 ? void 0 : _a.async("text"))];
case 1:
tableXmlString = _c.sent();
if (!tableXmlString) {
throw new Error(constants_1.Errors.workbookNotFound);
}
parser = new xmldom_qsa_1.DOMParser();
doc = parser.parseFromString(tableXmlString, constants_1.xmlTextResultType);
checkParserError(doc, constants_1.Errors.tableParse);
tableElements = doc.getElementsByTagName(constants_1.element.table);
reference = (_b = tableElements[0]) === null || _b === void 0 ? void 0 : _b.getAttribute(constants_1.elementAttributes.reference);
if (!reference) {
throw new Error(constants_1.Errors.tableReferenceNotFound);
}
return [2 /*return*/, reference.split(":")[0]]; // Return the start cell reference (e.g., "A1" from "A1:B10")
}
});
}); };
var findTablePathFromZip = function (zip, targetTableName) { return __awaiter(void 0, void 0, void 0, function () {
var tablesFolder, tableFilePromises, tableFiles, parser, _i, tableFiles_1, _a, path, content, doc, tableElem;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
tablesFolder = zip.folder(constants_1.tablesFolderPath);
if (!tablesFolder)
return [2 /*return*/, constants_1.emptyValue];
tableFilePromises = [];
tablesFolder.forEach(function (relativePath, file) {
tableFilePromises.push(file.async(constants_1.textResultType).then(function (content) { return ({ path: relativePath, content: content }); }));
});
return [4 /*yield*/, Promise.all(tableFilePromises)];
case 1:
tableFiles = _b.sent();
parser = new xmldom_qsa_1.DOMParser();
for (_i = 0, tableFiles_1 = tableFiles; _i < tableFiles_1.length; _i++) {
_a = tableFiles_1[_i], path = _a.path, content = _a.content;
doc = parser.parseFromString(content, constants_1.xmlTextResultType);
checkParserError(doc, "".concat(constants_1.Errors.tablePathParse, " ").concat(path));
tableElem = doc.getElementsByTagName(constants_1.element.table)[0];
if (tableElem && tableElem.getAttribute(constants_1.elementAttributes.name) === targetTableName) {
return [2 /*return*/, path];
}
}
throw new Error(constants_1.Errors.tableNotFound);
}
});
}); };
/**
* Determines the next available item number for a custom XML item in the Excel workbook.
* Scans the customXml folder to find existing item files and returns the next sequential number.
*
* @param zip - The JSZip instance containing the Excel workbook structure
* @returns Promise resolving to the next available item number (starting from 1 if no items exist)
*
* @example
* // If customXml folder contains item1.xml, item2.xml, returns 3
* const nextNumber = await getCustomXmlItemNumber(zip);
*/
var getCustomXmlItemNumber = function (zip) { return __awaiter(void 0, void 0, void 0, function () {
var customXmlFolder, re, matches, max, _i, matches_1, f, m, n;
return __generator(this, function (_a) {
customXmlFolder = zip.folder(constants_1.customXmlXmlPath);
if (!customXmlFolder) {
return [2 /*return*/, 1]; // start from 1 if folder doesn't exist
}
re = new RegExp("^".concat(constants_1.customXmlXmlPath, "/").concat(constants_1.customXML.itemNumberPattern.source, "$"));
matches = zip.file(re);
max = 0;
// Iterate through all matching files to find the highest item number
for (_i = 0, matches_1 = matches; _i < matches_1.length; _i++) {
f = matches_1[_i];
m = f.name.match(constants_1.customXML.itemNumberPattern);
if (m) {
n = parseInt(m[1], 10);
if (!Number.isNaN(n) && n > max) {
max = n;
}
}
}
return [2 /*return*/, max + 1]; // Return next available number
});
}); };
/**
* Checks if a custom XML item with connected-workbooks already exists in the Excel workbook.
* Searches through all custom XML files in the customXml folder to find a match with the expected content.
*
* @param zip - The JSZip instance containing the Excel workbook structure
* @returns Promise resolving to true if the custom XML item exists, false otherwise
*
* @example
* const exists = await isCustomXmlExists(zip);
* if (!exists) {
* // Add new custom XML item
* }
*/
var isCustomXmlExists = function (zip) { return __awaiter(void 0, void 0, void 0, function () {
var customXmlFolder, customXmlFiles, _i, customXmlFiles_1, file, content, error_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
customXmlFolder = zip.folder(constants_1.customXmlXmlPath);
if (!customXmlFolder) {
return [2 /*return*/, false]; // customXml folder does not exist
}
customXmlFiles = customXmlFolder.file(constants_1.customXML.itemFilePattern);
_i = 0, customXmlFiles_1 = customXmlFiles;
_a.label = 1;
case 1:
if (!(_i < customXmlFiles_1.length)) return [3 /*break*/, 6];
file = customXmlFiles_1[_i];
_a.label = 2;
case 2:
_a.trys.push([2, 4, , 5]);
return [4 /*yield*/, file.async(constants_1.textResultType)];
case 3:
content = _a.sent();
if (content.includes(constants_1.customXML.connectedWorkbookTag)) {
return [2 /*return*/, true]; // Found matching custom XML item
}
return [3 /*break*/, 5];
case 4:
error_1 = _a.sent();
// Skip files that can't be read and continue with the next file
return [3 /*break*/, 5];
case 5:
_i++;
return [3 /*break*/, 1];
case 6: return [2 /*return*/, false]; // No matching custom XML item found
}
});
}); };
/**
* Adds a content type override entry to the [Content_Types].xml file for a custom XML item.
* This registration is required for Excel to recognize and process the custom XML item.
*
* @param zip - The JSZip instance containing the Excel workbook structure
* @param itemIndex - The index/number of the custom XML item to register
* @throws {Error} When the [Content_Types].xml file is not found or cannot be parsed
*
* @example
* await addToContentType(zip, "1"); // Registers customXml/item1.xml in content types
*/
var addToContentType = function (zip, itemIndex) { return __awaiter(void 0, void 0, void 0, function () {
var contentTypesXmlString, parser, doc, partName, contentTypeValue, typesElement, ns, overrideEl, serializer, newDoc;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, ((_a = zip.file(constants_1.contentTypesXmlPath)) === null || _a === void 0 ? void 0 : _a.async(constants_1.textResultType))];
case 1:
contentTypesXmlString = _b.sent();
if (!contentTypesXmlString) {
throw new Error(constants_1.Errors.contentTypesNotFound);
}
parser = new xmldom_qsa_1.DOMParser();
doc = parser.parseFromString(contentTypesXmlString, constants_1.xmlTextResultType);
checkParserError(doc, constants_1.Errors.contentTypesParse);
partName = constants_1.customXML.itemPropsPartNameTemplate(itemIndex);
contentTypeValue = constants_1.customXML.contentType;
typesElement = doc.documentElement;
if (!typesElement) {
throw new Error(constants_1.Errors.contentTypesElementNotFound);
}
ns = doc.documentElement.namespaceURI;
overrideEl = ns ? doc.createElementNS(ns, constants_1.element.override) : doc.createElement(constants_1.element.override);
overrideEl.setAttribute(constants_1.elementAttributes.partName, partName);
overrideEl.setAttribute(constants_1.elementAttributes.contentType, contentTypeValue);
typesElement.appendChild(overrideEl);
serializer = new xmldom_qsa_1.XMLSerializer();
newDoc = serializer.serializeToString(doc);
zip.file(constants_1.contentTypesXmlPath, newDoc);
return [2 /*return*/];
}
});
}); };
/**
* Adds a relationship entry to the workbook relationships file for a custom XML item.
* Creates a new relationship that links the workbook to the custom XML item.
*
* @param zip - The JSZip instance containing the Excel workbook structure
* @param itemIndex - The index/number of the custom XML item to create a relationship for
* @throws {Error} When the workbook relationships file is not found or cannot be parsed
*
* @example
* await addCustomXmlToRels(zip, "1"); // Creates relationship to customXml/item1.xml
*/
var addCustomXmlToRels = function (zip, itemIndex) { return __awaiter(void 0, void 0, void 0, function () {
var relsXmlString, parser, doc, relationshipsElements, relationshipsElement, highestRid, newRid, target, type, ns, relationshipEl, serializer, newDoc;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, ((_a = zip.file(constants_1.workbookRelsXmlPath)) === null || _a === void 0 ? void 0 : _a.async(constants_1.textResultType))];
case 1:
relsXmlString = _b.sent();
if (!relsXmlString) {
throw new Error(constants_1.Errors.relsNotFound);
}
parser = new xmldom_qsa_1.DOMParser();
doc = parser.parseFromString(relsXmlString, constants_1.xmlTextResultType);
checkParserError(doc, constants_1.Errors.workbookRelsParse);
relationshipsElements = doc.getElementsByTagName(constants_1.element.relationships);
if (!relationshipsElements || relationshipsElements.length === 0) {
throw new Error(constants_1.Errors.relationship);
}
relationshipsElement = relationshipsElements[0];
highestRid = getHighestRelationshipId(relationshipsElement);
newRid = "".concat(constants_1.elementAttributes.relationshipIdPrefix).concat(highestRid + 1);
target = constants_1.customXML.relativeItemPathTemplate(itemIndex);
type = constants_1.customXML.relationshipType;
ns = doc.documentElement.namespaceURI;
relationshipEl = ns ? doc.createElementNS(ns, constants_1.element.relationship) : doc.createElement(constants_1.element.relationship);
relationshipEl.setAttribute(constants_1.elementAttributes.Id, newRid);
relationshipEl.setAttribute(constants_1.elementAttributes.type, type);
relationshipEl.setAttribute(constants_1.elementAttributes.target, target);
relationshipsElement.appendChild(relationshipEl);
serializer = new xmldom_qsa_1.XMLSerializer();
newDoc = serializer.serializeToString(doc);
zip.file(constants_1.workbookRelsXmlPath, newDoc);
return [2 /*return*/];
}
});
}); };
/**
* Finds the highest relationship ID number from existing relationships in a relationships element.
* Scans all relationship elements and extracts the numeric part from rId attributes.
*
* @param relationshipsElement - The relationships XML element containing relationship elements
* @returns The highest relationship ID number found, or 0 if none exist
*
* @example
* // If relationships contain rId1, rId3, rId7, returns 7
* const highestRid = getHighestRelationshipId(relationshipsElement);
*/
var getHighestRelationshipId = function (relationshipsElement) {
var relationships = relationshipsElement.getElementsByTagName(constants_1.element.relationship);
var highestRid = 0;
for (var i = 0; i < relationships.length; i++) {
var idAttr = relationships[i].getAttribute(constants_1.elementAttributes.Id);
if (idAttr && idAttr.startsWith(constants_1.elementAttributes.relationshipIdPrefix)) {
// Extract numeric part from rId (e.g., "rId5" -> 5, "rId123" -> 123)
var ridNumber = parseInt(idAttr.substring(constants_1.elementAttributes.relationshipIdPrefix.length), 10);
if (!isNaN(ridNumber) && ridNumber > highestRid) {
highestRid = ridNumber;
}
}
}
return highestRid;
};
exports.default = {
updateDocProps: updateDocProps,
clearLabelInfo: clearLabelInfo,
updateConnections: updateConnections,
updateSharedStrings: updateSharedStrings,
updateWorksheet: updateWorksheet,
updatePivotTablesandQueryTables: updatePivotTablesandQueryTables,
updateQueryTable: updateQueryTable,
updatePivotTable: updatePivotTable,
getSheetPathByNameFromZip: getSheetPathByNameFromZip,
getReferenceFromTable: getReferenceFromTable,
findTablePathFromZip: findTablePathFromZip,
getCustomXmlItemNumber: getCustomXmlItemNumber,
isCustomXmlExists: isCustomXmlExists,
addToContentType: addToContentType,
addCustomXmlToRels: addCustomXmlToRels,
checkParserError: checkParserError,
};