Skip to content

Commit

Permalink
feat: stiching with facade
Browse files Browse the repository at this point in the history
  • Loading branch information
AbhinavKumar-sf committed Sep 9, 2024
1 parent 5b05dee commit 7ddc839
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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();

Expand All @@ -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 {
Expand Down
21 changes: 17 additions & 4 deletions src/commands/omnistudio/migration/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,15 @@ 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';
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);
Expand Down Expand Up @@ -61,14 +59,15 @@ 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');
cli.exec(`sf project retrieve start --metadata Apexclass --target-org ${this.org.getUsername()}`);
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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
23 changes: 10 additions & 13 deletions src/migration/related/ApexMigration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<JSON[]> {
throw new Error('Method not implemented.');
Expand Down Expand Up @@ -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<string>(['VlocityOpenInterface', 'VlocityOpenInterface2', 'Callable']);
const parser = new ApexASTParser(fileContent, interfaces, 'DRGlobal.process');
const methodCalls = new Set<MethodCall>();
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<string, import('antlr4ts').Token>,
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');
}
*/
}
88 changes: 74 additions & 14 deletions src/utils/apex/parser/apexparser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,44 @@ import {
DotExpressionContext,
VariableDeclaratorContext,
CompilationUnitContext,
TypeRefContext,
} from '@apexdevtools/apex-parser';
import { CharStreams, Token } from 'antlr4ts';
import { ParseTreeWalker } from 'antlr4ts/tree/ParseTreeWalker';

export class ApexASTParser {
private apexFileContent: string;
private implementsInterface: Map<string, Token> = new Map();
private methodParameter: Map<string, Token> = new Map();
private namespaceChange: Map<string, Token[]> = new Map();
private namespace: string;
// private callsMethods: Map<string, Token[]>;
private interfaceNames: Set<string>;
private methodName: string;
// private className: string;
private astListener: ApexParserListener;
private methodCalls: Set<MethodCall>;

public get implementsInterfaces(): Map<string, Token> {
return this.implementsInterface;
}

public constructor(apexFileContent: string, interfaceNames: Set<string>, methodName: string) {
public get methodParameters(): Map<string, Token> {
return this.methodParameter;
}
public get namespaceChanges(): Map<string, Token[]> {
return this.namespaceChanges;
}

public constructor(
apexFileContent: string,
interfaceNames: Set<string>,
methodCalls: Set<MethodCall>,
namespace: string
) {
this.apexFileContent = apexFileContent;
this.interfaceNames = interfaceNames;
this.methodName = methodName;
this.methodCalls = methodCalls;
this.namespace = namespace;
this.astListener = this.createASTListener();
}

Expand All @@ -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;
Expand All @@ -64,29 +83,70 @@ 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 {
if (ctx.id().Identifier().symbol.text === 'DRName') {
// 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}()`;
}
}
2 changes: 1 addition & 1 deletion src/utils/file/fileutil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 6 additions & 5 deletions test/utils/apex/parser/apexparser.test.ts
Original file line number Diff line number Diff line change
@@ -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', () => {
Expand All @@ -11,14 +11,15 @@ describe('ApexASTParser', () => {
/* Populate the input JSON */
Map<String, Object> myTransformData = new Map<String, Object>{'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<string>(['Callable']);
const methodName = 'yourMethod';

const apexParser = new ApexASTParser(apexFileContent, interfaceName, methodName);
const methodCalls = new Set<MethodCall>();
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();
Expand Down

0 comments on commit 7ddc839

Please sign in to comment.