mirror of
https://github.com/usebruno/bruno.git
synced 2025-06-27 15:31:37 +02:00
feat(eval): handle globals
This commit is contained in:
parent
429ca4093c
commit
3d22f77226
@ -26,14 +26,26 @@ const compileJsExpression = (expr) => {
|
|||||||
const matches = expr.match(/([\w\.$]+)/g) ?? [];
|
const matches = expr.match(/([\w\.$]+)/g) ?? [];
|
||||||
|
|
||||||
// get valid js identifiers (foo, bar)
|
// get valid js identifiers (foo, bar)
|
||||||
const names = matches
|
const vars = new Set(
|
||||||
.filter(match => /^[a-zA-Z$_]/.test(match))
|
matches
|
||||||
.map(match => match.split('.')[0]);
|
.filter(match => /^[a-zA-Z$_]/.test(match)) // starts with valid js identifier (foo.bar)
|
||||||
|
.map(match => match.split('.')[0]) // top level identifier (foo)
|
||||||
|
.filter(name => !JS_KEYWORDS.includes(name)) // exclude js keywords
|
||||||
|
);
|
||||||
|
|
||||||
|
// globals such as Math
|
||||||
|
const globals = [...vars].filter(name => name in globalThis);
|
||||||
|
|
||||||
|
const code = {
|
||||||
|
vars: [...vars].join(", "),
|
||||||
|
// pick global from context or globalThis
|
||||||
|
globals: globals
|
||||||
|
.map(name => ` ${name} = ${name} ?? globalThis.${name};`)
|
||||||
|
.join('')
|
||||||
|
};
|
||||||
|
|
||||||
|
const body = `let { ${code.vars} } = context; ${code.globals}; return ${expr}`;
|
||||||
|
|
||||||
// exclude js keywords and get unique vars
|
|
||||||
const vars = new Set(names.filter(name => !JS_KEYWORDS.includes(name)));
|
|
||||||
const spread = [...vars].join(", ");
|
|
||||||
const body = `const { ${spread} } = context; return ${expr}`;
|
|
||||||
return new Function("context", body);
|
return new Function("context", body);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,32 +44,32 @@ describe("utils", () => {
|
|||||||
it("should identify top level variables", () => {
|
it("should identify top level variables", () => {
|
||||||
const expr = "res.data.pets[0].toUpperCase()";
|
const expr = "res.data.pets[0].toUpperCase()";
|
||||||
evaluateJsExpression(expr, context);
|
evaluateJsExpression(expr, context);
|
||||||
expect(cache.get(expr).toString()).toContain("const { res } = context;");
|
expect(cache.get(expr).toString()).toContain("let { res } = context;");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not duplicate variables", () => {
|
it("should not duplicate variables", () => {
|
||||||
const expr = "res.data.pets[0] + res.data.pets[1]";
|
const expr = "res.data.pets[0] + res.data.pets[1]";
|
||||||
evaluateJsExpression(expr, context);
|
evaluateJsExpression(expr, context);
|
||||||
expect(cache.get(expr).toString()).toContain("const { res } = context;");
|
expect(cache.get(expr).toString()).toContain("let { res } = context;");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should exclude js keywords like true false from vars", () => {
|
it("should exclude js keywords like true false from vars", () => {
|
||||||
const expr = "res.data.pets.length > 0 ? true : false";
|
const expr = "res.data.pets.length > 0 ? true : false";
|
||||||
evaluateJsExpression(expr, context);
|
evaluateJsExpression(expr, context);
|
||||||
expect(cache.get(expr).toString()).toContain("const { res } = context;");
|
expect(cache.get(expr).toString()).toContain("let { res } = context;");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should exclude numbers from vars", () => {
|
it("should exclude numbers from vars", () => {
|
||||||
const expr = "res.data.pets.length + 10";
|
const expr = "res.data.pets.length + 10";
|
||||||
evaluateJsExpression(expr, context);
|
evaluateJsExpression(expr, context);
|
||||||
expect(cache.get(expr).toString()).toContain("const { res } = context;");
|
expect(cache.get(expr).toString()).toContain("let { res } = context;");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should pick variables from complex expressions", () => {
|
it("should pick variables from complex expressions", () => {
|
||||||
const expr = "res.data.pets.map(pet => pet.length)";
|
const expr = "res.data.pets.map(pet => pet.length)";
|
||||||
const result = evaluateJsExpression(expr, context);
|
const result = evaluateJsExpression(expr, context);
|
||||||
expect(result).toEqual([5, 3]);
|
expect(result).toEqual([5, 3]);
|
||||||
expect(cache.get(expr).toString()).toContain("const { res, pet } = context;");
|
expect(cache.get(expr).toString()).toContain("let { res, pet } = context;");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be ok picking extra vars from strings", () => {
|
it("should be ok picking extra vars from strings", () => {
|
||||||
@ -77,7 +77,39 @@ describe("utils", () => {
|
|||||||
const result = evaluateJsExpression(expr, context);
|
const result = evaluateJsExpression(expr, context);
|
||||||
expect(result).toBe("hello bruno");
|
expect(result).toBe("hello bruno");
|
||||||
// extra var hello is harmless
|
// extra var hello is harmless
|
||||||
expect(cache.get(expr).toString()).toContain("const { hello, res } = context;");
|
expect(cache.get(expr).toString()).toContain("let { hello, res } = context;");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should evaluate expressions referencing globals", () => {
|
||||||
|
const startTime = new Date("2022-02-01").getTime();
|
||||||
|
const currentTime = new Date("2022-02-02").getTime();
|
||||||
|
|
||||||
|
jest.useFakeTimers({ now: currentTime });
|
||||||
|
|
||||||
|
const expr = "Math.max(Date.now(), startTime)";
|
||||||
|
const result = evaluateJsExpression(expr, { startTime });
|
||||||
|
|
||||||
|
expect(result).toBe(currentTime);
|
||||||
|
|
||||||
|
expect(cache.get(expr).toString()).toContain("Math = Math ?? globalThis.Math;");
|
||||||
|
expect(cache.get(expr).toString()).toContain("Date = Date ?? globalThis.Date;");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should use global overridden in context", () => {
|
||||||
|
const startTime = new Date("2022-02-01").getTime();
|
||||||
|
const currentTime = new Date("2022-02-02").getTime();
|
||||||
|
|
||||||
|
jest.useFakeTimers({ now: currentTime });
|
||||||
|
|
||||||
|
const context = {
|
||||||
|
Date: { now: () => new Date("2022-01-31").getTime() },
|
||||||
|
startTime
|
||||||
|
};
|
||||||
|
|
||||||
|
const expr = "Math.max(Date.now(), startTime)";
|
||||||
|
const result = evaluateJsExpression(expr, context);
|
||||||
|
|
||||||
|
expect(result).toBe(startTime);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user