UNPKG

mozjexl

Version:

Javascript Expression Language: Powerful context-based expression parser and evaluator

193 lines (189 loc) 5.82 kB
/* * Jexl * Copyright (c) 2015 TechnologyAdvice */ var should = require('chai').should(), Lexer = require('../lib/Lexer'), grammar = require('../lib/grammar').elements; var inst; describe('Lexer', function() { beforeEach(function() { inst = new Lexer(grammar); }); describe('Elements', function() { it("should count a string as one element", function() { var str = '"foo"', elems = inst.getElements(str); elems.should.have.length(1); elems[0].should.equal(str); }); it("should support single-quote strings", function() { var str = "'foo'", elems = inst.getElements(str); elems.should.have.length(1); elems[0].should.equal(str); }); it("should support escaping double-quotes", function() { var str = '"f\\"oo"', elems = inst.getElements(str); elems.should.have.length(1); elems[0].should.equal(str); }); it("should support escaping single-quotes", function() { var str = "'f\\'oo'", elems = inst.getElements(str); elems.should.have.length(1); elems[0].should.equal(str); }); it("should count an identifier as one element", function() { var str = "alpha12345", elems = inst.getElements(str); elems.should.deep.equal([str]); }); it("should not split grammar elements out of transforms", function() { var str = "inString", elems = inst.getElements(str); elems.should.deep.equal([str]); }); }); describe('Tokens', function() { it("should unquote string elements", function() { var tokens = inst.getTokens(['"foo \\"bar\\\\"']); tokens.should.deep.equal([{ type: 'literal', value: 'foo "bar\\', raw: '"foo \\"bar\\\\"' }]); }); it("should recognize booleans", function() { var tokens = inst.getTokens(['true', 'false']); tokens.should.deep.equal([ { type: 'literal', value: true, raw: 'true' }, { type: 'literal', value: false, raw: 'false' } ]); }); it("should recognize numerics", function() { var tokens = inst.getTokens(['-7.6', '20']); tokens.should.deep.equal([ { type: 'literal', value: -7.6, raw: '-7.6' }, { type: 'literal', value: 20, raw: '20' } ]); }); it("should recognize binary operators", function() { var tokens = inst.getTokens(['+']); tokens.should.deep.equal([{ type: 'binaryOp', value: '+', raw: '+' }]); }); it("should recognize unary operators", function() { var tokens = inst.getTokens(['!']); tokens.should.deep.equal([{ type: 'unaryOp', value: '!', raw: '!' }]); }); it("should recognize control characters", function() { var tokens = inst.getTokens(['(']); tokens.should.deep.equal([{ type: 'openParen', value: '(', raw: '(' }]); }); it("should recognize identifiers", function() { var tokens = inst.getTokens(['_foo9_bar']); tokens.should.deep.equal([{ type: 'identifier', value: '_foo9_bar', raw: '_foo9_bar' }]); }); it("should throw on invalid token", function() { var fn = inst.getTokens.bind(Lexer, ['9foo']); fn.should.throw(); }); }); describe('Comments', function() { it("should handle a complex mix of octothrope comments in single, multiline and value contexts", function () { var expression = [ '6+x - -17.55*y #end comment', '<= !foo.bar["baz\\"foz"] # with space', '&& b=="not a #comment" # is a comment', "# comment # 2nd comment" ].join("\n"); var tokens = inst.tokenize(expression); var ans = [ { type: 'literal', value: 6, raw: '6' }, { type: 'binaryOp', value: '+', raw: '+' }, { type: 'identifier', value: 'x', raw: 'x ' }, { type: 'binaryOp', value: '-', raw: '- ' }, { type: 'literal', value: -17.55, raw: '-17.55' }, { type: 'binaryOp', value: '*', raw: '*' }, { type: 'identifier', value: 'y', raw: 'y ' }, { type: 'binaryOp', value: '<=', raw: '<= ' }, { type: 'unaryOp', value: '!', raw: '!' }, { type: 'identifier', value: 'foo', raw: 'foo' }, { type: 'dot', value: '.', raw: '.' }, { type: 'identifier', value: 'bar', raw: 'bar' }, { type: 'openBracket', value: '[', raw: '[' }, { type: 'literal', value: 'baz"foz', raw: '"baz\\"foz"' }, { type: 'closeBracket', value: ']', raw: '] ' }, { type: 'binaryOp', value: '&&', raw: '&& ' }, { type: 'identifier', value: 'b', raw: 'b' }, { type: 'binaryOp', value: '==', raw: '==' }, { type: 'literal', value: 'not a #comment', raw: '"not a #comment" ' } ]; tokens.should.deep.equal(ans); }); }); it("should tokenize a full expression", function() { var tokens = inst.tokenize('6+x - -17.55*y<= !foo.bar["baz\\"foz"]'); tokens.should.deep.equal([ {type: 'literal', value: 6, raw: '6'}, {type: 'binaryOp', value: '+', raw: '+'}, {type: 'identifier', value: 'x', raw: 'x '}, {type: 'binaryOp', value: '-', raw: '- '}, {type: 'literal', value: -17.55, raw: '-17.55'}, {type: 'binaryOp', value: '*', raw: '*'}, {type: 'identifier', value: 'y', raw: 'y'}, {type: 'binaryOp', value: '<=', raw: '<= '}, {type: 'unaryOp', value: '!', raw: '!'}, {type: 'identifier', value: 'foo', raw: 'foo'}, {type: 'dot', value: '.', raw: '.'}, {type: 'identifier', value: 'bar', raw: 'bar'}, {type: 'openBracket', value: '[', raw: '['}, {type: 'literal', value: 'baz"foz', raw: '"baz\\"foz"'}, {type: 'closeBracket', value: ']', raw: ']'} ]); }); it("should consider minus to be negative appropriately", function() { inst.tokenize('-1?-2:-3').should.deep.equal([ {type: 'literal', value: -1, raw: '-1'}, {type: 'question', value: '?', raw: '?'}, {type: 'literal', value: -2, raw: '-2'}, {type: 'colon', value: ':', raw: ':'}, {type: 'literal', value: -3, raw: '-3'} ]); }); });