mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-16 15:45:13 +00:00
Implement getVariables method for expression evaluation (#4304)
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@gitbook/expr": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Implement a getVariables function for ExpressionRuntime
|
||||||
@@ -195,6 +195,49 @@ describe('ExpressionRuntime', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getVariables', () => {
|
||||||
|
it.each([
|
||||||
|
{
|
||||||
|
scenario: 'single variable',
|
||||||
|
condition: 'isBetaUser === true',
|
||||||
|
expectedVariables: ['isBetaUser'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: 'multiple variables',
|
||||||
|
condition: 'useProductA && !isBetaUser',
|
||||||
|
expectedVariables: ['useProductA', 'isBetaUser'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: 'member expression',
|
||||||
|
condition: 'user.role === "admin"',
|
||||||
|
expectedVariables: ['user.role'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: 'nested member expression with method call',
|
||||||
|
condition: 'products.includes("productA") && userSegments.alpha',
|
||||||
|
expectedVariables: ['products.includes', 'userSegments.alpha'],
|
||||||
|
},
|
||||||
|
])(
|
||||||
|
'should return variables used in expression: $scenario',
|
||||||
|
({ condition, expectedVariables }) => {
|
||||||
|
expect(runtime.getVariables(condition)).toEqual(expectedVariables);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
{
|
||||||
|
scenario: 'invalid syntax',
|
||||||
|
condition: 't}=d',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: 'non conditional expression',
|
||||||
|
condition: 'const a = 1;',
|
||||||
|
},
|
||||||
|
])('should return an empty array for invalid expressions: $scenario', ({ condition }) => {
|
||||||
|
expect(runtime.getVariables(condition)).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe.skip('generate', () => {
|
describe.skip('generate', () => {
|
||||||
it.each([
|
it.each([
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
import { parse as parseLoose } from 'acorn-loose';
|
import { parse as parseLoose } from 'acorn-loose';
|
||||||
import escodegen from 'escodegen';
|
import escodegen from 'escodegen';
|
||||||
import evalESTreeExpr from 'eval-estree-expression';
|
import evalESTreeExpr from 'eval-estree-expression';
|
||||||
const { evaluate } = evalESTreeExpr;
|
const { evaluate, variables } = evalESTreeExpr;
|
||||||
|
|
||||||
import { AutoComplete } from './autocomplete';
|
import { AutoComplete } from './autocomplete';
|
||||||
import { ExpressionError } from './errors';
|
import { ExpressionError } from './errors';
|
||||||
@@ -162,6 +162,28 @@ export class ExpressionRuntime {
|
|||||||
.join('');
|
.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an expression, returns a list of variables used in the expression.
|
||||||
|
*/
|
||||||
|
public getVariables(expr: string): string[] {
|
||||||
|
try {
|
||||||
|
const parsed = this.parse(expr);
|
||||||
|
|
||||||
|
if (parsed.invalidNodes.length > 0) {
|
||||||
|
throw new ExpressionError('Invalid nodes found when parsing');
|
||||||
|
}
|
||||||
|
|
||||||
|
return variables(parsed.result, {
|
||||||
|
functions: true,
|
||||||
|
withMembers: true,
|
||||||
|
generate: escodegen.generate,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error(`Error while parsing expression ${expr} to get variables`, error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a binary expression and returns an @ExpressionParserResult.
|
* Parses a binary expression and returns an @ExpressionParserResult.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+10
@@ -41,6 +41,16 @@ declare module 'eval-estree-expression' {
|
|||||||
options?: EvalESTreeExpressionOptions
|
options?: EvalESTreeExpressionOptions
|
||||||
): Promise<any>;
|
): Promise<any>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an ESTree-compliant AST node, returns a list of variables used in the expression.
|
||||||
|
* @param ast An object representing an ESTree-compliant AST node.
|
||||||
|
* @param options Options for evaluation and compilation.
|
||||||
|
*/
|
||||||
|
export function variables<ASTNode>(
|
||||||
|
ast: ASTNode,
|
||||||
|
options?: EvalESTreeExpressionOptions
|
||||||
|
): string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates an ESTree expression synchronously against a given context.
|
* Evaluates an ESTree expression synchronously against a given context.
|
||||||
* @param expression - An object representing an ESTree-compliant AST node.
|
* @param expression - An object representing an ESTree-compliant AST node.
|
||||||
|
|||||||
Reference in New Issue
Block a user