diff --git a/messages/assess.json b/messages/assess.json index ef21e25..ae617a6 100644 --- a/messages/assess.json +++ b/messages/assess.json @@ -21,6 +21,7 @@ "duplicatedCardName": "Duplicated Flex Card name", "duplicatedDrName": "Duplicated DataRaptor name", "duplicatedOSName": "Duplicated OmniScript name", + "duplicatedName": "Duplicated name", "errorWhileActivatingOs": "Could not activate OmniScript / Integration Procedure: ", "errorWhileActivatingCard": "Could not activate Card: ", "errorWhileUploadingCard": "An error ocurred while uploading Card: ", diff --git a/src/migration/dataraptor.ts b/src/migration/dataraptor.ts index 795e99b..5cbb5ee 100644 --- a/src/migration/dataraptor.ts +++ b/src/migration/dataraptor.ts @@ -2,13 +2,18 @@ import { AnyJson } from '@salesforce/ts-types'; import DRBundleMappings from '../mappings/DRBundle'; import DRMapItemMappings from '../mappings/DRMapItem'; -import { DebugTimer, QueryTools } from '../utils'; +import { DebugTimer, oldNew, QueryTools } from '../utils'; import { NetUtils } from '../utils/net'; import { BaseMigrationTool } from './base'; import { MigrationResult, MigrationTool, ObjectMapping, TransformData, UploadRecordResult } from './interfaces'; import { DataRaptorAssessmentInfo } from '../../src/utils'; -import { getAllFunctionMetadata, getReplacedString } from '../utils/formula/FormulaUtil'; +import { + getAllFunctionMetadata, + getReplacedString, + populateRegexForFunctionMetadata, +} from '../utils/formula/FormulaUtil'; +import { StringVal } from '../utils/StringValue/stringval'; export class DataRaptorMigrationTool extends BaseMigrationTool implements MigrationTool { static readonly DRBUNDLE_NAME = 'DRBundle__c'; @@ -183,10 +188,25 @@ export class DataRaptorMigrationTool extends BaseMigrationTool implements Migrat }; } + private async getAllDRToItemsMap(): Promise> { + const drToItemsMap = new Map(); + const drItems = await this.getAllItems(); + for (const drItem of drItems) { + const drName = drItem['Name']; + if (drToItemsMap.has(drName)) { + drToItemsMap.get(drName).push(drItem); + } else { + drToItemsMap.set(drName, [drItem]); + } + } + return drToItemsMap; + } + public async assess(): Promise { try { DebugTimer.getInstance().lap('Query data raptors'); const dataRaptors = await this.getAllDataRaptors(); + const dataRaptorAssessmentInfos = this.processDRComponents(dataRaptors); /* this.ux.log('dataRaptorAssessmentInfos'); this.ux.log(dataRaptorAssessmentInfos.toString()); */ @@ -201,40 +221,73 @@ export class DataRaptorMigrationTool extends BaseMigrationTool implements Migrat const dataRaptorAssessmentInfos: DataRaptorAssessmentInfo[] = []; // Query all the functionMetadata with all required fields const functionDefinitionMetadata = await getAllFunctionMetadata(this.namespace, this.connection); + populateRegexForFunctionMetadata(functionDefinitionMetadata); + const existingDataRaptorNames = new Set(); + const dataRaptorItemsMap = await this.getAllDRToItemsMap(); // Now process each OmniScript and its elements for (const dataRaptor of dataRaptors) { + if (dataRaptor[this.namespacePrefix + 'Type__c'] === 'Migration') continue; + const drName = dataRaptor['Name']; // Await here since processOSComponents is now async - this.ux.log(dataRaptor['Name']); - this.ux.log(dataRaptor[this.namespacePrefix + 'Formula__c']); - var customFunctionString = ''; - if (dataRaptor[this.namespacePrefix + 'Formula__c'] != null) { - this.ux.log('formula'); - customFunctionString = - 'Original Formula :' + dataRaptor[this.namespacePrefix + 'Formula__c'] + '\n\n' + 'Replaced Formula :Formula'; - try { - customFunctionString += - 'Replaced Formula :Formula \n\n' + - getReplacedString( - this.namespacePrefix, - dataRaptor[this.namespacePrefix + 'Formula__c'], - functionDefinitionMetadata - ); - } catch (ex) { - this.logger.error(JSON.stringify(ex)); - console.log( - "There was some problem while updating the formula syntax, please check the all the formula's syntax once : " + - dataRaptor[this.namespacePrefix + 'Formula__c'] - ); - } + this.ux.log(drName); + const warnings: string[] = []; + const existingDRNameVal = new StringVal(drName, 'name'); + + if (!existingDRNameVal.isNameCleaned()) { + warnings.push( + this.messages.getMessage('changeMessage', [ + existingDRNameVal.type, + existingDRNameVal.val, + existingDRNameVal.cleanName(), + ]) + ); + } + if (existingDataRaptorNames.has(existingDRNameVal.cleanName())) { + warnings.push(this.messages.getMessage('duplicatedName') + ' ' + existingDRNameVal.cleanName()); + } else { + existingDataRaptorNames.add(existingDRNameVal.cleanName()); + } + const apexDependencies = []; + if (dataRaptor[this.namespacePrefix + 'CustomInputClass__c']) { + apexDependencies.push(dataRaptor[this.namespacePrefix + 'CustomInputClass__c']); + } + if (dataRaptor[this.namespacePrefix + 'CustomOutputClass__c']) { + apexDependencies.push(dataRaptor[this.namespacePrefix + 'CustomOutputClass__c']); } + const formulaChanges: oldNew[] = []; + const drItems = dataRaptorItemsMap.get(drName); + if (drItems) { + for (const drItem of drItems) { + // this.ux.log(dataRaptor[this.namespacePrefix + 'Formula__c']); + const formula = drItem[this.namespacePrefix + 'Formula__c']; + if (formula) { + try { + const newFormula = getReplacedString(this.namespacePrefix, formula, functionDefinitionMetadata); + if (newFormula !== formula) { + formulaChanges.push({ + old: formula, + new: newFormula, + }); + } + } catch (ex) { + this.logger.error(JSON.stringify(ex)); + console.log( + "There was some problem while updating the formula syntax, please check the all the formula's syntax once : " + + formula + ); + } + } + } + } const dataRaptorAssessmentInfo: DataRaptorAssessmentInfo = { - name: dataRaptor['Name'], - customFunction: customFunctionString, + name: existingDRNameVal.val, id: dataRaptor['Id'], + formulaChanges: formulaChanges, infos: [], - warnings: [], + apexDependencies: apexDependencies, + warnings: warnings, }; dataRaptorAssessmentInfos.push(dataRaptorAssessmentInfo); } @@ -263,6 +316,20 @@ export class DataRaptorMigrationTool extends BaseMigrationTool implements Migrat ); } + /* + private async getAllItemsForDataRaptorByName(drName: string): Promise { + const filters = new Map(); + //Query all Elements + return await QueryTools.queryWithFilter( + this.connection, + this.namespace, + DataRaptorMigrationTool.DRMAPITEM_NAME, + this.getDRMapItemFields(), + filters.set('Name', drName) + ); + } + */ + // Get All Items for one DataRaptor private async getItemsForDataRaptor( dataRaptorItems: AnyJson[], diff --git a/src/migration/omniscript.ts b/src/migration/omniscript.ts index d1a32e5..9b0563a 100644 --- a/src/migration/omniscript.ts +++ b/src/migration/omniscript.ts @@ -274,6 +274,12 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat const lwcName = propertySet['lwcName']; dependenciesLWC.push({ name: lwcName, location: nameVal }); } + // To fetch custom overrides + if (propertySet['lwcComponentOverride']) { + const nameVal = `${elemName}`; + const lwcName = propertySet['lwcComponentOverride']; + dependenciesLWC.push({ name: lwcName, location: nameVal }); + } } const omniProcessType = omniscript[this.namespacePrefix + 'IsProcedure__c'] @@ -325,7 +331,7 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat ); } if (existingOmniscriptNames.has(recordName)) { - warnings.push(this.messages.getMessage('duplicatedName') + recordName); + warnings.push(this.messages.getMessage('duplicatedName') + ' ' + recordName); } else { existingOmniscriptNames.add(recordName); } diff --git a/src/migration/related/ApexMigration.ts b/src/migration/related/ApexMigration.ts index 7e521a7..21ad0b6 100644 --- a/src/migration/related/ApexMigration.ts +++ b/src/migration/related/ApexMigration.ts @@ -50,7 +50,7 @@ export class ApexMigration extends BaseRelatedObjectMigration implements Related const pwd = shell.pwd(); shell.cd(this.projectPath); const targetOrg: Org = this.org; - sfProject.retrieve(APEXCLASS, targetOrg.getUsername()); + // sfProject.retrieve(APEXCLASS, targetOrg.getUsername()); const apexAssessmentInfos = this.processApexFiles(this.projectPath); sfProject.deploy(APEXCLASS, targetOrg.getUsername()); shell.cd(pwd); @@ -60,8 +60,8 @@ export class ApexMigration extends BaseRelatedObjectMigration implements Related public assess(): ApexAssessmentInfo[] { const pwd = shell.pwd(); shell.cd(this.projectPath); - const targetOrg: Org = this.org; - sfProject.retrieve(APEXCLASS, targetOrg.getUsername()); + // const targetOrg: Org = this.org; + // sfProject.retrieve(APEXCLASS, this.org.getUsername()); const apexAssessmentInfos = this.processApexFiles(this.projectPath); shell.cd(pwd); return apexAssessmentInfos; diff --git a/src/migration/related/LwcMigration.ts b/src/migration/related/LwcMigration.ts index 00dda8b..2c4caf1 100644 --- a/src/migration/related/LwcMigration.ts +++ b/src/migration/related/LwcMigration.ts @@ -27,7 +27,7 @@ export class LwcMigration extends BaseRelatedObjectMigration implements RelatedO const type = 'assessment'; const pwd = shell.pwd(); shell.cd(this.projectPath); - sfProject.retrieve(LWCTYPE, this.org.getUsername()); + // sfProject.retrieve(LWCTYPE, this.org.getUsername()); const filesMap = this.processLwcFiles(this.projectPath); shell.cd(pwd); return this.processFiles(filesMap, type); diff --git a/src/utils/formula/FormulaUtil.ts b/src/utils/formula/FormulaUtil.ts index 69111f2..31525eb 100644 --- a/src/utils/formula/FormulaUtil.ts +++ b/src/utils/formula/FormulaUtil.ts @@ -78,6 +78,11 @@ export async function getAllFunctionMetadata(namespace: string, connection: Conn return await QueryTools.queryAll(connection, namespace, 'FunctionDefinition__mdt', getFunctionDefinitionFields()); } +export function populateRegexForFunctionMetadata(functionDefinitionMetadata: AnyJson[]) { + functionDefinitionMetadata.forEach((functionDef) => { + functionDef['regex'] = new RegExp('\\b' + functionDef['DeveloperName'] + '\\b', 'g'); + }); +} export function getReplacedString( namespacePrefix: string, inputString: string, @@ -85,10 +90,9 @@ export function getReplacedString( ): string { let formulaSyntax = inputString; for (let functionDefMd of functionDefinitionMetadata) { - const FormulaName = functionDefMd['DeveloperName']; - const regExStr = new RegExp('\\b' + FormulaName + '\\b', 'g'); - const numberOfOccurances: number = - formulaSyntax.match(regExStr) !== null ? formulaSyntax.match(regExStr).length : 0; + const regExStr = functionDefMd['regex']; + const match = formulaSyntax.match(regExStr); + const numberOfOccurances: number = match !== null ? match.length : 0; if (numberOfOccurances > 0) { for (var count: number = 1; count <= numberOfOccurances; count++) { formulaSyntax = getReplacedformulaString( diff --git a/src/utils/interfaces.ts b/src/utils/interfaces.ts index 9fdbb0a..737f091 100644 --- a/src/utils/interfaces.ts +++ b/src/utils/interfaces.ts @@ -90,10 +90,11 @@ export interface FlexCardAssessmentInfo { export interface DataRaptorAssessmentInfo { name: string; - customFunction: string; id: string; + formulaChanges: oldNew[]; infos: string[]; warnings: string[]; + apexDependencies: string[]; } export interface OmniAssessmentInfo { @@ -124,3 +125,8 @@ export interface nameLocation { name: string; location: string; } + +export interface oldNew { + old: string; + new: string; +} diff --git a/src/utils/resultsbuilder/DRAssessmentReporter.ts b/src/utils/resultsbuilder/DRAssessmentReporter.ts new file mode 100644 index 0000000..e01e7de --- /dev/null +++ b/src/utils/resultsbuilder/DRAssessmentReporter.ts @@ -0,0 +1,68 @@ +import { DataRaptorAssessmentInfo } from '../interfaces'; +import { reportingHelper } from './reportingHelper'; + +export class DRAssessmentReporter { + public static generateDRAssesment( + dataRaptorAssessmentInfos: DataRaptorAssessmentInfo[], + instanceUrl: string + ): string { + let tableBody = ''; + tableBody += '
Data Raptor Components Assessment
'; + for (const dr of dataRaptorAssessmentInfos) { + const row = ` + + +
${dr.name}
+ + + + + + ${reportingHelper.convertToBuletedList(dr.warnings)} + + +
${reportingHelper.decorateChanges(dr.formulaChanges, 'Formula')}
+ + + ${reportingHelper.convertToBuletedList(dr.apexDependencies)} + + + `; + tableBody += row; + } + + return DRAssessmentReporter.getDRAssessmentReport(tableBody); + } + + private static getDRAssessmentReport(tableContent: string): string { + const tableBody = ` +
+ + + + + + + + + + + + ${tableContent} + +
+
Name
+
+
ID
+
+
Summary
+
+
Custom Function Changes
+
+
Apex dependencies
+
+
`; + return tableBody; + } +} diff --git a/src/utils/resultsbuilder/assessmentReporter.ts b/src/utils/resultsbuilder/assessmentReporter.ts index 2eb3256..490489e 100644 --- a/src/utils/resultsbuilder/assessmentReporter.ts +++ b/src/utils/resultsbuilder/assessmentReporter.ts @@ -8,11 +8,11 @@ import { LWCAssessmentInfo, OmniAssessmentInfo, FlexCardAssessmentInfo, - DataRaptorAssessmentInfo, nameLocation, } from '../interfaces'; import { OSAssesmentReporter } from './OSAssessmentReporter'; import { IPAssessmentReporter } from './IPAssessmentReporter'; +import { DRAssessmentReporter } from './DRAssessmentReporter'; export class AssessmentReporter { public static async generate(result: AssessmentInfo, instanceUrl: string): Promise { @@ -39,7 +39,7 @@ export class AssessmentReporter { ); this.createDocument( dataMapperAssessmentFilePath, - this.generateDRAssesment(result.dataRaptorAssessmentInfos, instanceUrl) + DRAssessmentReporter.generateDRAssesment(result.dataRaptorAssessmentInfos, instanceUrl) ); this.createDocument(apexAssessmentFilePath, this.generateApexAssesment(result.apexAssessmentInfos)); this.createDocument(lwcAssessmentFilePath, this.generateLwcAssesment(result.lwcAssessmentInfos)); @@ -229,23 +229,6 @@ export class AssessmentReporter { return this.getCardAssessmentReport(tableBody); } - private static generateDRAssesment(dataRaptorAssessmentInfos: DataRaptorAssessmentInfo[], instanceUrl): string { - let tableBody = ''; - tableBody += '
Data Raptor Components Assessment
'; - for (const dr of dataRaptorAssessmentInfos) { - const row = ` - - -
${dr.name}
-
${dr.customFunction}
- - `; - tableBody += row; - } - - return this.getDRAssessmentReport(tableBody); - } - private static generateMessages(messages: string[]): string { let messageBody = ''; for (const message of messages) { @@ -304,40 +287,6 @@ export class AssessmentReporter { return tableBody; } - private static getDRAssessmentReport(tableContent: string): string { - const tableBody = ` -
- - - - - - - - - - ${tableContent} - -
-
Name
-
-
Custom Function Change
-
-
`; - return tableBody; - } - private static getLWCAssesmentReport(tableContent: string): string { const tableBody = `
diff --git a/src/utils/resultsbuilder/reportingHelper.ts b/src/utils/resultsbuilder/reportingHelper.ts index d478f7f..063f235 100644 --- a/src/utils/resultsbuilder/reportingHelper.ts +++ b/src/utils/resultsbuilder/reportingHelper.ts @@ -1,4 +1,4 @@ -import { nameLocation } from '../interfaces'; +import { nameLocation, oldNew } from '../interfaces'; export class reportingHelper { public static decorate(nameLocations: nameLocation[]): string { @@ -18,4 +18,14 @@ export class reportingHelper { htmlContent += ''; return htmlContent; } + + public static decorateChanges(changes: oldNew[], what: string): string { + if (!changes || changes.length === 0) return ''; + let htmlContent = '
    '; + for (const change of changes) { + htmlContent += `
  • ${what} will change ${change.old} to ${change.new}
  • `; + + return htmlContent; + } + } } diff --git a/test/utils/formula/formulaUtil.test.ts b/test/utils/formula/formulaUtil.test.ts index 12a5f52..ff596e8 100644 --- a/test/utils/formula/formulaUtil.test.ts +++ b/test/utils/formula/formulaUtil.test.ts @@ -1,12 +1,13 @@ /* eslint-disable camelcase */ import { expect } from '@salesforce/command/lib/test'; import { AnyJson } from '@salesforce/ts-types'; -import { getReplacedString } from '../../../src/utils/formula/FormulaUtil'; +import { getReplacedString, populateRegexForFunctionMetadata } from '../../../src/utils/formula/FormulaUtil'; -describe('ApexASTParser', () => { +describe('FormulaUtilTest', () => { it('should generate new string with standard function format', () => { const namespacePrefix = 'test_namespace__'; const mockedFunctionDefinitionMetadata = getMockedAllFunctionMetadata(); + populateRegexForFunctionMetadata(mockedFunctionDefinitionMetadata); const inputString = "TESTMETHODFIRST('hello','bye')"; // eslint-disable-next-line @typescript-eslint/no-unsafe-call const result = getReplacedString(namespacePrefix, inputString, mockedFunctionDefinitionMetadata); @@ -18,6 +19,7 @@ describe('ApexASTParser', () => { it('should generate new string with standard function format with nested custom formula', () => { const namespacePrefix = 'test_namespace__'; const mockedFunctionDefinitionMetadata = getMockedAllFunctionMetadata(); + populateRegexForFunctionMetadata(mockedFunctionDefinitionMetadata); const inputString = "TESTMETHODFIRST('hello',TESTMETHOD('bye'))"; // eslint-disable-next-line @typescript-eslint/no-unsafe-call const result = getReplacedString(namespacePrefix, inputString, mockedFunctionDefinitionMetadata); @@ -29,6 +31,7 @@ describe('ApexASTParser', () => { it('should generate new string with standard function format with nested custom formula and a formula used more than Once', () => { const namespacePrefix = 'test_namespace__'; const mockedFunctionDefinitionMetadata = getMockedAllFunctionMetadata(); + populateRegexForFunctionMetadata(mockedFunctionDefinitionMetadata); const inputString = "TESTMETHODFIRST('hello',TESTMETHOD(TESTMETHODFIRST('bye','check')))"; // eslint-disable-next-line @typescript-eslint/no-unsafe-call const result = getReplacedString(namespacePrefix, inputString, mockedFunctionDefinitionMetadata);