Skip to content

Commit 9931254

Browse files
Merge pull request #227 from salesforcecli/u/abhinavkumar2/apex-parser/W-16427555
@W-16427555 Apex parser integration
2 parents b3b944b + 5d901d7 commit 9931254

File tree

5 files changed

+173
-3
lines changed

5 files changed

+173
-3
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"author": "Salesforce",
66
"bugs": "https://github.com/forcedotcom/cli/issues",
77
"dependencies": {
8+
"@apexdevtools/apex-parser": "^4.1.0",
89
"@oclif/command": "^1",
910
"@oclif/config": "^1",
1011
"@oclif/errors": "^1",
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/* eslint-disable @typescript-eslint/no-unsafe-return */
2+
/* eslint-disable @typescript-eslint/no-unsafe-call */
3+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
4+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
5+
import {
6+
ApexLexer,
7+
CommonTokenStream,
8+
ApexParser,
9+
CaseInsensitiveInputStream,
10+
ApexParserListener,
11+
ClassDeclarationContext,
12+
DotExpressionContext,
13+
VariableDeclaratorContext,
14+
CompilationUnitContext,
15+
} from '@apexdevtools/apex-parser';
16+
import { CharStreams, Token } from 'antlr4ts';
17+
import { ParseTreeWalker } from 'antlr4ts/tree/ParseTreeWalker';
18+
19+
export class ApexASTParser {
20+
private apexFileContent: string;
21+
private implementsInterface: Map<string, Token> = new Map();
22+
// private callsMethods: Map<string, Token[]>;
23+
private interfaceName: string;
24+
private methodName: string;
25+
// private className: string;
26+
private astListener: ApexParserListener;
27+
28+
public get implemementsInterface(): Map<string, Token> {
29+
return this.implementsInterface;
30+
}
31+
32+
public constructor(apexFileContent: string, interfaceName: string, methodName: string) {
33+
this.apexFileContent = apexFileContent;
34+
this.interfaceName = interfaceName;
35+
this.methodName = methodName;
36+
this.astListener = this.createASTListener();
37+
}
38+
39+
public parse(): CompilationUnitContext {
40+
const lexer = new ApexLexer(new CaseInsensitiveInputStream(CharStreams.fromString(this.apexFileContent)));
41+
const tokens = new CommonTokenStream(lexer);
42+
const parser = new ApexParser(tokens);
43+
const context = parser.compilationUnit();
44+
// parser.addParseListener(new interfaceVisitor() as ApexParserListener);
45+
ParseTreeWalker.DEFAULT.walk(this.astListener, context);
46+
return context;
47+
}
48+
49+
private createASTListener(): ApexParserListener {
50+
class ApexMigrationListener implements ApexParserListener {
51+
public constructor(private parser: ApexASTParser) {}
52+
public enterClassDeclaration(ctx: ClassDeclarationContext): void {
53+
const interfaceToBeSearched = this.parser.interfaceName;
54+
if (!interfaceToBeSearched) return;
55+
if (!ctx.typeList() || !ctx.typeList().typeRef()) return;
56+
for (const typeRefContext of ctx.typeList().typeRef())
57+
for (const typeNameContext of typeRefContext.typeName()) {
58+
if (!typeNameContext.id() || !typeNameContext.id().Identifier()) continue;
59+
if (typeNameContext.id().Identifier().symbol.text === interfaceToBeSearched) {
60+
this.parser.implementsInterface.set(interfaceToBeSearched, typeNameContext.id().Identifier().symbol);
61+
}
62+
}
63+
}
64+
65+
public enterDotExpression(ctx: DotExpressionContext): void {
66+
// console.log('*********');
67+
// console.log(ctx.expression().start.text);
68+
if (ctx.dotMethodCall() && this.parser.methodName) {
69+
// console.log(ctx.dotMethodCall().anyId().Identifier().symbol.text);
70+
// ctx.dotMethodCall().expressionList().expression(1).children[0].children[0].children[0];
71+
// console.log(ctx.dotMethodCall().expressionList().expression(1).children[0]);
72+
}
73+
// console.log('*********');
74+
}
75+
76+
public enterVariableDeclarator(ctx: VariableDeclaratorContext): void {
77+
if (ctx.id().Identifier().symbol.text === 'DRName') {
78+
// console.log(ctx.expression());
79+
}
80+
}
81+
}
82+
return new ApexMigrationListener(this);
83+
}
84+
}
85+
86+
// const filePath = '/Users/abhinavkumar2/company/plugin-omnistudio-migration-tool/test/FormulaParserService.cls';
87+
// new ApexASTParser(filePath, 'callable', '').parse(filePath);
88+
89+
// console.log(ast);

test/commands/omnistudio/migration/info.test.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ describe('omnistudio:migration:info', () => {
2121
.stdout()
2222
.command(['omnistudio:migration:info', '--targetusername', '[email protected]', '--allversions'])
2323
.it('runs omnistudio:migration:info --targetusername [email protected] --allversions', (ctx) => {
24-
expect(ctx.stdout).to.contain(
25-
'Hello world! This is org: Super Awesome Org and I will be around until Tue Mar 20 2018!'
26-
);
24+
expect(ctx.stdout).to.contain('Hello world! This is org: Super Awesome Org');
2725
});
2826
});
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
The service implements Callable to support calling
3+
FormulaParser functions from Core/Java.
4+
The allowed functions are listed in FormulaParser FUNCTIONS_FROM_JAVA.
5+
*/
6+
global with sharing class FormulaParserService implements Callable
7+
{
8+
/* global Object call(String action, Map<String, Object> args)
9+
{
10+
Map<String, Object> input = (Map<String, Object>) args.get('input');
11+
Map<String, Object> output = (Map<String, Object>) args.get('output');
12+
13+
String function = (String)input.get('function');
14+
if (function == null || String.isBlank(function))
15+
{
16+
return null;
17+
}
18+
19+
List<Object> arguments = (input.get('arguments') != null && input.get('arguments') InstanceOf List<Object>)
20+
? (List<Object>)input.get('arguments') : new List<Object>();
21+
22+
if (action == 'evaluateFunctionFromJava')
23+
{
24+
Object res = FormulaParser.evaluateFunctionFromJava(function, arguments);
25+
if (res != null)
26+
{
27+
output.put('result', res);
28+
}
29+
}
30+
return null;
31+
}
32+
33+
global void evaluateFunctionFromJava(String function, List<Object> arguments)
34+
{
35+
Map < String, Object > testMap = new Map < String, Object > { 'BirthDate' => '1982-11-06' };
36+
DRProcessResult result = DRGlobal.process(testMap, 'DRTurboTemp2');
37+
//List < Object > resultMap = (List < Object >)((Map < String, Object >)result.toJson()).get('Contact');
38+
//System.assertEquals(Date.newInstance(1982, 11, 6), ((Map < String, Object >)resultMap[0]).get('Birthdate'));
39+
}*/
40+
41+
global void justForTest(String kkdbk) {
42+
/* Specify Data Mapper extract or transform to call */
43+
String DRName = 'DataMapperNewName';
44+
/* Populate the input JSON */
45+
Map<String, Object> myTransformData = new Map<String, Object>{'MyKey'=>'MyValue'};
46+
/* Call the Data Mapper */
47+
omnistudio.DRProcessResult result1 = omnistudio.DRGlobal.process(myTransformData, DRName);
48+
}
49+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { expect } from '@salesforce/command/lib/test';
2+
import { ApexASTParser } from '../../../../src/utils/apex/parser/apexparser';
3+
4+
describe('ApexASTParser', () => {
5+
it('should parse the Apex file and collect interface implementations, method calls, and class names', () => {
6+
const apexFileContent = `global with sharing class FormulaParserService implements Callable{
7+
8+
global void justForTest(String kkdbk) {
9+
/* Specify Data Mapper extract or transform to call */
10+
String DRName = 'DataMapperNewName';
11+
/* Populate the input JSON */
12+
Map<String, Object> myTransformData = new Map<String, Object>{'MyKey'=>'MyValue'};
13+
/* Call the Data Mapper */
14+
omnistudio.DRProcessResult result1 = omnistudio.DRGlobal.process(myTransformData, DRName);
15+
}
16+
}`;
17+
const interfaceName = 'Callable';
18+
const methodName = 'yourMethod';
19+
20+
const apexParser = new ApexASTParser(apexFileContent, interfaceName, methodName);
21+
apexParser.parse();
22+
const implementsInterface = apexParser.implemementsInterface;
23+
// const callsMethods = apexParser.getCallsMethods();
24+
// const className = apexParser.getClassName();
25+
26+
// Add your assertions here based on the expected results
27+
// implementsInterface.get(interfaceName);
28+
expect(implementsInterface.get(interfaceName).charPositionInLine).to.be.equal(58);
29+
expect(implementsInterface.get(interfaceName).line).to.be.equal(1);
30+
// expect(callsMethods).to.not.be.empty;
31+
// expect(className).to.equal('YourClass');
32+
});
33+
});

0 commit comments

Comments
 (0)