From 59544ee961f2aa637ca8c90a0b2477c0fa5aadb1 Mon Sep 17 00:00:00 2001 From: Matt Carvin <90224411+mcarvin8@users.noreply.github.com> Date: Thu, 22 Feb 2024 11:08:35 -0500 Subject: [PATCH] fix: dynamically get xml namespace and add to disassembled/reassembled files if defined --- README.md | 2 - src/service/buildDisassembledFiles.ts | 22 ++++++++-- src/service/buildReassembledFiles.ts | 2 +- src/service/reassembleXMLFileHandler.ts | 24 ++++++---- .../HR_Admin.permissionset-meta.xml | 44 +++++++++++++++++++ test/main.spec.ts | 23 +++++++++- 6 files changed, 100 insertions(+), 17 deletions(-) create mode 100644 test/baselines/no-namespace/HR_Admin.permissionset-meta.xml diff --git a/README.md b/README.md index 0fd2ad0..6a2278c 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,6 @@ Import the `ReassembleXMLFileHandler` class from the package. /* FLAGS - xmlPath: Path to the disassembled XML files to reassemble (must be a directory) -- xmlNamespace: (Optional) Namespace for the final XML (default: None) - fileExtension: (Optional) Desired file extension for the final XML (default: `.xml`) */ import { ReassembleXMLFileHandler } from "xml-disassembler"; @@ -135,7 +134,6 @@ import { ReassembleXMLFileHandler } from "xml-disassembler"; const handler = new ReassembleXMLFileHandler(); await handler.reassemble({ xmlPath: "test/baselines/general/HR_Admin", - xmlNamespace: "http://soap.sforce.com/2006/04/metadata", fileExtension: "permissionset-meta.xml", }); ``` diff --git a/src/service/buildDisassembledFiles.ts b/src/service/buildDisassembledFiles.ts index 198acc2..e872fff 100644 --- a/src/service/buildDisassembledFiles.ts +++ b/src/service/buildDisassembledFiles.ts @@ -18,9 +18,14 @@ export function buildDisassembledFiles( ): void { const xmlParser = new XMLParser(XML_PARSER_OPTION); const result = xmlParser.parse(xmlString) as Record; - const rootElementName = Object.keys(result)[1]; const rootElement: XmlElement = result[rootElementName]; + let rootElementNamespace: string | undefined; + if (rootElement["@_xmlns"] !== undefined) { + rootElementNamespace = String(rootElement["@_xmlns"]); + } else { + rootElementNamespace = undefined; + } let leafContent = ""; let leafCount = 0; @@ -37,6 +42,7 @@ export function buildDisassembledFiles( metadataPath, uniqueIdElements, rootElementName, + rootElementNamespace, key, indent, ); @@ -52,6 +58,7 @@ export function buildDisassembledFiles( metadataPath, uniqueIdElements, rootElementName, + rootElementNamespace, key, indent, ); @@ -66,7 +73,11 @@ export function buildDisassembledFiles( if (leafCount > 0) { let leafFile = `${XML_HEADER}\n`; - leafFile += `<${rootElementName}>\n`; + leafFile += `<${rootElementName}`; + if (rootElementNamespace) { + leafFile += ` xmlns="${rootElementNamespace}"`; + } + leafFile += `>\n`; const sortedLeafContent = leafContent .split("\n") // Split by lines @@ -87,6 +98,7 @@ function buildNestedFile( metadataPath: string, uniqueIdElements: string | undefined, rootElementName: string, + rootElementNamespace: string | undefined, parentKey: string, indent: string, ): void { @@ -104,7 +116,11 @@ function buildNestedFile( // Call the buildNestedElements to build the XML content string elementContent = buildNestedElements(element); let decomposeFileContents = `${XML_HEADER}\n`; - decomposeFileContents += `<${rootElementName}>\n`; + decomposeFileContents += `<${rootElementName}`; + if (rootElementNamespace) { + decomposeFileContents += ` xmlns="${rootElementNamespace}"`; + } + decomposeFileContents += `>\n`; decomposeFileContents += `${indent}<${parentKey}>\n`; decomposeFileContents += `${elementContent}\n`; decomposeFileContents += `${indent}\n`; diff --git a/src/service/buildReassembledFiles.ts b/src/service/buildReassembledFiles.ts index 60bd9f1..30faf07 100644 --- a/src/service/buildReassembledFiles.ts +++ b/src/service/buildReassembledFiles.ts @@ -7,7 +7,7 @@ export async function buildReassembledFile( combinedXmlContents: string[], filePath: string, xmlElement: string, - xmlNamespace?: string | undefined, + xmlNamespace: string | undefined, ): Promise { // Combine XML contents into a single string let finalXmlContent = combinedXmlContents.join("\n"); diff --git a/src/service/reassembleXMLFileHandler.ts b/src/service/reassembleXMLFileHandler.ts index 3bf4fd6..8894218 100644 --- a/src/service/reassembleXMLFileHandler.ts +++ b/src/service/reassembleXMLFileHandler.ts @@ -34,7 +34,7 @@ export class ReassembleXMLFileHandler { async processFilesForRootElement( dirPath: string, - ): Promise { + ): Promise<[string, string | undefined] | undefined> { const files = await fs.readdir(dirPath); const xmlParser = new XMLParser(XML_PARSER_OPTION); @@ -57,9 +57,15 @@ export class ReassembleXMLFileHandler { XmlElement >; const rootElementName = Object.keys(xmlParsed)[1]; + const rootElement: XmlElement = xmlParsed[rootElementName]; + let rootElementNamespace: string | undefined; + if (rootElement["@_xmlns"] !== undefined) { + rootElementNamespace = String(rootElement["@_xmlns"]); + } else { + rootElementNamespace = undefined; + } if (rootElementName !== undefined) { - // Found root element name, return it - return rootElementName; + return [rootElementName, rootElementNamespace]; } } } @@ -70,10 +76,9 @@ export class ReassembleXMLFileHandler { async reassemble(xmlAttributes: { xmlPath: string; - xmlNamespace?: string; fileExtension?: string; }): Promise { - const { xmlPath, xmlNamespace, fileExtension } = xmlAttributes; + const { xmlPath, fileExtension } = xmlAttributes; const combinedXmlContents: string[] = []; const fileStat = await fs.stat(xmlPath); @@ -95,8 +100,8 @@ export class ReassembleXMLFileHandler { } } - // Process at least one XML file to get the `rootElementName` - let rootElementName = await this.processFilesForRootElement(xmlPath); + // Process at least one XML file to get the `rootElementName` and `rootElementNamespace` + const rootResult = await this.processFilesForRootElement(xmlPath); const parentDirectory = path.dirname(xmlPath); // Get the parent directory path const subdirectoryBasename = path.basename(xmlPath); @@ -105,12 +110,13 @@ export class ReassembleXMLFileHandler { : `${subdirectoryBasename}.xml`; const filePath = path.join(parentDirectory, fileName); - if (rootElementName !== undefined) { + if (rootResult !== undefined) { + const [rootElementName, rootElementNamespace] = rootResult; await buildReassembledFile( combinedXmlContents, filePath, rootElementName, - xmlNamespace, + rootElementNamespace, ); } else { console.error("Root element name is undefined"); diff --git a/test/baselines/no-namespace/HR_Admin.permissionset-meta.xml b/test/baselines/no-namespace/HR_Admin.permissionset-meta.xml new file mode 100644 index 0000000..3cb4d38 --- /dev/null +++ b/test/baselines/no-namespace/HR_Admin.permissionset-meta.xml @@ -0,0 +1,44 @@ + + + + JobApps__Recruiting + true + + + Send_Email_Confirmation + true + + + true + Job_Request__c.Salary__c + true + + Grants all rights needed for an HR administrator to manage employees. + + Salesforce + + true + true + true + true + true + true + Job_Request__c + + + Job_Request_Web_Form + true + + + Recruiting.DevManager + true + + + Job_Request__c + Available + + + true + APIEnabled + + \ No newline at end of file diff --git a/test/main.spec.ts b/test/main.spec.ts index 92134df..0f7c513 100644 --- a/test/main.spec.ts +++ b/test/main.spec.ts @@ -27,7 +27,6 @@ describe("main function", () => { const handler = new ReassembleXMLFileHandler(); await handler.reassemble({ xmlPath: "test/baselines/general/HR_Admin", - xmlNamespace: "http://soap.sforce.com/2006/04/metadata", fileExtension: "permissionset-meta.xml", }); @@ -96,7 +95,6 @@ describe("main function", () => { const handler = new ReassembleXMLFileHandler(); await handler.reassemble({ xmlPath: "test/baselines/array-of-leafs/Dreamhouse", - xmlNamespace: "http://soap.sforce.com/2006/04/metadata", fileExtension: "app-meta.xml", }); @@ -110,6 +108,27 @@ describe("main function", () => { purge: true, }); + // Ensure that the console.log spy was called with the correct message + expect(console.log).toHaveBeenCalled(); + }); + it('should disassemble a XML file with no namespace."', async () => { + const handler = new DisassembleXMLFileHandler(); + await handler.disassemble({ + xmlPath: "test/baselines/no-namespace", + uniqueIdElements: + "application,apexClass,name,externalDataSource,flow,object,apexPage,recordType,tab,field", + }); + + // Ensure that the console.log spy was called with the correct message + expect(console.log).toHaveBeenCalled(); + }); + it('should reassemble a XML file with no namespace."', async () => { + const handler = new ReassembleXMLFileHandler(); + await handler.reassemble({ + xmlPath: "test/baselines/no-namespace/HR_Admin", + fileExtension: "permissionset-meta.xml", + }); + // Ensure that the console.log spy was called with the correct message expect(console.log).toHaveBeenCalled(); });