Skip to content

Commit ef8dae0

Browse files
feat: parser unit tests
1 parent 0d86090 commit ef8dae0

File tree

4 files changed

+136
-35
lines changed

4 files changed

+136
-35
lines changed

package.json

Lines changed: 3 additions & 3 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",
@@ -13,8 +14,7 @@
1314
"@types/lodash.chunk": "^4.2.9",
1415
"lodash.chunk": "^4.2.0",
1516
"open": "^8.4.2",
16-
"tslib": "^2",
17-
"@apexdevtools/apex-parser": "^4.1.0"
17+
"tslib": "^2"
1818
},
1919
"devDependencies": {
2020
"@oclif/dev-cli": "^1",
@@ -115,4 +115,4 @@
115115
"pre-push": "sf-husky-pre-push"
116116
}
117117
}
118-
}
118+
}
Lines changed: 64 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
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 */
15
import fs from 'fs';
26
import {
37
ApexLexer,
@@ -10,51 +14,79 @@ import {
1014
VariableDeclaratorContext,
1115
CompilationUnitContext,
1216
} from '@apexdevtools/apex-parser';
13-
import { CharStreams } from 'antlr4ts';
17+
import { CharStreams, Token } from 'antlr4ts';
1418
import { ParseTreeWalker } from 'antlr4ts/tree/ParseTreeWalker';
1519

16-
export class ApexASTTraverser {
17-
public static parse(apexClass: string): CompilationUnitContext {
18-
const lexer = new ApexLexer(new CaseInsensitiveInputStream(CharStreams.fromString(apexClass)));
20+
export class ApexASTParser {
21+
private apexFilePath: string;
22+
private implementsInterface: Map<string, Token>;
23+
private callsMethods: Map<string, Token[]>;
24+
private interfaceName: string;
25+
private methodName: string;
26+
private className: string;
27+
private astListener: ApexParserListener;
28+
29+
public get implemementsInterface(): Map<string, Token> {
30+
return this.implementsInterface;
31+
}
32+
33+
public constructor(apexFilePath: string, interfaceName: string, methodName: string) {
34+
this.apexFilePath = apexFilePath;
35+
this.interfaceName = interfaceName;
36+
this.methodName = methodName;
37+
this.astListener = this.createASTListener();
38+
}
39+
40+
public parse(filePath: string): CompilationUnitContext {
41+
const fileContent = fs.readFileSync(filePath).toString();
42+
const lexer = new ApexLexer(new CaseInsensitiveInputStream(CharStreams.fromString(fileContent)));
1943
const tokens = new CommonTokenStream(lexer);
2044
const parser = new ApexParser(tokens);
2145
const context = parser.compilationUnit();
2246
// parser.addParseListener(new interfaceVisitor() as ApexParserListener);
23-
ParseTreeWalker.DEFAULT.walk(new interfaceVisitor() as ApexParserListener, context);
47+
ParseTreeWalker.DEFAULT.walk(this.astListener, context);
2448
return context;
2549
}
2650

27-
public static traverse(filePath: string): CompilationUnitContext {
28-
const fileContent = fs.readFileSync(filePath).toString();
29-
const ast = this.parse(fileContent);
30-
return ast;
31-
}
32-
}
33-
export class interfaceVisitor implements ApexParserListener {
34-
private interfaceImplementations: string[] = [];
51+
private createASTListener(): ApexParserListener {
52+
class ApexMigrationListener implements ApexParserListener {
53+
public constructor(private parser: ApexASTParser) { }
3554

36-
public enterClassDeclaration(ctx: ClassDeclarationContext): void {
37-
this.interfaceImplementations.push(ctx.typeList().typeRef(0).typeName(0).id().Identifier().symbol.text);
38-
}
39-
public enterDotExpression(ctx: DotExpressionContext): void {
40-
// console.log('*********');
41-
// console.log(ctx.expression().start.text);
42-
43-
if (ctx.dotMethodCall()) {
44-
// console.log(ctx.dotMethodCall().anyId().Identifier().symbol.text);
45-
// ctx.dotMethodCall().expressionList().expression(1).children[0].children[0].children[0];
46-
// console.log(ctx.dotMethodCall().expressionList().expression(1).children[0]);
47-
}
48-
// console.log('*********');
49-
}
50-
public enterVariableDeclarator(ctx: VariableDeclaratorContext): void {
51-
if (ctx.id().Identifier().symbol.text === 'DRName') {
52-
// console.log(ctx.expression());
55+
public enterClassDeclaration(ctx: ClassDeclarationContext): void {
56+
const interfaceToBeSearched = this.parser.interfaceName;
57+
if (!interfaceToBeSearched) return;
58+
if (!ctx.typeList() || !ctx.typeList().typeRef()) return;
59+
for (const typeRefContext of ctx.typeList().typeRef())
60+
for (const typeNameContext of typeRefContext.typeName()) {
61+
if (!typeNameContext.id() || !typeNameContext.id().Identifier()) continue;
62+
if (typeNameContext.id().Identifier().symbol.text === interfaceToBeSearched) {
63+
this.parser.implementsInterface.set(interfaceToBeSearched, typeNameContext.id().Identifier().symbol);
64+
}
65+
}
66+
}
67+
68+
public enterDotExpression(ctx: DotExpressionContext): void {
69+
// console.log('*********');
70+
// console.log(ctx.expression().start.text);
71+
if (ctx.dotMethodCall()) {
72+
// console.log(ctx.dotMethodCall().anyId().Identifier().symbol.text);
73+
// ctx.dotMethodCall().expressionList().expression(1).children[0].children[0].children[0];
74+
// console.log(ctx.dotMethodCall().expressionList().expression(1).children[0]);
75+
}
76+
// console.log('*********');
77+
}
78+
79+
public enterVariableDeclarator(ctx: VariableDeclaratorContext): void {
80+
if (ctx.id().Identifier().symbol.text === 'DRName') {
81+
// console.log(ctx.expression());
82+
}
83+
}
5384
}
85+
return new ApexMigrationListener(this);
5486
}
5587
}
5688

57-
const filePath = '/Users/abhinavkumar2/company/plugin-omnistudio-migration-tool/test/FormulaParserService.cls';
58-
ApexASTTraverser.traverse(filePath);
89+
// const filePath = '/Users/abhinavkumar2/company/plugin-omnistudio-migration-tool/test/FormulaParserService.cls';
90+
// new ApexASTParser(filePath, 'callable', '').parse(filePath);
5991

6092
// console.log(ast);

test/FormulaParserService.cls

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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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 apexFilePath = '../../../FormulaParserService.cls';
7+
const interfaceName = 'YourInterface';
8+
const methodName = 'yourMethod';
9+
10+
const apexParser = new ApexASTParser(apexFilePath, interfaceName, methodName);
11+
const implementsInterface = apexParser.implemementsInterface;
12+
// const callsMethods = apexParser.getCallsMethods();
13+
// const className = apexParser.getClassName();
14+
15+
// Add your assertions here based on the expected results
16+
expect(implementsInterface).to.not.be.empty;
17+
// expect(callsMethods).to.not.be.empty;
18+
// expect(className).to.equal('YourClass');
19+
});
20+
});

0 commit comments

Comments
 (0)