From db66eb7c87dcb62bdfee746c64cdd117e8322f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Catal=C3=A1n?= Date: Sun, 24 Dec 2023 00:48:14 -0500 Subject: [PATCH] refactor: milestone, functional album except workflow --- src/shared/Atlas.ts | 41 +++++++++++++++++++++++++++++++---- src/shared/XmlParser.ts | 47 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/shared/Atlas.ts b/src/shared/Atlas.ts index 97c9fec..351656f 100644 --- a/src/shared/Atlas.ts +++ b/src/shared/Atlas.ts @@ -5,9 +5,8 @@ import { SfProject, NamedPackageDir } from '@salesforce/core'; import * as ExcelJS from 'exceljs'; import { Spinner } from '@salesforce/sf-plugins-core'; import * as Metadata from './metadata/types/metadata.js'; -import { Extended } from './metadata/file/index.js'; import { XmlParser } from './XmlParser.js'; - +import { Extended, Album, Definition, ALL_DEFINITIONS, getExtension } from './metadata/file/index.js'; // TO DO // - flexipages / lightning pages // - flows @@ -15,8 +14,6 @@ import { XmlParser } from './XmlParser.js'; // - lightning components export class Atlas { - public projectPath: string; - public apexClasses: Array> = []; public apexTriggers: Array> = []; public visualforcePages: Array> = []; @@ -50,12 +47,34 @@ export class Atlas { public flows: Array> = []; // public globalValueSets: Array> = []; + public projectPath: string; + public album: Album = {}; + private fileDefinitionsByExtension: Map; + private metadataExtensions: Set; + public constructor(projectPath: string) { this.projectPath = projectPath; + this.fileDefinitionsByExtension = new Map(); + for (const thisFileDefinition of ALL_DEFINITIONS) { + this.album[thisFileDefinition.list] = []; + if (thisFileDefinition.extension) { + this.fileDefinitionsByExtension.set(thisFileDefinition.extension, thisFileDefinition); + } + } + this.metadataExtensions = new Set(this.fileDefinitionsByExtension.keys()); } public async initialize(spinner: Spinner): Promise { const allFiles = await getAllProjectFiles(this.projectPath); + const allMetadataFiles = allFiles.filter((theFile) => this.isMetadataFile(theFile)); + + for (const thisFile of allMetadataFiles) { + spinner.status = thisFile; + const thisDefinition: Definition = this.fileDefinitionsByExtension.get(getExtension(thisFile))!; + const xml = fs.readFileSync(thisFile, 'utf-8'); + this.absorb(XmlParser.getMetadata>(xml, thisFile, thisDefinition)); + } + for (const thisFile of allFiles) { spinner.status = thisFile; @@ -171,6 +190,16 @@ export class Atlas { } } + private absorb(album: Album): void { + for (const thisList of Object.keys(album)) { + if (!this.album[thisList]) { + this.album[thisList] = []; + } + this.album[thisList].push(...album[thisList]); + } + } + + // eslint-disable-next-line @typescript-eslint/member-ordering public async writeXlsx(): Promise { const workbook = new ExcelJS.default.Workbook(); @@ -834,6 +863,10 @@ export class Atlas { await workbook.xlsx.writeFile(fileName); return fileName; } + + private isMetadataFile(thisFile: string): boolean { + return this.metadataExtensions.has(getExtension(thisFile)); + } } async function getAllProjectFiles(projectPath: string): Promise { diff --git a/src/shared/XmlParser.ts b/src/shared/XmlParser.ts index 6c28349..a37b505 100644 --- a/src/shared/XmlParser.ts +++ b/src/shared/XmlParser.ts @@ -1,8 +1,9 @@ +/* eslint-disable @typescript-eslint/member-ordering */ import * as path from 'node:path'; import * as xml2js from 'xml2js'; import * as Metadata from './metadata/types/metadata.js'; -import { Extended } from './metadata/file/index.js'; import { array } from './array.js'; +import { Extended, ExtendedMetadata, Album, Definition } from './metadata/file/index.js'; const nameRegEx = new RegExp('.+/([^.]*)'); const parserOptions: xml2js.ParserOptions = { @@ -17,6 +18,50 @@ const parserOptions: xml2js.ParserOptions = { }; export class XmlParser { + public static getMetadata(xml: string, fileName: string, definition: Definition): Album { + const album: Album = {}; + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + xml2js.parseString(xml, parserOptions, (err, result: Record) => { + const theRecord = result[definition.name]; + if (!definition.container) { + XmlParser.treatRecord(theRecord, definition, fileName); + album[definition.list] = [theRecord]; + } + if (definition.children) { + for (const listName of definition.children.keys()) { + const thisDefinition = definition.children.get(listName) as Definition; + album[thisDefinition.list] = []; + const records = array(theRecord[listName]) as Array>; + for (const thisRecord of records) { + XmlParser.treatRecord(thisRecord, thisDefinition, fileName); + album[thisDefinition.list].push(thisRecord as T); + } + } + } + }); + return album; + } + + private static treatRecord( + record: Extended, + metadata: Definition, + fileName: string + ): void { + record.fileName = fileName; + if (metadata.setName) { + record.name = metadata.setName(fileName); + } + if (metadata.setObjectname) { + record.objectName = metadata.setObjectname(fileName); + } + if (metadata.setFullName) { + record.fullName = metadata.setFullName(fileName); + } + if (metadata.transform) { + metadata.transform(record); + } + } + public static getApexClasses(xml: string, fileName: string): Array> { const apexClasses: Array> = []; // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access