From b3b2c39df680f88e1e6d3615245754ae5f0380d0 Mon Sep 17 00:00:00 2001 From: Akshay Nair Date: Sat, 8 Jan 2022 21:17:10 +0530 Subject: feat(eval): implements object property matching --- src/eval/index.ts | 38 +++++++++++++++++++++----------------- src/parser/index.ts | 30 ++++++++++++++++++++---------- src/parser/utils.ts | 16 +++++++++------- tests/eval.spec.ts | 34 ++++++++++++++++++++++++++++++---- tests/parser.spec.ts | 5 ++++- 5 files changed, 84 insertions(+), 39 deletions(-) diff --git a/src/eval/index.ts b/src/eval/index.ts index f80c04d..b4dcf48 100644 --- a/src/eval/index.ts +++ b/src/eval/index.ts @@ -1,23 +1,27 @@ -import {pipe} from 'fp-ts/function'; +import { pipe } from 'fp-ts/function' import { Expr, ListExpr } from '../types' -import {match} from '../utils'; +import { match } from '../utils' export const find = ([startO, exprs, endO]: ListExpr, list: T[]): any => { - const check = (expr: Expr) => (x: T, i: number, ls: T[]): boolean => { - return pipe( - expr, - match({ - AnyItem: _ => true, - AnyNumber: _ => typeof x === 'number', - AnyString: _ => typeof x === 'string', - AnyBool: _ => typeof x === 'boolean', - Truthy: _ => !!x, - Falsey: _ => !x, - Group: ({ exprs }) => exprs.every(e => check(e)(x, i, ls)), - _: _ => false, - }) - ) - }; + const check = + (expr: Expr) => + (x: T, i: number, ls: T[]): boolean => { + return pipe( + expr, + match({ + AnyItem: _ => true, + AnyNumber: _ => typeof x === 'number', + AnyString: _ => typeof x === 'string', + AnyBool: _ => typeof x === 'boolean', + Truthy: _ => !!x, + Falsey: _ => !x, + Group: ({ exprs }) => exprs.every(e => check(e)(x, i, ls)), + PropertyMatch: ({ name, exprs }) => + name in x && exprs.every(e => check(e)(x[name], i, ls)), + _: _ => false, + }), + ) + } const cs = exprs.map(check) diff --git a/src/parser/index.ts b/src/parser/index.ts index 2f5781e..386fa94 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -30,8 +30,8 @@ const anyBool = mapTo(symbol('\\b'), _ => Expr.AnyBool(null)) const truthy = mapTo(symbol('\\T'), _ => Expr.Truthy(null)) const falsey = mapTo(symbol('\\F'), _ => Expr.Falsey(null)) -const wrapQuantifiers: (e: ParserResult) => ParserResult = - chain(([expr, input]) => +const wrapQuantifiers: (e: ParserResult) => ParserResult = chain( + ([expr, input]) => pipe( input, or([ @@ -41,7 +41,7 @@ const wrapQuantifiers: (e: ParserResult) => ParserResult = ]), orElse(_ => right([expr, input])), ), - ) +) const wrapAlt: (e: ParserResult) => ParserResult = chain( ([expr, input]) => @@ -63,12 +63,18 @@ export const propertyName: Parser = pipe( p => suffixed(p, whitespaces0), ) -const objectProperty = (input: string) => pipe( - input, - mapTo(delimited(symbol('['), pair(propertyName, many0(expressionP)), symbol(']')), ([name, exprs]) => - Expr.PropertyMatch({ name, exprs }), - ), -) +const objectProperty = (input: string) => + pipe( + input, + mapTo( + delimited( + symbol('['), + pair(propertyName, many0(expressionP)), + symbol(']'), + ), + ([name, exprs]) => Expr.PropertyMatch({ name, exprs }), + ), + ) const expressionP: Parser = (input: string) => pipe( @@ -90,7 +96,11 @@ const expressionP: Parser = (input: string) => wrapAlt, ) -export const parser: Parser = tuple3(optional(start), many1(expressionP), optional(end)) +export const parser: Parser = tuple3( + optional(start), + many1(expressionP), + optional(end), +) /* diff --git a/src/parser/utils.ts b/src/parser/utils.ts index 9e05286..841d77c 100644 --- a/src/parser/utils.ts +++ b/src/parser/utils.ts @@ -40,14 +40,16 @@ export const many0 = (parser: Parser): Parser> => ) export const many1 = (parser: Parser): Parser> => - recoverInput(flow( - many0(parser), - chain(([res, inp]) => - res.length > 0 - ? right([res, inp]) - : left([`many1 failed to parse at ${inp}`, inp]), + recoverInput( + flow( + many0(parser), + chain(([res, inp]) => + res.length > 0 + ? right([res, inp]) + : left([`many1 failed to parse at ${inp}`, inp]), + ), ), - )) + ) const recoverInput = (p: Parser): Parser => diff --git a/tests/eval.spec.ts b/tests/eval.spec.ts index 9bf3000..dada762 100644 --- a/tests/eval.spec.ts +++ b/tests/eval.spec.ts @@ -10,14 +10,14 @@ describe('Eval', () => { const liexp: ListExpr = [ none, - [ Expr.AnyNumber(null), Expr.Truthy(null) ], + [Expr.AnyNumber(null), Expr.Truthy(null)], none, ] expect(find(liexp, list)).toEqual([1, 3, 5]) const liexp2: ListExpr = [ none, - [ Expr.Falsey(null), Expr.Truthy(null) ], + [Expr.Falsey(null), Expr.Truthy(null)], none, ] expect(find(liexp2, list)).toEqual([]) @@ -28,10 +28,36 @@ describe('Eval', () => { const liexp: ListExpr = [ none, - [ Expr.AnyItem(null), Expr.Group({ exprs: [ Expr.AnyNumber(null), Expr.Truthy(null)] }) ], + [ + Expr.AnyItem(null), + Expr.Group({ exprs: [Expr.AnyNumber(null), Expr.Truthy(null)] }), + ], none, ] expect(find(liexp, list)).toEqual([1, 3, 5]) }) -}) + it('object property', () => { + const list = [ + { name: 20, age: 'hello' }, + { name: 'gello', age: 20 }, + { name: '', age: 20 }, + { name: 'Wow' }, + { age: 20 }, + ] + + const liexp: ListExpr = [ + none, + [ + Expr.PropertyMatch({ + name: 'name', + exprs: [Expr.AnyString(null), Expr.Truthy(null)], + }), + Expr.PropertyMatch({ name: 'age', exprs: [Expr.AnyNumber(null)] }), + ], + none, + ] + + expect(find(liexp, list)).toEqual([{ name: 'gello', age: 20 }]) + }) +}) diff --git a/tests/parser.spec.ts b/tests/parser.spec.ts index 1ebd290..4db0894 100644 --- a/tests/parser.spec.ts +++ b/tests/parser.spec.ts @@ -91,7 +91,10 @@ describe('Foobar', () => { [ none, [ - Expr.PropertyMatch({ name: 'name', exprs: [Expr.AnyString(null), Expr.Truthy(null)] }), + Expr.PropertyMatch({ + name: 'name', + exprs: [Expr.AnyString(null), Expr.Truthy(null)], + }), Expr.PropertyMatch({ name: 'age', exprs: [Expr.AnyNumber(null)] }), ], none, -- cgit v1.3.1