Skip to content

Commit

Permalink
feat: add support for context var index (#111)
Browse files Browse the repository at this point in the history
* feat: add support for context var index

* fix: context var mappings

* fix: context var mappings
  • Loading branch information
koladilip authored Jul 1, 2024
1 parent 048f031 commit 5f1d213
Show file tree
Hide file tree
Showing 12 changed files with 346 additions and 73 deletions.
25 changes: 18 additions & 7 deletions src/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { JsonTemplateTranslator } from './translator';
import {
EngineOptions,
Expression,
FlatMappingAST,
FlatMappingPaths,
PathType,
SyntaxType,
Expand Down Expand Up @@ -66,7 +67,7 @@ export class JsonTemplateEngine {
}));
}

static validateMappings(mappings: FlatMappingPaths[]) {
static validateMappings(mappings: FlatMappingPaths[], options?: EngineOptions) {
JsonTemplateEngine.prepareMappings(mappings).forEach((mapping) => {
if (
!JsonTemplateEngine.isValidJSONPath(mapping.input) ||
Expand All @@ -79,18 +80,24 @@ export class JsonTemplateEngine {
);
}
});
JsonTemplateEngine.parseMappingPaths(mappings);
JsonTemplateEngine.parseMappingPaths(mappings, options);
}

static parseMappingPaths(mappings: FlatMappingPaths[], options?: EngineOptions): Expression {
const flatMappingAST = JsonTemplateEngine.prepareMappings(mappings)
private static createFlatMappingsAST(
mappings: FlatMappingPaths[],
options?: EngineOptions,
): FlatMappingAST[] {
return JsonTemplateEngine.prepareMappings(mappings)
.filter((mapping) => mapping.input && mapping.output)
.map((mapping) => ({
...mapping,
inputExpr: JsonTemplateEngine.parse(mapping.input, options).statements[0],
outputExpr: JsonTemplateEngine.parse(mapping.output, options).statements[0],
}));
return convertToObjectMapping(flatMappingAST);
}

static parseMappingPaths(mappings: FlatMappingPaths[], options?: EngineOptions): Expression {
return convertToObjectMapping(JsonTemplateEngine.createFlatMappingsAST(mappings, options));
}

static create(templateOrExpr: TemplateInput, options?: EngineOptions): JsonTemplateEngine {
Expand Down Expand Up @@ -120,9 +127,13 @@ export class JsonTemplateEngine {
return JsonTemplateEngine.translateExpression(JsonTemplateEngine.parse(template, options));
}

static reverseTranslate(expr: Expression, options?: EngineOptions): string {
static reverseTranslate(expr: Expression | FlatMappingPaths[], options?: EngineOptions): string {
const translator = new JsonTemplateReverseTranslator(options);
return translator.translate(expr);
let newExpr = expr;
if (Array.isArray(expr)) {
newExpr = JsonTemplateEngine.parseMappingPaths(expr as FlatMappingPaths[], options);
}
return translator.translate(newExpr as Expression);
}

static convertMappingsToTemplate(mappings: FlatMappingPaths[], options?: EngineOptions): string {
Expand Down
14 changes: 9 additions & 5 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1443,9 +1443,9 @@ export class JsonTemplateParser {
return this.lexer.throwUnexpectedToken();
}

private static pathContainsVariables(parts: Expression[]): boolean {
private static shouldPathBeConvertedAsBlock(parts: Expression[]): boolean {
return parts
.filter((part) => part.type === SyntaxType.PATH_OPTIONS)
.filter((part, index) => part.type === SyntaxType.PATH_OPTIONS && index < parts.length - 1)
.some((part) => part.options?.index ?? part.options?.item);
}

Expand Down Expand Up @@ -1550,17 +1550,21 @@ export class JsonTemplateParser {
newPathExpr.parts.shift();
}

const shouldConvertAsBlock = JsonTemplateParser.pathContainsVariables(newPathExpr.parts);
const shouldConvertAsBlock = JsonTemplateParser.shouldPathBeConvertedAsBlock(newPathExpr.parts);
let lastPart = getLastElement(newPathExpr.parts);
let fnExpr: FunctionCallExpression | undefined;
if (lastPart?.type === SyntaxType.FUNCTION_CALL_EXPR) {
fnExpr = newPathExpr.parts.pop() as FunctionCallExpression;
}

lastPart = getLastElement(newPathExpr.parts);
if (lastPart?.type === SyntaxType.PATH_OPTIONS) {
newPathExpr.parts.pop();
if (lastPart?.type === SyntaxType.PATH_OPTIONS && lastPart.options?.toArray) {
newPathExpr.returnAsArray = lastPart.options?.toArray;
if (!lastPart.options.item && !lastPart.options.index) {
newPathExpr.parts.pop();
} else {
lastPart.options.toArray = false;
}
}
newPathExpr.parts = JsonTemplateParser.combinePathOptionParts(newPathExpr.parts);

Expand Down
8 changes: 5 additions & 3 deletions src/reverse_translator.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { JsonTemplateEngine } from './engine';
import { PathType } from './types';

describe('reverse_translator', () => {
it('should reverse translate with indentation', () => {
Expand All @@ -12,7 +13,7 @@ describe('reverse_translator', () => {

it('should reverse translate json mappings', () => {
const template = JsonTemplateEngine.reverseTranslate(
JsonTemplateEngine.parse([
[
{
input: '$.userId',
output: '$.user.id',
Expand Down Expand Up @@ -41,10 +42,11 @@ describe('reverse_translator', () => {
input: '$.products[?(@.category)].(@.price * @.quantity * (1 - $.discount / 100)).sum()',
output: '$.events[0].revenue',
},
]),
],
{ defaultPathType: PathType.JSON },
);
expect(template).toEqual(
'{\n "user": {\n "id": $.userId\n },\n "events": [{\n "items": $.products{.category}.({\n "discount": $.discount,\n "product_id": .id,\n "options": .variations[*].({\n "s": .size\n })[],\n "value": .price * .quantity * (1 - $.discount / 100)\n })[],\n "name": $.events[0],\n "revenue": $.products{.category}.(.price * .quantity * (1 - $.discount / 100)).sum()\n }]\n}',
'{\n "user": {\n "id": $.userId\n },\n "events": [{\n "items": $.products[?(@.category)].({\n "discount": $.discount,\n "product_id": @.id,\n "options": @.variations[*].({\n "s": @.size\n })[],\n "value": @.price * @.quantity * (1 - $.discount / 100)\n })[],\n "name": $.events[0],\n "revenue": $.products[?(@.category)].(@.price * @.quantity * (1 - $.discount / 100)).sum()\n }]\n}',
);
});
});
27 changes: 17 additions & 10 deletions src/translator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,17 +310,21 @@ export class JsonTemplateTranslator {
code.push(JsonTemplateTranslator.covertToArrayValue(data));
if (
JsonTemplateTranslator.isArrayFilterExpr(expr.parts[partNum]) ||
JsonTemplateTranslator.isAllFilterExpr(expr.parts[partNum]) ||
JsonTemplateTranslator.isToArray(expr, partNum)
) {
code.push(`${data} = [${data}];`);
}
return code.join('');
}

static isAllFilterExpr(expr: Expression): boolean {
return (
expr.type === SyntaxType.OBJECT_FILTER_EXPR && expr.filter.type === SyntaxType.ALL_FILTER_EXPR
);
}

private translatePathParts(expr: PathExpression, dest: string): string {
if (!expr.parts.length) {
return '';
}
const { parts } = expr;
const code: string[] = [];
const numParts = parts.length;
Expand Down Expand Up @@ -384,8 +388,9 @@ export class JsonTemplateTranslator {
}
const code: string[] = [];
code.push(this.translatePathRoot(expr, dest, ctx));
code.push(this.translatePathParts(expr, dest));
if (expr.returnAsArray && expr.parts.length === 0) {
if (expr.parts.length > 0) {
code.push(this.translatePathParts(expr, dest));
} else if (expr.returnAsArray) {
code.push(JsonTemplateTranslator.covertToArrayValue(dest));
}
return code.join('');
Expand Down Expand Up @@ -786,11 +791,13 @@ export class JsonTemplateTranslator {
ctx: string,
): string {
const code: string[] = [];
const condition = this.acquireVar();
code.push(JsonTemplateTranslator.generateAssignmentCode(condition, 'true'));
code.push(this.translateExpr(expr.filter, condition, ctx));
code.push(`if(!${condition}) {${dest} = undefined;}`);
this.releaseVars(condition);
if (expr.filter.type !== SyntaxType.ALL_FILTER_EXPR) {
const condition = this.acquireVar();
code.push(JsonTemplateTranslator.generateAssignmentCode(condition, 'true'));
code.push(this.translateExpr(expr.filter, condition, ctx));
code.push(`if(!${condition}) {${dest} = undefined;}`);
this.releaseVars(condition);
}
return code.join('');
}

Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ export type FlatMappingPaths = {
};

export type FlatMappingAST = FlatMappingPaths & {
inputExpr: PathExpression;
inputExpr: Expression;
outputExpr: PathExpression;
};

Expand Down
Loading

0 comments on commit 5f1d213

Please sign in to comment.