UNPKG

@qualifyze/airtable-formulator

Version:
855 lines 28.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const globals_1 = require("@jest/globals"); const parse_1 = require("../parse"); (0, globals_1.describe)("parse()", () => { (0, globals_1.it)("should work with the example in the readme", () => { (0, globals_1.expect)((0, parse_1.parse)("IF({name}='Robert',{age},0)")).toMatchObject({ type: "functionCall", reference: { value: "IF", }, argumentList: { args: [ { type: "operation", left: { type: "fieldReference", value: "name", }, operator: { value: "=", }, right: { type: "string", value: "Robert", }, }, { type: "fieldReference", }, { type: "number", }, ], }, }); }); (0, globals_1.it)("should parse empty extremes", () => { (0, globals_1.expect)((0, parse_1.parse)("")).toBeNull(); (0, globals_1.expect)((0, parse_1.parse)(" ")).toBeNull(); }); (0, globals_1.it)("should parse literals", () => { (0, globals_1.expect)((0, parse_1.parse)("1")).toMatchObject({ type: "number", value: "1", }); (0, globals_1.expect)((0, parse_1.parse)("1.234")).toMatchObject({ type: "number", value: "1.234", }); (0, globals_1.expect)((0, parse_1.parse)("'hello'")).toMatchObject({ type: "string", value: "hello", opener: { type: "quoteMark", }, closer: { type: "quoteMark", }, }); }); (0, globals_1.it)("should parse field references", () => { (0, globals_1.expect)((0, parse_1.parse)("foo")).toMatchObject({ type: "fieldReference", value: "foo", }); (0, globals_1.expect)((0, parse_1.parse)("{foo bar}")).toMatchObject({ type: "fieldReference", value: "foo bar", }); }); (0, globals_1.it)("should parse modifiers", () => { (0, globals_1.expect)((0, parse_1.parse)("-1")).toMatchObject({ type: "modifier", value: "-1", operator: { type: "operator", value: "-", }, operand: { type: "number", value: "1", }, }); (0, globals_1.expect)((0, parse_1.parse)("-a")).toMatchObject({ type: "modifier", value: "-a", operator: { type: "operator", value: "-", }, operand: { type: "fieldReference", value: "a", }, }); (0, globals_1.expect)((0, parse_1.parse)("--a")).toMatchObject({ type: "modifier", value: "--a", operator: { type: "operator", value: "-", }, operand: { type: "modifier", value: "-a", operator: { type: "operator", value: "-", }, operand: { type: "fieldReference", value: "a", }, }, }); }); (0, globals_1.it)("should parse operations", () => { (0, globals_1.expect)((0, parse_1.parse)("1 + 2")).toMatchObject({ type: "operation", value: "1 + 2", operator: { type: "operator", value: "+", }, left: { type: "number", value: "1", }, right: { type: "number", value: "2", }, }); (0, globals_1.expect)((0, parse_1.parse)("1 != 3")).toMatchObject({ type: "operation", value: "1 != 3", operator: { type: "operator", value: "!=", }, left: { type: "number", value: "1", }, right: { type: "number", value: "3", }, }); (0, globals_1.expect)((0, parse_1.parse)("1 + 2 + 3")).toMatchObject({ type: "operation", value: "1 + 2 + 3", operator: { type: "operator", value: "+", }, left: { type: "operation", value: "1 + 2", operator: { type: "operator", value: "+", }, left: { type: "number", value: "1", }, right: { type: "number", value: "2", }, }, right: { type: "number", value: "3", }, }); (0, globals_1.expect)((0, parse_1.parse)("-1 + 2")).toMatchObject({ type: "operation", left: { type: "modifier", operator: { value: "-", }, operand: { type: "number", value: "1", }, }, operator: { type: "operator", value: "+", }, right: { type: "number", value: "2", }, }); (0, globals_1.expect)((0, parse_1.parse)("1 <= 5")).toMatchObject({ type: "operation", left: { type: "number", value: "1", }, operator: { type: "operator", value: "<=", }, right: { type: "number", value: "5", }, }); }); (0, globals_1.it)("should respect operator precedence", () => { (0, globals_1.expect)((0, parse_1.parse)("1 + 2 * 3")).toMatchObject({ left: { value: "1", }, operator: { value: "+", }, right: { left: { value: "2", }, operator: { value: "*", }, right: { value: "3", }, }, }); (0, globals_1.expect)((0, parse_1.parse)("1 * 2 + 3")).toMatchObject({ left: { left: { value: "1", }, operator: { value: "*", }, right: { value: "2", }, }, operator: { value: "+", }, right: { value: "3", }, }); }); (0, globals_1.it)("should parse enclosed expressions", () => { (0, globals_1.expect)((0, parse_1.parse)("(1)")).toMatchObject({ type: "enclosedExpression", value: "1", opener: { type: "openParenthesis", }, closer: { type: "closeParenthesis", }, expression: { type: "number", value: "1", }, }); (0, globals_1.expect)((0, parse_1.parse)("(1 + 2)")).toMatchObject({ type: "enclosedExpression", value: "1 + 2", opener: { type: "openParenthesis", }, closer: { type: "closeParenthesis", }, expression: { type: "operation", value: "1 + 2", operator: { type: "operator", value: "+", }, left: { type: "number", value: "1", }, right: { type: "number", value: "2", }, }, }); (0, globals_1.expect)((0, parse_1.parse)("((1))")).toMatchObject({ type: "enclosedExpression", value: "(1)", expression: { type: "enclosedExpression", value: "1", expression: { type: "number", value: "1", }, }, }); (0, globals_1.expect)((0, parse_1.parse)("((0) * (0))")).toMatchObject({ type: "enclosedExpression", value: "(0) * (0)", expression: { type: "operation", value: "(0) * (0)", operator: { type: "operator", value: "*", }, left: { type: "enclosedExpression", value: "0", expression: { type: "number", value: "0", }, }, right: { type: "enclosedExpression", value: "0", expression: { type: "number", value: "0", }, }, }, }); }); (0, globals_1.it)("should parse function calls", () => { (0, globals_1.expect)((0, parse_1.parse)("foo()")).toMatchObject({ type: "functionCall", value: "foo()", argumentList: { type: "argumentList", args: [], }, reference: { type: "functionReference", value: "foo", }, }); (0, globals_1.expect)((0, parse_1.parse)("foo(1)")).toMatchObject({ type: "functionCall", value: "foo(1)", argumentList: { type: "argumentList", args: [ { type: "number", value: "1", }, ], }, reference: { type: "functionReference", value: "foo", }, }); (0, globals_1.expect)((0, parse_1.parse)("foo(a)")).toMatchObject({ type: "functionCall", value: "foo(a)", argumentList: { type: "argumentList", args: [ { type: "fieldReference", value: "a", }, ], }, reference: { type: "functionReference", value: "foo", }, }); (0, globals_1.expect)((0, parse_1.parse)("foo('a')")).toMatchObject({ type: "functionCall", value: "foo('a')", argumentList: { type: "argumentList", args: [ { type: "string", value: "a", }, ], }, reference: { type: "functionReference", value: "foo", }, }); (0, globals_1.expect)((0, parse_1.parse)("foo(bar())")).toMatchObject({ type: "functionCall", value: "foo(bar())", argumentList: { type: "argumentList", args: [ { type: "functionCall", value: "bar()", argumentList: { type: "argumentList", args: [], }, reference: { type: "functionReference", value: "bar", }, }, ], }, reference: { type: "functionReference", value: "foo", }, }); (0, globals_1.expect)((0, parse_1.parse)("foo(1, 2)")).toMatchObject({ type: "functionCall", value: "foo(1, 2)", argumentList: { type: "argumentList", args: [ { type: "number", value: "1", }, { type: "number", value: "2", }, ], }, reference: { type: "functionReference", value: "foo", }, }); (0, globals_1.expect)((0, parse_1.parse)("foo(1, a, 'x', bar())")).toMatchObject({ type: "functionCall", argumentList: { args: [ { type: "number", value: "1", }, { type: "fieldReference", value: "a", }, { type: "string", value: "x", }, { type: "functionCall", argumentList: { args: [], }, reference: { value: "bar", }, }, ], }, reference: { type: "functionReference", value: "foo", }, }); (0, globals_1.expect)((0, parse_1.parse)("foo(1, bar(), 2)")).toMatchObject({ type: "functionCall", argumentList: { args: [ { type: "number", value: "1", }, { type: "functionCall", argumentList: { args: [], }, reference: { value: "bar", }, }, { type: "number", value: "2", }, ], }, reference: { value: "foo", }, }); (0, globals_1.expect)((0, parse_1.parse)("foo(bar(), 'x', 3)")).toMatchObject({ argumentList: { args: [ { type: "functionCall", argumentList: { args: [], }, reference: { value: "bar", }, }, { type: "string", value: "x", }, { type: "number", value: "3", }, ], }, reference: { value: "foo", }, }); (0, globals_1.expect)((0, parse_1.parse)("IF(TRUE(), FALSE())")).toMatchObject({ type: "functionCall", reference: { value: "IF" }, argumentList: { type: "argumentList", args: [ { type: "functionCall", reference: { value: "TRUE" }, argumentList: { args: [], }, }, { type: "functionCall", reference: { value: "FALSE" }, argumentList: { args: [], }, }, ], }, }); }); (0, globals_1.it)("should parse complicated formulas", () => { (0, globals_1.expect)((0, parse_1.parse)("a+foo()")).toMatchInlineSnapshot(` Object { "end": 6, "left": Object { "end": 1, "start": 0, "type": "fieldReference", "value": "a", }, "members": Array [ Object { "end": 1, "start": 0, "type": "fieldReference", "value": "a", }, Object { "end": 2, "start": 1, "type": "operator", "value": "+", }, Object { "argumentList": Object { "args": Array [], "closer": Object { "end": 7, "start": 6, "type": "closeParenthesis", "value": ")", }, "end": 6, "members": Array [], "opener": Object { "end": 6, "start": 5, "type": "openParenthesis", "value": "(", }, "start": 6, "type": "argumentList", "value": "", }, "end": 6, "members": Array [ Object { "end": 5, "start": 2, "type": "functionReference", "value": "foo", }, Object { "args": Array [], "closer": Object { "end": 7, "start": 6, "type": "closeParenthesis", "value": ")", }, "end": 6, "members": Array [], "opener": Object { "end": 6, "start": 5, "type": "openParenthesis", "value": "(", }, "start": 6, "type": "argumentList", "value": "", }, ], "reference": Object { "end": 5, "start": 2, "type": "functionReference", "value": "foo", }, "start": 2, "type": "functionCall", "value": "foo()", }, ], "operator": Object { "end": 2, "start": 1, "type": "operator", "value": "+", }, "right": Object { "argumentList": Object { "args": Array [], "closer": Object { "end": 7, "start": 6, "type": "closeParenthesis", "value": ")", }, "end": 6, "members": Array [], "opener": Object { "end": 6, "start": 5, "type": "openParenthesis", "value": "(", }, "start": 6, "type": "argumentList", "value": "", }, "end": 6, "members": Array [ Object { "end": 5, "start": 2, "type": "functionReference", "value": "foo", }, Object { "args": Array [], "closer": Object { "end": 7, "start": 6, "type": "closeParenthesis", "value": ")", }, "end": 6, "members": Array [], "opener": Object { "end": 6, "start": 5, "type": "openParenthesis", "value": "(", }, "start": 6, "type": "argumentList", "value": "", }, ], "reference": Object { "end": 5, "start": 2, "type": "functionReference", "value": "foo", }, "start": 2, "type": "functionCall", "value": "foo()", }, "start": 0, "type": "operation", "value": "a+foo()", } `); (0, globals_1.expect)((0, parse_1.parse)("IF(AND(name='Robert',age >= {minimum age} + 10), TRUE(), 'not robert or underage')")).toMatchObject({ type: "functionCall", reference: { value: "IF" }, argumentList: { args: [ { type: "functionCall", reference: { value: "AND" }, argumentList: { args: [ { type: "operation", left: { type: "fieldReference", value: "name", }, operator: { value: "=", }, right: { type: "string", value: "Robert", }, }, { type: "operation", left: { type: "fieldReference", value: "age", }, operator: { value: ">=", }, right: { type: "operation", left: { type: "fieldReference", value: "minimum age", }, operator: { value: "+", }, right: { value: "10", }, }, }, ], }, }, { type: "functionCall", reference: { value: "TRUE" }, argumentList: { args: [], }, }, { value: "not robert or underage", }, ], }, }); }); (0, globals_1.it)("should throw on invalid function call syntax", () => { (0, globals_1.expect)(() => (0, parse_1.parse)("foo(,)")).toThrowErrorMatchingInlineSnapshot(`"Syntax Error while parsing argumentSeparator node at position 4: Expected at least one node before separator, but got none"`); (0, globals_1.expect)(() => (0, parse_1.parse)("foo(,3)")).toThrowErrorMatchingInlineSnapshot(`"Syntax Error while parsing argumentSeparator node at position 4: Expected at least one node before separator, but got none"`); (0, globals_1.expect)(() => (0, parse_1.parse)("foo(1,,3)")).toThrowErrorMatchingInlineSnapshot(`"Syntax Error while parsing argumentSeparator node at position 6: Expected at least one node before separator, but got none"`); (0, globals_1.expect)(() => (0, parse_1.parse)("foo(2,)")).toThrowErrorMatchingInlineSnapshot(`"Syntax Error while parsing argumentSeparator node at position 5: expected at least one node after separator, but got 0"`); (0, globals_1.expect)(() => (0, parse_1.parse)("(1,2)")).toThrowErrorMatchingInlineSnapshot(`"Syntax Error while parsing group node at position 1: Expected an argument list to be preceded by a reference, but got undefined instead"`); (0, globals_1.expect)(() => (0, parse_1.parse)("foo(1,2)s")).toThrowErrorMatchingInlineSnapshot(`"Syntax Error while parsing reference node at position 8: Unexpected node reference"`); (0, globals_1.expect)(() => (0, parse_1.parse)("1,2")).toThrowErrorMatchingInlineSnapshot(`"Syntax Error while parsing argumentSeparator node at position 1: Unexpected node argumentSeparator"`); (0, globals_1.expect)(() => (0, parse_1.parse)("f o(1,2)")).toThrowErrorMatchingInlineSnapshot(`"Syntax Error while parsing reference node at position 2: Unexpected node reference"`); (0, globals_1.expect)(() => (0, parse_1.parse)("&3")).toThrowErrorMatchingInlineSnapshot(`"Syntax Error while parsing number node at position 1: Unexpected node number"`); (0, globals_1.expect)(() => (0, parse_1.parse)("(*3)")).toThrowErrorMatchingInlineSnapshot(`"Syntax Error while parsing enclosedExpression node at position 1: Invalid Enclosed expression"`); }); (0, globals_1.it)("should throw on invalid operator usage", () => { (0, globals_1.expect)(() => (0, parse_1.parse)("1+")).toThrowErrorMatchingInlineSnapshot(`"Syntax Error while parsing operator node at position 1: Unexpected node operator"`); (0, globals_1.expect)(() => (0, parse_1.parse)("1+()")).toThrowErrorMatchingInlineSnapshot(`"Syntax Error while parsing group node at position 3: Expected an argument list to be preceded by a reference, but got operator instead"`); }); (0, globals_1.it)("should remove spaces", () => { (0, globals_1.expect)((0, parse_1.parse)("1 + 2", { removeSpace: true })).toMatchObject({ type: "operation", members: [ { type: "number", value: "1", }, { type: "operator", value: "+", }, { type: "number", value: "2", }, ], }); }); (0, globals_1.it)("should keep spaces", () => { (0, globals_1.expect)((0, parse_1.parse)("1 + 2", { removeSpace: false })).toMatchObject({ type: "operation", members: [ { type: "number", value: "1", }, { type: "space", value: " ", start: 1, end: 2, }, { type: "operator", value: "+", }, { type: "space", value: " ", start: 3, end: 4, }, { type: "number", value: "2", }, ], left: { type: "number", value: "1", }, right: { type: "number", value: "2", }, operator: { type: "operator", value: "+", }, }); }); }); //# sourceMappingURL=parse.test.js.map