From 7ddc839a5588f1c19890e1c8e964f8fb012eb58e Mon Sep 17 00:00:00 2001 From: abhinavkumar2 Date: Mon, 9 Sep 2024 15:26:43 +0530 Subject: [PATCH] feat: stiching with facade --- .../OmnistudioRelatedObjectMigrationFacade.ts | 25 +++--- src/commands/omnistudio/migration/migrate.ts | 21 ++++- src/migration/related/ApexMigration.ts | 23 +++-- src/utils/apex/parser/apexparser.ts | 88 ++++++++++++++++--- src/utils/file/fileutil.ts | 2 +- test/utils/apex/parser/apexparser.test.ts | 11 +-- 6 files changed, 118 insertions(+), 52 deletions(-) diff --git a/src/commands/omnistudio/migration/OmnistudioRelatedObjectMigrationFacade.ts b/src/commands/omnistudio/migration/OmnistudioRelatedObjectMigrationFacade.ts index 0027419..79629bb 100644 --- a/src/commands/omnistudio/migration/OmnistudioRelatedObjectMigrationFacade.ts +++ b/src/commands/omnistudio/migration/OmnistudioRelatedObjectMigrationFacade.ts @@ -1,26 +1,25 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-explicit-any */ -import * as os from 'os'; -import { Messages, Org } from '@salesforce/core'; +import { Org } from '@salesforce/core'; import '../../../utils/prototypes'; -import { DebugTimer } from '../../../utils'; -import { MigrationResult, RelatedObjectsMigrate } from '../../../migration/interfaces'; +import { DebugTimer, MigratedObject } from '../../../utils'; +import { RelatedObjectsMigrate } from '../../../migration/interfaces'; import { sfProject } from '../../../utils/sfcli/project/sfProject'; import { Logger } from '../../../utils/logger'; import { ApexMigration } from '../../../migration/related/ApexMigration'; // Initialize Messages with the current plugin directory -Messages.importMessagesDirectory(__dirname); +// Messages.importMessagesDirectory(__dirname); // Load the specific messages for this file. Messages from @salesforce/command, @salesforce/core, // or any library that is using the messages framework can also be loaded this way. -const messages = Messages.loadMessages('@salesforce/plugin-omnistudio-related-object-migration-tool', 'migrate'); +// const messages = Messages.loadMessages('@salesforce/plugin-omnistudio-related-object-migration-tool', 'migrate'); const defaultProjectName = 'omnistudio_migration'; export default class OmnistudioRelatedObjectMigrationFacade { - public static description = messages.getMessage('commandDescription'); - public static examples = messages.getMessage('examples').split(os.EOL); + // public static description = messages.getMessage('commandDescription'); + // public static examples = messages.getMessage('examples').split(os.EOL); public static args = [{ name: 'file' }]; protected readonly namespace: string; @@ -34,7 +33,7 @@ export default class OmnistudioRelatedObjectMigrationFacade { this.allversions = allversions; this.org = org; } - public migrateAll(migrationResult: MigrationResult, namespace: string, relatedObjects: string[]): any { + public migrateAll(migrationResult: MigratedObject[], relatedObjects: string[]): any { // Start the debug timer DebugTimer.getInstance().start(); @@ -45,19 +44,15 @@ export default class OmnistudioRelatedObjectMigrationFacade { debugTimer.start(); // Initialize migration tools based on the relatedObjects parameter if (relatedObjects.includes('lwc')) { - migrationTools.push(this.createLWCComponentMigrationTool(namespace, this.org)); + migrationTools.push(this.createLWCComponentMigrationTool(this.namespace, this.org)); } if (relatedObjects.includes('labels')) { - migrationTools.push(this.createCustomLabelMigrationTool(namespace, this.org)); + migrationTools.push(this.createCustomLabelMigrationTool(this.namespace, this.org)); } if (relatedObjects.includes('apex')) { migrationTools.push(this.createApexClassMigrationTool(projectDirectory)); } - if (migrationTools.length === 0) { - throw new Error(messages.getMessage('noMigrationToolsSelected')); - } - // Proceed with migration logic for (const migrationTool of migrationTools.reverse()) { try { diff --git a/src/commands/omnistudio/migration/migrate.ts b/src/commands/omnistudio/migration/migrate.ts index 3d68ab6..33e0114 100644 --- a/src/commands/omnistudio/migration/migrate.ts +++ b/src/commands/omnistudio/migration/migrate.ts @@ -11,7 +11,6 @@ import * as os from 'os'; import { flags } from '@salesforce/command'; import { Messages } from '@salesforce/core'; import '../../../utils/prototypes'; -import * as shell from 'shelljs'; import OmniStudioBaseCommand from '../../basecommand'; import { DataRaptorMigrationTool } from '../../../migration/dataraptor'; import { DebugTimer, MigratedObject, MigratedRecordInfo } from '../../../utils'; @@ -19,9 +18,8 @@ import { MigrationResult, MigrationTool } from '../../../migration/interfaces'; import { ResultsBuilder } from '../../../utils/resultsbuilder'; import { CardMigrationTool } from '../../../migration/flexcard'; import { OmniScriptExportType, OmniScriptMigrationTool } from '../../../migration/omniscript'; -import { cli } from '../../../utils/shell/cli'; import { Logger } from '../../../utils/logger'; -import { sfProject } from '../../../utils/sfcli/project/sfProject'; +import OmnistudioRelatedObjectMigrationFacade from './OmnistudioRelatedObjectMigrationFacade'; // Initialize Messages with the current plugin directory Messages.importMessagesDirectory(__dirname); @@ -61,7 +59,7 @@ export default class Migrate extends OmniStudioBaseCommand { const allVersions = this.flags.allversions || false; // await sfcclicommand.fetchApexClasses(this.org, '/Users/abhinavkumar2/company/mywork'); // await sfcclicommand.deployApexClasses(this.org, '/Users/abhinavkumar2/company/mywork/main/default/classes'); - sfProject.create('omnistudio_migration', '/Users/abhinavkumar2/company/new'); + /* sfProject.create('omnistudio_migration', '/Users/abhinavkumar2/company/new'); this.ux.log('creating project'); const pwd = shell.pwd(); shell.cd('/Users/abhinavkumar2/company/new/omnistudio_migration'); @@ -69,6 +67,7 @@ export default class Migrate extends OmniStudioBaseCommand { this.ux.log('retrieving apex classes'); cli.exec(`sf project deploy start --metadata Apexclass --target-org ${this.org.getUsername()}`); shell.cd(pwd); + */ Logger.initialiseLogger(this.ux, this.logger); this.logger = Logger.logger; @@ -137,6 +136,13 @@ export default class Migrate extends OmniStudioBaseCommand { // Migrate individual objects const debugTimer = DebugTimer.getInstance(); let objectMigrationResults: MigratedObject[] = []; + const omnistudioRelatedObjectsMig = new OmnistudioRelatedObjectMigrationFacade( + namespace, + migrateOnly, + allVersions, + this.org + ); + omnistudioRelatedObjectsMig.migrateAll(objectMigrationResults, ['apex']); // We need to truncate the standard objects first let allTruncateComplete = true; @@ -182,6 +188,13 @@ export default class Migrate extends OmniStudioBaseCommand { // Stop the debug timer const timer = DebugTimer.getInstance().stop(); + const omnistudioRelatedObjectsMigration = new OmnistudioRelatedObjectMigrationFacade( + namespace, + migrateOnly, + allVersions, + this.org + ); + omnistudioRelatedObjectsMigration.migrateAll(objectMigrationResults, ['Apex']); await ResultsBuilder.generate(objectMigrationResults, conn.instanceUrl); // save timer to debug logger diff --git a/src/migration/related/ApexMigration.ts b/src/migration/related/ApexMigration.ts index 17aae06..36d7cdb 100644 --- a/src/migration/related/ApexMigration.ts +++ b/src/migration/related/ApexMigration.ts @@ -3,14 +3,13 @@ import * as fs from 'fs'; // import { sfcclicommand } from '../../utils/sfcli/commands/sfclicommand'; import * as shell from 'shelljs'; import { Org } from '@salesforce/core'; -import { ApexASTParser } from '../../utils/apex/parser/apexparser'; +import { ApexASTParser, MethodCall } from '../../utils/apex/parser/apexparser'; import { MigrationResult, RelatedObjectsMigrate } from '../interfaces'; import { sfProject } from '../../utils/sfcli/project/sfProject'; import { fileutil, File } from '../../utils/file/fileutil'; import { BaseRelatedObjectMigration } from './BaseRealtedObjectMigration'; - const APEXCLASS = 'Apexclass'; -const APEX_CLASS_PATH = 'main/default/classes'; +const APEX_CLASS_PATH = '/force-app/main/default/classes'; export class ApexMigration extends BaseRelatedObjectMigration implements RelatedObjectsMigrate { public identifyObjects(migrationResults: MigrationResult[]): Promise { throw new Error('Method not implemented.'); @@ -41,17 +40,15 @@ export class ApexMigration extends BaseRelatedObjectMigration implements Related public processApexFile(file: File): void { const fileContent = fs.readFileSync(file.location, 'utf8'); const interfaces = new Set(['VlocityOpenInterface', 'VlocityOpenInterface2', 'Callable']); - const parser = new ApexASTParser(fileContent, interfaces, 'DRGlobal.process'); + const methodCalls = new Set(); + methodCalls.add(new MethodCall('process', 'DRGlobal', this.namespace)); + methodCalls.add(new MethodCall('processObjectsJSON', 'DRGlobal', this.namespace)); + const parser = new ApexASTParser(fileContent, interfaces, methodCalls, this.namespace); parser.parse(); - // this.processApexFileforInterfaces(parser.implementsInterfaces, file, fileContent); + this.processApexFileforDRCalls(file, fileContent); } - /* - processApexFileforInterfaces( - implementsInterfaces: Map, - file: File, - fileContent: string - ) { - if (implementsInterfaces.has('Callable')) return; + public processApexFileforDRCalls(file: File, fileContent: string): void { + // fileContent = fileContent.replace(this.namespace + '.', 'omnistudio.'); + fs.writeFileSync(file.location, fileContent, 'utf-8'); } -*/ } diff --git a/src/utils/apex/parser/apexparser.ts b/src/utils/apex/parser/apexparser.ts index a973df5..dde9e62 100644 --- a/src/utils/apex/parser/apexparser.ts +++ b/src/utils/apex/parser/apexparser.ts @@ -12,6 +12,7 @@ import { DotExpressionContext, VariableDeclaratorContext, CompilationUnitContext, + TypeRefContext, } from '@apexdevtools/apex-parser'; import { CharStreams, Token } from 'antlr4ts'; import { ParseTreeWalker } from 'antlr4ts/tree/ParseTreeWalker'; @@ -19,20 +20,36 @@ import { ParseTreeWalker } from 'antlr4ts/tree/ParseTreeWalker'; export class ApexASTParser { private apexFileContent: string; private implementsInterface: Map = new Map(); + private methodParameter: Map = new Map(); + private namespaceChange: Map = new Map(); + private namespace: string; // private callsMethods: Map; private interfaceNames: Set; - private methodName: string; // private className: string; private astListener: ApexParserListener; + private methodCalls: Set; public get implementsInterfaces(): Map { return this.implementsInterface; } - public constructor(apexFileContent: string, interfaceNames: Set, methodName: string) { + public get methodParameters(): Map { + return this.methodParameter; + } + public get namespaceChanges(): Map { + return this.namespaceChanges; + } + + public constructor( + apexFileContent: string, + interfaceNames: Set, + methodCalls: Set, + namespace: string + ) { this.apexFileContent = apexFileContent; this.interfaceNames = interfaceNames; - this.methodName = methodName; + this.methodCalls = methodCalls; + this.namespace = namespace; this.astListener = this.createASTListener(); } @@ -48,7 +65,9 @@ export class ApexASTParser { private createASTListener(): ApexParserListener { class ApexMigrationListener implements ApexParserListener { - public constructor(private parser: ApexASTParser) {} + public constructor(private parser: ApexASTParser) { + // + } public enterClassDeclaration(ctx: ClassDeclarationContext): void { const interfaceToBeSearched = this.parser.interfaceNames; if (!interfaceToBeSearched) return; @@ -64,16 +83,32 @@ export class ApexASTParser { } } } - public enterDotExpression(ctx: DotExpressionContext): void { // console.log('*********'); // console.log(ctx.expression().start.text); - if (ctx.dotMethodCall() && this.parser.methodName) { - // console.log(ctx.dotMethodCall().anyId().Identifier().symbol.text); - // ctx.dotMethodCall().expressionList().expression(1).children[0].children[0].children[0]; - // console.log(ctx.dotMethodCall().expressionList().expression(1).children[0]); + if (ctx.dotMethodCall() && this.parser.methodCalls) { + const namespaceUsed = ctx.expression().getChild(0); + const methodName = ctx.dotMethodCall().anyId().Identifier().symbol; + const className = ctx.expression().getChild(2); + + for (const methodcall of this.parser.methodCalls) { + if ( + methodcall.methodName === methodName.text && + methodcall.className === className.text && + methodcall.namespace && + methodcall.namespace === namespaceUsed.text + ) { + const bundleName = ctx.dotMethodCall().expressionList().expression(1); + this.parser.methodParameter.set(methodcall.getExpression(), bundleName.start); + } + } } - // console.log('*********'); + // console.log(ctx.dotMethodCall().anyId().Identifier().symbol.text); + // console.log(ctx.expression().anyId().Identifier().symbol.text); + // console.log(ctx.expression().children[0].children[0].id().text); + // console.log(ctx.dotMethodCall().expressionList().expression(0).children[0].children[0].children[0]); + // ctx.dotMethodCall().expressionList().expression(1).children[0].children[0].children[0]; + // console.log(ctx.dotMethodCall().expressionList().expression(1).children[0]); } public enterVariableDeclarator(ctx: VariableDeclaratorContext): void { @@ -81,12 +116,37 @@ export class ApexASTParser { // console.log(ctx.expression()); } } + public enterTypeRef(ctx: TypeRefContext): void { + if ( + ctx.childCount >= 2 && + ctx.typeName(0).text === this.parser.namespace && + ctx.typeName(1).text === 'DRProcessResult' + ) { + if (!this.parser.namespaceChange.has(this.parser.namespace)) { + this.parser.namespaceChange.set(this.parser.namespace, []); + } + this.parser.namespaceChange.get(this.parser.namespace).push(ctx.typeName(0).start); + // bkbkdv + // console.log(ctx.typeName(0).text); + // console.log(ctx.typeName(1).text); + } + } } return new ApexMigrationListener(this); } } -// const filePath = '/Users/abhinavkumar2/company/plugin-omnistudio-migration-tool/test/FormulaParserService.cls'; -// new ApexASTParser(filePath, 'callable', '').parse(filePath); - -// console.log(ast); +export class MethodCall { + public methodName: string; + public className: string; + public namespace: string; + public constructor(className: string, methodName: string, namespace?: string) { + this.className = className; + this.methodName = methodName; + this.namespace = namespace; + } + public getExpression(): string { + if (this.namespace) return `${this.namespace}.${this.className}.${this.methodName}()`; + else return `${this.className}.${this.methodName}()`; + } +} diff --git a/src/utils/file/fileutil.ts b/src/utils/file/fileutil.ts index a279f73..876c329 100644 --- a/src/utils/file/fileutil.ts +++ b/src/utils/file/fileutil.ts @@ -3,7 +3,7 @@ import * as path from 'path'; export class fileutil { public static readFilesSync(dir: string): File[] { - let files: File[]; + const files: File[] = []; fs.readdirSync(dir).forEach((filename) => { const name = path.parse(filename).name; const ext = path.parse(filename).ext; diff --git a/test/utils/apex/parser/apexparser.test.ts b/test/utils/apex/parser/apexparser.test.ts index f2482ce..0dd8b08 100644 --- a/test/utils/apex/parser/apexparser.test.ts +++ b/test/utils/apex/parser/apexparser.test.ts @@ -1,5 +1,5 @@ import { expect } from '@salesforce/command/lib/test'; -import { ApexASTParser } from '../../../../src/utils/apex/parser/apexparser'; +import { ApexASTParser, MethodCall } from '../../../../src/utils/apex/parser/apexparser'; describe('ApexASTParser', () => { it('should parse the Apex file and collect interface implementations, method calls, and class names', () => { @@ -11,14 +11,15 @@ describe('ApexASTParser', () => { /* Populate the input JSON */ Map myTransformData = new Map{'MyKey'=>'MyValue'}; /* Call the Data Mapper */ - omnistudio.DRProcessResult result1 = omnistudio.DRGlobal.process(myTransformData, DRName); + vlocity_ins.DRProcessResult result1 = vlocity_ins.DRGlobal.process(myTransformData, 'DRName'); } }`; const callable = 'Callable'; const interfaceName = new Set(['Callable']); - const methodName = 'yourMethod'; - - const apexParser = new ApexASTParser(apexFileContent, interfaceName, methodName); + const methodCalls = new Set(); + methodCalls.add(new MethodCall('process', 'DRGlobal', 'vlocity_ins')); + methodCalls.add(new MethodCall('processObjectsJSON', 'DRGlobal', 'vlocity_ins')); + const apexParser = new ApexASTParser(apexFileContent, interfaceName, methodCalls, 'vlocity_ins'); apexParser.parse(); const implementsInterface = apexParser.implementsInterfaces; // const callsMethods = apexParser.getCallsMethods();