From 07cc8c1c6fa803777fa669301b132b7ee121a06d Mon Sep 17 00:00:00 2001 From: Steve Larson <9larsons@gmail.com> Date: Thu, 17 Oct 2024 10:05:50 -0500 Subject: [PATCH] Added support for single character strings (#91) ref https://github.com/TryGhost/NQL/issues/20 I -believe- this works all right. It's at the end of the rules so it should allow for matching on just about anything else practical, then allow us a chance at matching a single character string, before throwing a Lexical Error. I've added negation for all special chars except for + and - as you ought to be able to do 'post:a+other' and 'post:a-something'. --- packages/nql-lang/dist/parser.js | 6 ++++-- packages/nql-lang/src/nql.l | 1 + packages/nql-lang/test/lexer.test.js | 14 +++++++++++--- packages/nql-lang/test/parser.test.js | 6 ++++++ 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/nql-lang/dist/parser.js b/packages/nql-lang/dist/parser.js index 3608b05a..6ab01a7f 100644 --- a/packages/nql-lang/dist/parser.js +++ b/packages/nql-lang/dist/parser.js @@ -743,10 +743,12 @@ case 25:return 35; break; case 26:return 33; break; +case 27:return 29; +break; } }, -rules: [/^(?:\s+)/,/^(?:(?:null|NULL|Null)(?!(\\(['"\+\,\(\)\>\<=\[\]\~\^\$])|([^\s'"\+\,\(\)\>\<=\[\]\~]))+))/,/^(?:(?:true|TRUE|True)(?!(\\(['"\+\,\(\)\>\<=\[\]\~\^\$])|([^\s'"\+\,\(\)\>\<=\[\]\~]))+))/,/^(?:(?:false|FALSE|False)(?!(\\(['"\+\,\(\)\>\<=\[\]\~\^\$])|([^\s'"\+\,\(\)\>\<=\[\]\~]))+))/,/^(?:[a-zA-Z_][a-zA-Z0-9_\.]*[:])/,/^(?:[0-9]+(\.[0-9]+)?\b(?![\-]))/,/^(?:\[)/,/^(?:\])/,/^(?:now(?=[-+]\d+[dwMyhms](?:([\+\,\(\)\[\]])|$)))/,/^(?:-)/,/^(?:\+)/,/^(?:\d+)/,/^(?:[dwMyhms])/,/^(?:([^\s'"\+\,\(\)\>\<=\[\]\~\-])(\\(['"\+\,\(\)\>\<=\[\]\~\^\$])|([^\s'"\+\,\(\)\>\<=\[\]\~]))+)/,/^(?:['](\\['"]|[^'"])+?['])/,/^(?:\()/,/^(?:\))/,/^(?:,)/,/^(?:\+)/,/^(?:-)/,/^(?:>=)/,/^(?:<=)/,/^(?:>)/,/^(?:<)/,/^(?:~\^)/,/^(?:~\$)/,/^(?:~)/], -conditions: {"reldate":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26],"inclusive":true},"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,13,14,15,16,17,18,19,20,21,22,23,24,25,26],"inclusive":true}} +rules: [/^(?:\s+)/,/^(?:(?:null|NULL|Null)(?!(\\(['"\+\,\(\)\>\<=\[\]\~\^\$])|([^\s'"\+\,\(\)\>\<=\[\]\~]))+))/,/^(?:(?:true|TRUE|True)(?!(\\(['"\+\,\(\)\>\<=\[\]\~\^\$])|([^\s'"\+\,\(\)\>\<=\[\]\~]))+))/,/^(?:(?:false|FALSE|False)(?!(\\(['"\+\,\(\)\>\<=\[\]\~\^\$])|([^\s'"\+\,\(\)\>\<=\[\]\~]))+))/,/^(?:[a-zA-Z_][a-zA-Z0-9_\.]*[:])/,/^(?:[0-9]+(\.[0-9]+)?\b(?![\-]))/,/^(?:\[)/,/^(?:\])/,/^(?:now(?=[-+]\d+[dwMyhms](?:([\+\,\(\)\[\]])|$)))/,/^(?:-)/,/^(?:\+)/,/^(?:\d+)/,/^(?:[dwMyhms])/,/^(?:([^\s'"\+\,\(\)\>\<=\[\]\~\-])(\\(['"\+\,\(\)\>\<=\[\]\~\^\$])|([^\s'"\+\,\(\)\>\<=\[\]\~]))+)/,/^(?:['](\\['"]|[^'"])+?['])/,/^(?:\()/,/^(?:\))/,/^(?:,)/,/^(?:\+)/,/^(?:-)/,/^(?:>=)/,/^(?:<=)/,/^(?:>)/,/^(?:<)/,/^(?:~\^)/,/^(?:~\$)/,/^(?:~)/,/^(?:([a-zA-Z])(?![a-zA-Z'"\,\(\)\>\<=\[\]\~]))/], +conditions: {"reldate":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27],"inclusive":true},"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27],"inclusive":true}} }); lexer.parseError = function(errStr, object) { var lines = errStr.split("\n"), diff --git a/packages/nql-lang/src/nql.l b/packages/nql-lang/src/nql.l index f8602b5d..0833c6ac 100644 --- a/packages/nql-lang/src/nql.l +++ b/packages/nql-lang/src/nql.l @@ -43,6 +43,7 @@ now(?=[-+]\d+[dwMyhms](?:{final}|$)) { this.pushState('re '~^' return 'STARTSWITH'; '~$' return 'ENDSWITH'; '~' return 'CONTAINS'; +([a-zA-Z])(?![a-zA-Z'"\,\(\)\>\<=\[\]\~]) return 'LITERAL'; %% diff --git a/packages/nql-lang/test/lexer.test.js b/packages/nql-lang/test/lexer.test.js index 74d8b88b..9b694f06 100644 --- a/packages/nql-lang/test/lexer.test.js +++ b/packages/nql-lang/test/lexer.test.js @@ -165,6 +165,17 @@ describe('Lexer', function () { (function () { lex('my&valu\'e!'); }).should.throw(lexicalError); + lex('a').should.eql([ + {token: 'LITERAL', matched: 'a'} + ]); + lex('a-b').should.eql([ + {token: 'LITERAL', matched: 'a-b'} + ]); + lex('a+bc').should.eql([ + {token: 'LITERAL', matched: 'a'}, + {token: 'AND', matched: '+'}, + {token: 'LITERAL', matched: 'bc'} + ]); }); it('should separate NOT at beginning of literal', function () { @@ -180,9 +191,6 @@ describe('Lexer', function () { }); it('should NOT permit special chars inside a literal', function () { - (function () { - lex('t+st'); - }).should.throw(lexicalError); (function () { lex('t,st'); }).should.throw(lexicalError); diff --git a/packages/nql-lang/test/parser.test.js b/packages/nql-lang/test/parser.test.js index 92e15c82..616e2991 100644 --- a/packages/nql-lang/test/parser.test.js +++ b/packages/nql-lang/test/parser.test.js @@ -627,5 +627,11 @@ describe('Parser', function () { sinon.assert.calledTwice(relDateToAbsoluteSpy); }); }); + + describe('Single character literals', function () { + it('can handle single character literals', function () { + parse('name:a').should.eql({name: 'a'}); + }); + }); }); });