diff --git a/types/jexl/index.d.ts b/types/jexl/index.d.ts index dace08345d..6834afe0b7 100644 --- a/types/jexl/index.d.ts +++ b/types/jexl/index.d.ts @@ -1,19 +1,15 @@ -// Type definitions for jexl 1.1 -// Project: https://github.com/tomfrost/jexl +// Type definitions for jexl 2.1 +// Project: https://github.com/TomFrost/Jexl // Definitions by: Marcin Tomczyk // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.2 -// Currently maintained by https://github.com/TomFrost/Jexl - type TransformFunction = (value: any, ...args: any[]) => any; type BinaryOpFunction = (left: any, right: any) => any; type UnaryOpFunction = (right: any) => any; -type EvalCallbackFunction = (err: Error | null, result: any) => void; - /** * Jexl is the Javascript Expression Language, capable of parsing and * evaluating basic to complex expression strings, combined with advanced @@ -54,14 +50,14 @@ declare class Jexl { * @param name The name of the transform function, as it will be used * within Jexl expressions * @param fn The function to be executed when this transform is - * invoked. It will be provided with at least one argument: + * invoked. It will be provided with at least one argument: * - {*} value: The value to be transformed * - {...*} args: The arguments for this transform */ addTransform(name: string, fn: TransformFunction): void; /** - * Syntactic sugar for calling {@link #Jexl:addTransform} repeatedly. This function + * Syntactic sugar for calling {@link #addTransform} repeatedly. This function * accepts a map of one or more transform names to their transform function. * @param map A map of transform names to transform functions */ @@ -75,25 +71,23 @@ declare class Jexl { getTransform(name: string): TransformFunction; /** - * Evaluates a Jexl string within an optional context. + * Asynchronously evaluates a Jexl string within an optional context. * @param expression The Jexl expression to be evaluated - * @param context A mapping of variables to values, which will be + * @param [context] A mapping of variables to values, which will be * made accessible to the Jexl expression when evaluating it - * @param cb An optional callback function to be executed when - * evaluation is complete. It will be supplied with two arguments: - * - err: Present if an error occurred - * - result: The result of the evaluation - * @returns resolves with the result of the evaluation. Note that - * if a callback is supplied, the returned promise will already have - * a '.catch' attached to it in order to pass the error to the callback. + * @returns resolves with the result of the evaluation. */ - eval(expression: string, context?: object, cb?: EvalCallbackFunction): Promise; + eval(expression: string, context?: object): Promise; /** - * Removes a binary or unary operator from the Jexl grammar. - * @param operator The operator string to be removed + * Synchronously evaluates a Jexl string within an optional context. + * @param expression The Jexl expression to be evaluated + * @param [context] A mapping of variables to values, which will be + * made accessible to the Jexl expression when evaluating it + * @returns the result of the evaluation. + * @throws on error */ - removeOp(operator: string): void; + evalSync(expression: string, context?: object): any; } /** diff --git a/types/jexl/jexl-tests.ts b/types/jexl/jexl-tests.ts index 872c9e7dd4..e21dd7e73e 100644 --- a/types/jexl/jexl-tests.ts +++ b/types/jexl/jexl-tests.ts @@ -10,74 +10,104 @@ const context = { age: 36 }; -// Filter an array -// Output: Kane +// Dummy console. Comment it out if you want to run this code and see output +class DummyConsole { + log(...args: string[]) { + } +} + +const console = new DummyConsole(); + +// Dummy helper function +function dbSelectByLastName(val: string, stat: string): Promise { + return new Promise(((resolve, reject) => resolve(184))); +} + +/* Type testing */ + // $ExpectType Promise jexl.eval('assoc[.first == "Lana"].last', context); -// Do math -// Output: 72 -// $ExpectType Promise -jexl.eval('age * (3 - 1)', context, (err, res) => { -}); +// $ExpectType any +jexl.evalSync('assoc[.first == "Lana"].last'); + +// $ExpectType Promise +jexl.eval('age * (3 - 1)', context); -// Concatenate -// Output: Sterling Archer // $ExpectType Promise jexl.eval('name.first + " " + name["la" + "st"]', context); -// Compound -// Output: true // $ExpectType Promise jexl.eval('assoc[.last == "Figgis"].first == "Cyril" && assoc[.last == "Poovey"].first == "Pam"', context); -// Use array indexes -// Output: Cyril Figgis // $ExpectType Promise -jexl.eval('assoc[1]', context, (err, res) => { -}); +jexl.eval('assoc[1]', context); -// Use conditional logic -// Output: working // $ExpectType Promise jexl.eval('age > 62 ? "retired" : "working"', context); -// Transform // $ExpectType void -jexl.addTransform('upper', (val) => { - return val.toUpperCase(); -}); -// Output: DUCHESS ARCHER +jexl.addTransform('upper', (val) => val.toUpperCase()); // $ExpectType Promise jexl.eval('"duchess"|upper + " " + name.last|upper', context); -// Transform asynchronously, with arguments // $ExpectType void -jexl.addTransform('getStat', (val, stat) => { - return Promise.resolve('Test'); // Returns a promise -}); -// Output: 184 +jexl.addTransform('getStat', async (val, stat) => dbSelectByLastName(val, stat)); // $ExpectType Promise -jexl.eval('name.last|getStat("weight")', context, (err, res) => { -}); +jexl.eval('name.last|getStat("weight")', context); -// Transform with multiple arguments // $ExpectType void -jexl.addTransform('substring', (val: string, start: number, end?: number) => { - return val.substring(start, end); -}); - -// Add your own (a)synchronous operators -// Here's a case-insensitive string equality -// $ExpectType void -jexl.addBinaryOp('_=', 20, (left, right) => { - return left.toLowerCase() === right.toLowerCase(); -}); -// Output: true +jexl.addBinaryOp('_=', 20, (left, right) => left.toLowerCase() === right.toLowerCase()); // $ExpectType Promise jexl.eval('"Guest" _= "gUeSt"'); -const newJexlInstance = new jexl.Jexl(); +/* Example - runnable code */ +(async function testStuff() { +// Filter an array asynchronously... + jexl.eval('assoc[.first == "Lana"].last', context).then(filterArray => { + console.log('1. Filter Array', filterArray); // Output: Kane + }); -// $ExpectType Promise -newJexlInstance.eval("true == true"); +// Or synchronously! + console.log('2. Filter Array Sync', jexl.evalSync('assoc[.first == "Lana"].last')); // Output: Kane + +// Do math + const match = await jexl.eval('age * (3 - 1)', context); + console.log('3. Match', match); // Output: 72 + +// Concatenate + const concatenate = await jexl.eval('name.first + " " + name["la" + "st"]', context); + console.log('4. Concatenate', concatenate); // "Sterling Archer" + +// Compound + const compound = await jexl.eval('assoc[.last == "Figgis"].first == "Cyril" && assoc[.last == "Poovey"].first == "Pam"', context); + console.log('5. Compound', compound); // true + +// Use array indexes + const arrayIndex = await jexl.eval('assoc[1]', context); + console.log('6. Array Index', arrayIndex); // { first: 'Cyril', last: 'Figgis' } + +// Use conditional logic + const conditional = await jexl.eval('age > 62 ? "retired" : "working"', context); + console.log('7. Conditional', conditional); // "working" + +// Transform + jexl.addTransform('upper', (val) => val.toUpperCase()); + const transform = await jexl.eval('"duchess"|upper + " " + name.last|upper', context); + console.log('8. Transform', transform); // "DUCHESS ARCHER" + +// Transform asynchronously, with arguments + jexl.addTransform('getStat', async (val, stat) => dbSelectByLastName(val, stat)); + try { + const asyncTransform = await jexl.eval('name.last|getStat("weight")', context); + console.log('9. Async Transform', asyncTransform); // Output: 184 + } catch (e) { + console.log('Database Error', e.stack); + } + +// Add your own (a)synchronous operators +// Here's a case-insensitive string equality + jexl.addBinaryOp('_=', 20, (left, right) => left.toLowerCase() === right.toLowerCase()); + const binaryOp = await jexl.eval('"Guest" _= "gUeSt"'); + console.log('10. Binary Op', binaryOp); // true +})().then(() => console.log('Testing done'));