You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@filtron/core

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@filtron/core - npm Package Compare versions

Comparing version
1.3.2
to
1.4.0
+27
examples/ast-inspection.ts
// Traversing the AST to extract all field names used in a query.
// Run with: bun run examples/ast-inspection.ts
import { parseOrThrow, type ASTNode } from "../src/index";
function collectFields(node: ASTNode): string[] {
switch (node.type) {
case "or":
case "and":
return [...collectFields(node.left), ...collectFields(node.right)];
case "not":
return collectFields(node.expression);
case "comparison":
case "oneOf":
case "notOneOf":
case "exists":
case "booleanField":
case "range":
return [node.field];
}
}
const ast = parseOrThrow('(role = "admin" OR role = "user") AND verified AND age >= 21');
const fields = [...new Set(collectFields(ast))];
console.log("Fields:", fields);
// Output: Fields: [ "role", "verified", "age" ]
// Handling parse errors with both parse() and parseOrThrow().
// Run with: bun run examples/error-handling.ts
import { parse, parseOrThrow, FiltronParseError } from "../src/index";
// Using parse() - returns a result object with success/error
const result = parse("invalid === query");
if (!result.success) {
console.log("Parse failed:", result.error);
if (result.position !== undefined) {
console.log("Error position:", result.position);
}
}
// Using parseOrThrow() - throws FiltronParseError on failure
try {
parseOrThrow("another bad >> query");
} catch (error) {
if (error instanceof FiltronParseError) {
console.log("Caught FiltronParseError:", error.message);
if (error.position !== undefined) {
console.log("Error position:", error.position);
}
}
}
// Overview of Filtron query syntax and supported operators.
// Run with: bun run examples/query-syntax.ts
import { parseOrThrow } from "../src/index";
// Comparison operators: =, !=, >, >=, <, <=
parseOrThrow('status = "active"');
parseOrThrow("age >= 18");
parseOrThrow("price < 100");
// Contains operator (~) for substring matching
parseOrThrow('name ~ "john"');
// Boolean field shorthand (field is truthy)
parseOrThrow("verified");
parseOrThrow("premium AND verified");
// Field existence check (?)
parseOrThrow("email?");
// One-of operator (:) for matching against a list
parseOrThrow('role : ["admin", "moderator", "user"]');
// Not-one-of operator (!:)
parseOrThrow('status !: ["deleted", "banned"]');
// Range syntax for numeric ranges (inclusive)
parseOrThrow("age = 18..65");
// Logical operators: AND, OR, NOT
parseOrThrow('active AND role = "admin"');
parseOrThrow('role = "admin" OR role = "moderator"');
parseOrThrow("NOT suspended");
// Parentheses for grouping
parseOrThrow('(role = "admin" OR role = "moderator") AND active');
// Dotted field names for nested access
parseOrThrow("user.profile.age >= 18");
console.log("All syntax examples parsed successfully");
// Minimal example of parsing a Filtron query.
// Run with: bun run examples/simple.ts
import { parse } from "../src/index";
const result = parse('status = "active" AND age >= 18');
if (result.success) {
console.log(result.ast);
} else {
console.error(result.error);
}
{
"name": "Filtron",
"scopeName": "source.filtron",
"patterns": [
{
"include": "#keywords"
},
{
"include": "#operators"
},
{
"include": "#strings"
},
{
"include": "#numbers"
},
{
"include": "#fields"
},
{
"include": "#brackets"
}
],
"repository": {
"keywords": {
"match": "\\b(AND|OR|NOT|EXISTS|TRUE|FALSE)\\b",
"name": "keyword.control.filtron"
},
"operators": {
"match": "(>=|<=|!=|!:|:|=|>|<|~|\\?|\\.\\.)",
"name": "keyword.operator.filtron"
},
"strings": {
"begin": "\"",
"end": "\"",
"name": "string.quoted.double.filtron",
"patterns": [
{
"match": "\\\\.",
"name": "constant.character.escape.filtron"
}
]
},
"numbers": {
"match": "-?\\d+(\\.\\d+)?",
"name": "constant.numeric.filtron"
},
"fields": {
"match": "[a-zA-Z_][a-zA-Z0-9_.]*",
"name": "variable.other.filtron"
},
"brackets": {
"match": "[\\[\\]\\(\\)]",
"name": "punctuation.bracket.filtron"
}
}
}
+3
-3

@@ -1,5 +0,5 @@

var A={Tab:9,Newline:10,CarriageReturn:13,Space:32,Bang:33,Quote:34,LParen:40,RParen:41,Comma:44,Minus:45,Dot:46,Slash:47,Zero:48,Nine:57,Colon:58,LessThan:60,Equals:61,GreaterThan:62,Question:63,UpperA:65,UpperZ:90,LBracket:91,Backslash:92,RBracket:93,Underscore:95,LowerA:97,LowerN:110,LowerR:114,LowerT:116,LowerZ:122,Tilde:126};class z extends Error{position;constructor(V,B){super(V);this.position=B;this.name="LexerError"}}class G{pos=0;input;length;constructor(V){this.input=V,this.length=V.length}readString(){let V=this.input,B=this.length,O=this.pos,N=this.pos+1,R=!1,M=N;while(N<B){let b=V.charCodeAt(N);if(b===A.Quote)return this.pos=N+1,{type:"STRING",value:V.slice(M,N),start:O,end:this.pos};if(b===A.Backslash){R=!0;break}N++}if(R){N=M;let b="",D=N;while(N<B){let F=V.charCodeAt(N);if(F===A.Quote)return b+=V.slice(D,N),this.pos=N+1,{type:"STRING",value:b,start:O,end:this.pos};if(F===A.Backslash){b+=V.slice(D,N),N++;let H=V.charCodeAt(N);switch(N++,H){case A.LowerN:b+=`
`;break;case A.LowerT:b+="\t";break;case A.LowerR:b+="\r";break;case A.Backslash:b+="\\";break;case A.Quote:b+='"';break;default:b+=String.fromCharCode(H)}D=N;continue}N++}}throw new z("Unterminated string literal",O)}readNumber(){let V=this.input,B=this.length,O=this.pos,N=this.pos;if(V.charCodeAt(N)===A.Minus)N++;while(N<B){let R=V.charCodeAt(N);if(R<A.Zero||R>A.Nine)break;N++}if(N<B&&V.charCodeAt(N)===A.Dot&&N+1<B){let R=V.charCodeAt(N+1);if(R>=A.Zero&&R<=A.Nine){N++;while(N<B){let M=V.charCodeAt(N);if(M<A.Zero||M>A.Nine)break;N++}return this.pos=N,{type:"NUMBER",value:parseFloat(V.slice(O,N)),start:O,end:N}}}return this.pos=N,{type:"NUMBER",value:parseInt(V.slice(O,N),10),start:O,end:N}}readIdentifier(){let V=this.input,B=this.length,O=this.pos,N=this.pos;while(N<B){let M=V.charCodeAt(N);if(M>=A.LowerA&&M<=A.LowerZ||M>=A.UpperA&&M<=A.UpperZ||M>=A.Zero&&M<=A.Nine||M===A.Underscore)N++;else break}this.pos=N;let R=N-O;if(R>=2&&R<=6){let M=V.charCodeAt(O)|32;if(R===2){if(M===111&&(V.charCodeAt(O+1)|32)===114)return{type:"OR",value:"or",start:O,end:N}}else if(R===3){if(M===97){if((V.charCodeAt(O+1)|32)===110&&(V.charCodeAt(O+2)|32)===100)return{type:"AND",value:"and",start:O,end:N}}else if(M===110){if((V.charCodeAt(O+1)|32)===111&&(V.charCodeAt(O+2)|32)===116)return{type:"NOT",value:"not",start:O,end:N}}}else if(R===4){if(M===116){if((V.charCodeAt(O+1)|32)===114&&(V.charCodeAt(O+2)|32)===117&&(V.charCodeAt(O+3)|32)===101)return{type:"TRUE",value:!0,start:O,end:N}}}else if(R===5){if(M===102){if((V.charCodeAt(O+1)|32)===97&&(V.charCodeAt(O+2)|32)===108&&(V.charCodeAt(O+3)|32)===115&&(V.charCodeAt(O+4)|32)===101)return{type:"FALSE",value:!1,start:O,end:N}}}else if(R===6){if(M===101){if((V.charCodeAt(O+1)|32)===120&&(V.charCodeAt(O+2)|32)===105&&(V.charCodeAt(O+3)|32)===115&&(V.charCodeAt(O+4)|32)===116&&(V.charCodeAt(O+5)|32)===115)return{type:"EXISTS",value:"exists",start:O,end:N}}}}return{type:"IDENT",value:V.slice(O,N),start:O,end:N}}next(){let V=this.input,B=this.length,O=this.pos;while(O<B){let M=V.charCodeAt(O);if(M===A.Space||M===A.Tab||M===A.Newline||M===A.CarriageReturn){O++;continue}if(M===A.Slash&&O+1<B&&V.charCodeAt(O+1)===A.Slash){O+=2;while(O<B&&V.charCodeAt(O)!==A.Newline)O++;continue}break}if(this.pos=O,O>=this.length)return{type:"EOF",value:"",start:O,end:O};let N=V.charCodeAt(O);switch(N){case A.LParen:return this.pos=O+1,{type:"LPAREN",value:"(",start:O,end:O+1};case A.RParen:return this.pos=O+1,{type:"RPAREN",value:")",start:O,end:O+1};case A.LBracket:return this.pos=O+1,{type:"LBRACKET",value:"[",start:O,end:O+1};case A.RBracket:return this.pos=O+1,{type:"RBRACKET",value:"]",start:O,end:O+1};case A.Comma:return this.pos=O+1,{type:"COMMA",value:",",start:O,end:O+1};case A.Question:return this.pos=O+1,{type:"QUESTION",value:"?",start:O,end:O+1};case A.Equals:return this.pos=O+1,{type:"EQ",value:"=",start:O,end:O+1};case A.Tilde:return this.pos=O+1,{type:"LIKE",value:"~",start:O,end:O+1};case A.Colon:return this.pos=O+1,{type:"COLON",value:":",start:O,end:O+1}}let R=O+1<this.length?V.charCodeAt(O+1):0;if(N===A.Bang){if(R===A.Equals)return this.pos=O+2,{type:"NEQ",value:"!=",start:O,end:O+2};if(R===A.Colon)return this.pos=O+2,{type:"NOT_COLON",value:"!:",start:O,end:O+2}}if(N===A.GreaterThan){if(R===A.Equals)return this.pos=O+2,{type:"GTE",value:">=",start:O,end:O+2};return this.pos=O+1,{type:"GT",value:">",start:O,end:O+1}}if(N===A.LessThan){if(R===A.Equals)return this.pos=O+2,{type:"LTE",value:"<=",start:O,end:O+2};return this.pos=O+1,{type:"LT",value:"<",start:O,end:O+1}}if(N===A.Dot){if(R===A.Dot)return this.pos=O+2,{type:"DOTDOT",value:"..",start:O,end:O+2};return this.pos=O+1,{type:"DOT",value:".",start:O,end:O+1}}if(N===A.Quote)return this.readString();if(N>=A.Zero&&N<=A.Nine)return this.readNumber();if(N===A.Minus&&R>=A.Zero&&R<=A.Nine)return this.readNumber();if(N>=A.LowerA&&N<=A.LowerZ||N>=A.UpperA&&N<=A.UpperZ||N===A.Underscore)return this.readIdentifier();throw new z(`Unexpected character: '${V[O]}'`,O)}}class j extends Error{position;constructor(V,B){super(V);this.position=B;this.name="ParseError"}}class I{lexer;current;nextToken=null;constructor(V){this.lexer=new G(V),this.current=this.lexer.next()}advance(){let V=this.current;if(this.nextToken)this.current=this.nextToken,this.nextToken=null;else this.current=this.lexer.next();return V}check(V){return this.current.type===V}expect(V,B){if(this.current.type!==V){let O=B??`Expected ${V}, got ${this.current.type}`;throw new j(O,this.current.start)}return this.advance()}parse(){if(this.check("EOF"))throw new j("Empty query",0);let V=this.parseOrExpression();if(!this.check("EOF"))throw new j(`Unexpected token: ${this.current.type}`,this.current.start);return V}parseOrExpression(){let V=this.parseAndExpression();while(this.check("OR")){this.advance();let B=this.parseAndExpression();V={type:"or",left:V,right:B}}return V}parseAndExpression(){let V=this.parseNotExpression();while(this.check("AND")){this.advance();let B=this.parseNotExpression();V={type:"and",left:V,right:B}}return V}parseNotExpression(){if(this.check("NOT"))return this.advance(),{type:"not",expression:this.parseNotExpression()};return this.parsePrimaryExpression()}parsePrimaryExpression(){if(this.check("LPAREN")){this.advance();let V=this.parseOrExpression();return this.expect("RPAREN","Expected closing parenthesis"),V}return this.parseFieldExpression()}parseFieldExpression(){let V=this.parseFieldName(),B=this.current.type;if(B==="QUESTION"||B==="EXISTS")return this.advance(),{type:"exists",field:V};if(B==="COLON"&&this.peekNextIsLBracket())return this.advance(),this.parseOneOfArray(V,"oneOf");if(B==="NOT_COLON")return this.advance(),this.parseOneOfArray(V,"notOneOf");if(B==="EQ"||B==="NEQ"||B==="GT"||B==="GTE"||B==="LT"||B==="LTE"||B==="LIKE"||B==="COLON"){let O=this.advance(),N=this.tokenToOperator(O);if(N==="="&&this.check("NUMBER")){let b=this.advance().value;if(this.check("DOTDOT")){this.advance();let F=this.expect("NUMBER","Expected number after '..'").value;return{type:"range",field:V,min:b,max:F}}return{type:"comparison",field:V,operator:N,value:{type:"number",value:b}}}let R=this.parseValue();return{type:"comparison",field:V,operator:N,value:R}}return{type:"booleanField",field:V}}peekNextIsLBracket(){if(!this.nextToken)this.nextToken=this.lexer.next();return this.nextToken.type==="LBRACKET"}tokenToOperator(V){switch(V.type){case"EQ":return"=";case"NEQ":return"!=";case"GT":return">";case"GTE":return">=";case"LT":return"<";case"LTE":return"<=";case"LIKE":return"~";case"COLON":return":";default:throw new j(`Invalid operator: ${V.type}`,V.start)}}parseFieldName(){let B=this.expect("IDENT","Expected field name").value;while(this.check("DOT")){this.advance();let O=this.expect("IDENT","Expected identifier after '.'");B+="."+O.value}return B}parseOneOfArray(V,B){this.expect("LBRACKET","Expected '[' after operator");let O=[];if(!this.check("RBRACKET")){O.push(this.parseValue());while(this.check("COMMA"))this.advance(),O.push(this.parseValue())}if(this.expect("RBRACKET","Expected ']' to close array"),O.length===0)throw new j("Array cannot be empty",this.current.start);return{type:B,field:V,values:O}}parseValue(){let V=this.current.type;if(V==="STRING")return{type:"string",value:this.advance().value};if(V==="NUMBER")return{type:"number",value:this.advance().value};if(V==="TRUE")return this.advance(),{type:"boolean",value:!0};if(V==="FALSE")return this.advance(),{type:"boolean",value:!1};if(V==="IDENT"){let O=this.advance().value;while(this.current.type==="DOT"){this.advance();let N=this.expect("IDENT","Expected identifier after '.'");O+="."+N.value}return{type:"identifier",value:O}}throw new j(`Expected value, got ${V}`,this.current.start)}}function J(V){return new I(V).parse()}var K=(V)=>{try{return{success:!0,ast:J(V)}}catch(B){let O;if(B instanceof j||B instanceof z)O=B.message;else if(B instanceof Error)O=B.message;else O=String(B);return{success:!1,error:O,message:O}}},W=(V)=>{let B=K(V);if(B.success)return B.ast;throw Error(`Failed to parse Filtron query: ${B.error}`)};export{W as parseOrThrow,K as parse};
var V={Tab:9,Newline:10,CarriageReturn:13,Space:32,Bang:33,Quote:34,LParen:40,RParen:41,Comma:44,Minus:45,Dot:46,Slash:47,Zero:48,Nine:57,Colon:58,LessThan:60,Equals:61,GreaterThan:62,Question:63,UpperA:65,UpperZ:90,LBracket:91,Backslash:92,RBracket:93,Underscore:95,LowerA:97,LowerN:110,LowerR:114,LowerT:116,LowerZ:122,Tilde:126};class G extends Error{position;constructor(N,A){super(N);this.position=A;this.name="LexerError"}}class I{pos=0;input;length;constructor(N){this.input=N,this.length=N.length}readString(){let N=this.input,A=this.length,O=this.pos,B=this.pos+1,M=!1,b=B;while(B<A){let R=N.charCodeAt(B);if(R===V.Quote)return this.pos=B+1,{type:"STRING",value:N.slice(b,B),start:O,end:this.pos};if(R===V.Backslash){M=!0;break}B++}if(M){B=b;let R="",z=B;while(B<A){let D=N.charCodeAt(B);if(D===V.Quote)return R+=N.slice(z,B),this.pos=B+1,{type:"STRING",value:R,start:O,end:this.pos};if(D===V.Backslash){R+=N.slice(z,B),B++;let H=N.charCodeAt(B);switch(B++,H){case V.LowerN:R+=`
`;break;case V.LowerT:R+="\t";break;case V.LowerR:R+="\r";break;case V.Backslash:R+="\\";break;case V.Quote:R+='"';break;default:R+=String.fromCharCode(H)}z=B;continue}B++}}throw new G("Unterminated string literal",O)}readNumber(){let N=this.input,A=this.length,O=this.pos,B=this.pos,M=!1;if(N.charCodeAt(B)===V.Minus)M=!0,B++;let b=0;while(B<A){let R=N.charCodeAt(B);if(R<V.Zero||R>V.Nine)break;b=b*10+(R-V.Zero),B++}if(B<A&&N.charCodeAt(B)===V.Dot&&B+1<A){let R=N.charCodeAt(B+1);if(R>=V.Zero&&R<=V.Nine){B++;let z=0,D=1;while(B<A){let J=N.charCodeAt(B);if(J<V.Zero||J>V.Nine)break;z=z*10+(J-V.Zero),D*=10,B++}this.pos=B;let H=b+z/D;return{type:"NUMBER",value:M?-H:H,start:O,end:B}}}return this.pos=B,{type:"NUMBER",value:M?-b:b,start:O,end:B}}readIdentifier(){let N=this.input,A=this.length,O=this.pos,B=this.pos;while(B<A){let b=N.charCodeAt(B);if(b>=V.LowerA&&b<=V.LowerZ||b>=V.UpperA&&b<=V.UpperZ||b>=V.Zero&&b<=V.Nine||b===V.Underscore)B++;else break}this.pos=B;let M=B-O;if(M>=2&&M<=6){let b=N.charCodeAt(O)|32;if(M===2){if(b===111&&(N.charCodeAt(O+1)|32)===114)return{type:"OR",value:"or",start:O,end:B}}else if(M===3){if(b===97){if((N.charCodeAt(O+1)|32)===110&&(N.charCodeAt(O+2)|32)===100)return{type:"AND",value:"and",start:O,end:B}}else if(b===110){if((N.charCodeAt(O+1)|32)===111&&(N.charCodeAt(O+2)|32)===116)return{type:"NOT",value:"not",start:O,end:B}}}else if(M===4){if(b===116){if((N.charCodeAt(O+1)|32)===114&&(N.charCodeAt(O+2)|32)===117&&(N.charCodeAt(O+3)|32)===101)return{type:"TRUE",value:!0,start:O,end:B}}}else if(M===5){if(b===102){if((N.charCodeAt(O+1)|32)===97&&(N.charCodeAt(O+2)|32)===108&&(N.charCodeAt(O+3)|32)===115&&(N.charCodeAt(O+4)|32)===101)return{type:"FALSE",value:!1,start:O,end:B}}}else if(M===6){if(b===101){if((N.charCodeAt(O+1)|32)===120&&(N.charCodeAt(O+2)|32)===105&&(N.charCodeAt(O+3)|32)===115&&(N.charCodeAt(O+4)|32)===116&&(N.charCodeAt(O+5)|32)===115)return{type:"EXISTS",value:"exists",start:O,end:B}}}}return{type:"IDENT",value:N.slice(O,B),start:O,end:B}}next(){let N=this.input,A=this.length,O=this.pos;while(O<A){let b=N.charCodeAt(O);if(b===V.Space||b===V.Tab||b===V.Newline||b===V.CarriageReturn){O++;continue}if(b===V.Slash&&O+1<A&&N.charCodeAt(O+1)===V.Slash){O+=2;while(O<A&&N.charCodeAt(O)!==V.Newline)O++;continue}break}if(this.pos=O,O>=this.length)return{type:"EOF",value:"",start:O,end:O};let B=N.charCodeAt(O);switch(B){case V.LParen:return this.pos=O+1,{type:"LPAREN",value:"(",start:O,end:O+1};case V.RParen:return this.pos=O+1,{type:"RPAREN",value:")",start:O,end:O+1};case V.LBracket:return this.pos=O+1,{type:"LBRACKET",value:"[",start:O,end:O+1};case V.RBracket:return this.pos=O+1,{type:"RBRACKET",value:"]",start:O,end:O+1};case V.Comma:return this.pos=O+1,{type:"COMMA",value:",",start:O,end:O+1};case V.Question:return this.pos=O+1,{type:"QUESTION",value:"?",start:O,end:O+1};case V.Equals:return this.pos=O+1,{type:"EQ",value:"=",start:O,end:O+1};case V.Tilde:return this.pos=O+1,{type:"LIKE",value:"~",start:O,end:O+1};case V.Colon:return this.pos=O+1,{type:"COLON",value:":",start:O,end:O+1}}let M=O+1<this.length?N.charCodeAt(O+1):0;if(B===V.Bang){if(M===V.Equals)return this.pos=O+2,{type:"NEQ",value:"!=",start:O,end:O+2};if(M===V.Colon)return this.pos=O+2,{type:"NOT_COLON",value:"!:",start:O,end:O+2}}if(B===V.GreaterThan){if(M===V.Equals)return this.pos=O+2,{type:"GTE",value:">=",start:O,end:O+2};return this.pos=O+1,{type:"GT",value:">",start:O,end:O+1}}if(B===V.LessThan){if(M===V.Equals)return this.pos=O+2,{type:"LTE",value:"<=",start:O,end:O+2};return this.pos=O+1,{type:"LT",value:"<",start:O,end:O+1}}if(B===V.Dot){if(M===V.Dot)return this.pos=O+2,{type:"DOTDOT",value:"..",start:O,end:O+2};return this.pos=O+1,{type:"DOT",value:".",start:O,end:O+1}}if(B===V.Quote)return this.readString();if(B>=V.Zero&&B<=V.Nine)return this.readNumber();if(B===V.Minus&&M>=V.Zero&&M<=V.Nine)return this.readNumber();if(B>=V.LowerA&&B<=V.LowerZ||B>=V.UpperA&&B<=V.UpperZ||B===V.Underscore)return this.readIdentifier();throw new G(`Unexpected character: '${N[O]}'`,O)}}class j extends Error{position;constructor(N,A){super(N);this.position=A;this.name="ParseError"}}class W{lexer;current;nextToken=null;constructor(N){this.lexer=new I(N),this.current=this.lexer.next()}advance(){let N=this.current;if(this.nextToken)this.current=this.nextToken,this.nextToken=null;else this.current=this.lexer.next();return N}check(N){return this.current.type===N}expect(N,A){if(this.current.type!==N){let O=A??`Expected ${N}, got ${this.current.type}`;throw new j(O,this.current.start)}return this.advance()}parse(){if(this.check("EOF"))throw new j("Empty query",0);let N=this.parseOrExpression();if(!this.check("EOF"))throw new j(`Unexpected token: ${this.current.type}`,this.current.start);return N}parseOrExpression(){let N=this.parseAndExpression();while(this.check("OR")){this.advance();let A=this.parseAndExpression();N={type:"or",left:N,right:A}}return N}parseAndExpression(){let N=this.parseNotExpression();while(this.check("AND")){this.advance();let A=this.parseNotExpression();N={type:"and",left:N,right:A}}return N}parseNotExpression(){if(this.check("NOT"))return this.advance(),{type:"not",expression:this.parseNotExpression()};return this.parsePrimaryExpression()}parsePrimaryExpression(){if(this.check("LPAREN")){this.advance();let N=this.parseOrExpression();return this.expect("RPAREN","Expected closing parenthesis"),N}return this.parseFieldExpression()}parseFieldExpression(){let N=this.parseFieldName(),A=this.current.type;if(A==="QUESTION"||A==="EXISTS")return this.advance(),{type:"exists",field:N};if(A==="COLON"&&this.peekNextIsLBracket())return this.advance(),this.parseOneOfArray(N,"oneOf");if(A==="NOT_COLON")return this.advance(),this.parseOneOfArray(N,"notOneOf");if(A==="EQ"||A==="NEQ"||A==="GT"||A==="GTE"||A==="LT"||A==="LTE"||A==="LIKE"||A==="COLON"){let O=this.advance(),B=this.tokenToOperator(O);if(B==="="&&this.check("NUMBER")){let R=this.advance().value;if(this.check("DOTDOT")){this.advance();let D=this.expect("NUMBER","Expected number after '..'").value;return{type:"range",field:N,min:R,max:D}}return{type:"comparison",field:N,operator:B,value:{type:"number",value:R}}}let M=this.parseValue();return{type:"comparison",field:N,operator:B,value:M}}return{type:"booleanField",field:N}}peekNextIsLBracket(){if(!this.nextToken)this.nextToken=this.lexer.next();return this.nextToken.type==="LBRACKET"}tokenToOperator(N){switch(N.type){case"EQ":return"=";case"NEQ":return"!=";case"GT":return">";case"GTE":return">=";case"LT":return"<";case"LTE":return"<=";case"LIKE":return"~";case"COLON":return":";default:throw new j(`Invalid operator: ${N.type}`,N.start)}}parseFieldName(){let A=this.expect("IDENT","Expected field name").value;while(this.check("DOT")){this.advance();let O=this.expect("IDENT","Expected identifier after '.'");A+="."+O.value}return A}parseOneOfArray(N,A){this.expect("LBRACKET","Expected '[' after operator");let O=[];if(!this.check("RBRACKET")){O.push(this.parseValue());while(this.check("COMMA"))this.advance(),O.push(this.parseValue())}if(this.expect("RBRACKET","Expected ']' to close array"),O.length===0)throw new j("Array cannot be empty",this.current.start);return{type:A,field:N,values:O}}parseValue(){let N=this.current.type;if(N==="STRING")return{type:"string",value:this.advance().value};if(N==="NUMBER")return{type:"number",value:this.advance().value};if(N==="TRUE")return this.advance(),{type:"boolean",value:!0};if(N==="FALSE")return this.advance(),{type:"boolean",value:!1};if(N==="IDENT"){let O=this.advance().value;while(this.current.type==="DOT"){this.advance();let B=this.expect("IDENT","Expected identifier after '.'");O+="."+B.value}return{type:"identifier",value:O}}throw new j(`Expected value, got ${N}`,this.current.start)}}function X(N){return new W(N).parse()}class K extends Error{position;constructor(N,A){super(N);this.position=A;this.name="FiltronParseError"}}var Y=(N)=>{try{return{success:!0,ast:X(N)}}catch(A){let O,B;if(A instanceof j||A instanceof G)O=A.message,B=A.position;else if(A instanceof Error)O=A.message;else O=String(A);return{success:!1,error:O,message:O,position:B}}},Z=(N)=>{let A=Y(N);if(A.success)return A.ast;throw new K(`Failed to parse Filtron query: ${A.error}`,A.position)};export{Z as parseOrThrow,Y as parse,G as LexerError,I as Lexer,K as FiltronParseError};
//# debugId=839D03E8D259923E64756E2164756E21
//# debugId=55F7033D8A7F4FE964756E2164756E21
//# sourceMappingURL=index.js.map

@@ -5,9 +5,9 @@ {

"sourcesContent": [
"/**\n * A Lexer for the Filtron query language\n */\n\n/**\n * Token types produced by the lexer\n */\nexport type TokenType =\n\t| \"LPAREN\"\n\t| \"RPAREN\"\n\t| \"LBRACKET\"\n\t| \"RBRACKET\"\n\t| \"COMMA\"\n\t| \"QUESTION\"\n\t| \"DOT\"\n\t| \"DOTDOT\"\n\t| \"AND\"\n\t| \"OR\"\n\t| \"NOT\"\n\t| \"EXISTS\"\n\t| \"TRUE\"\n\t| \"FALSE\"\n\t| \"EQ\"\n\t| \"NEQ\"\n\t| \"GT\"\n\t| \"GTE\"\n\t| \"LT\"\n\t| \"LTE\"\n\t| \"LIKE\"\n\t| \"COLON\"\n\t| \"NOT_COLON\"\n\t| \"STRING\"\n\t| \"NUMBER\"\n\t| \"IDENT\"\n\t| \"EOF\";\n\n/** Base token properties */\ninterface TokenBase {\n\tstart: number;\n\tend: number;\n}\n\n/** Tokens with string values (punctuation, operators, keywords, identifiers) */\nexport interface StringToken extends TokenBase {\n\ttype:\n\t\t| \"LPAREN\"\n\t\t| \"RPAREN\"\n\t\t| \"LBRACKET\"\n\t\t| \"RBRACKET\"\n\t\t| \"COMMA\"\n\t\t| \"QUESTION\"\n\t\t| \"DOT\"\n\t\t| \"DOTDOT\"\n\t\t| \"AND\"\n\t\t| \"OR\"\n\t\t| \"NOT\"\n\t\t| \"EXISTS\"\n\t\t| \"EQ\"\n\t\t| \"NEQ\"\n\t\t| \"GT\"\n\t\t| \"GTE\"\n\t\t| \"LT\"\n\t\t| \"LTE\"\n\t\t| \"LIKE\"\n\t\t| \"COLON\"\n\t\t| \"NOT_COLON\"\n\t\t| \"STRING\"\n\t\t| \"IDENT\"\n\t\t| \"EOF\";\n\tvalue: string;\n}\n\n/** Tokens with number values */\nexport interface NumberToken extends TokenBase {\n\ttype: \"NUMBER\";\n\tvalue: number;\n}\n\n/** Tokens with boolean values */\nexport interface BooleanToken extends TokenBase {\n\ttype: \"TRUE\" | \"FALSE\";\n\tvalue: boolean;\n}\n\n/**\n * Discriminated union of all token types for proper type narrowing\n */\nexport type Token = StringToken | NumberToken | BooleanToken;\n\n// Character codes\nconst C = {\n\tTab: 9,\n\tNewline: 10,\n\tCarriageReturn: 13,\n\tSpace: 32,\n\tBang: 33,\n\tQuote: 34,\n\tLParen: 40,\n\tRParen: 41,\n\tComma: 44,\n\tMinus: 45,\n\tDot: 46,\n\tSlash: 47,\n\tZero: 48,\n\tNine: 57,\n\tColon: 58,\n\tLessThan: 60,\n\tEquals: 61,\n\tGreaterThan: 62,\n\tQuestion: 63,\n\tUpperA: 65,\n\tUpperZ: 90,\n\tLBracket: 91,\n\tBackslash: 92,\n\tRBracket: 93,\n\tUnderscore: 95,\n\tLowerA: 97,\n\tLowerN: 110,\n\tLowerR: 114,\n\tLowerT: 116,\n\tLowerZ: 122,\n\tTilde: 126,\n} as const;\n\n/**\n * Lexer error with position information\n */\nexport class LexerError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic position: number,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"LexerError\";\n\t}\n}\n\n/**\n * Lexer for tokenizing Filtron query strings\n */\nexport class Lexer {\n\tprivate pos = 0;\n\tprivate readonly input: string;\n\tprivate readonly length: number;\n\n\tconstructor(input: string) {\n\t\tthis.input = input;\n\t\tthis.length = input.length;\n\t}\n\n\t/**\n\t * Read a string literal - fast path for no escapes\n\t */\n\tprivate readString(): Token {\n\t\tconst input = this.input;\n\t\tconst length = this.length;\n\t\tconst start = this.pos;\n\t\tlet pos = this.pos + 1; // skip opening quote\n\n\t\t// Fast path: scan for closing quote or backslash\n\t\tlet hasEscape = false;\n\t\tconst scanStart = pos;\n\t\twhile (pos < length) {\n\t\t\tconst code = input.charCodeAt(pos);\n\t\t\tif (code === C.Quote) {\n\t\t\t\t// No escapes - just slice\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"STRING\",\n\t\t\t\t\tvalue: input.slice(scanStart, pos),\n\t\t\t\t\tstart,\n\t\t\t\t\tend: this.pos,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (code === C.Backslash) {\n\t\t\t\thasEscape = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tpos++;\n\t\t}\n\n\t\t// Slow path: handle escapes\n\t\tif (hasEscape) {\n\t\t\tpos = scanStart;\n\t\t\tlet result = \"\";\n\t\t\tlet chunkStart = pos;\n\n\t\t\twhile (pos < length) {\n\t\t\t\tconst code = input.charCodeAt(pos);\n\n\t\t\t\tif (code === C.Quote) {\n\t\t\t\t\tresult += input.slice(chunkStart, pos);\n\t\t\t\t\tthis.pos = pos + 1;\n\t\t\t\t\treturn { type: \"STRING\", value: result, start, end: this.pos };\n\t\t\t\t}\n\n\t\t\t\tif (code === C.Backslash) {\n\t\t\t\t\tresult += input.slice(chunkStart, pos);\n\t\t\t\t\tpos++;\n\t\t\t\t\tconst escaped = input.charCodeAt(pos);\n\t\t\t\t\tpos++;\n\t\t\t\t\tswitch (escaped) {\n\t\t\t\t\t\tcase C.LowerN:\n\t\t\t\t\t\t\tresult += \"\\n\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase C.LowerT:\n\t\t\t\t\t\t\tresult += \"\\t\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase C.LowerR:\n\t\t\t\t\t\t\tresult += \"\\r\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase C.Backslash:\n\t\t\t\t\t\t\tresult += \"\\\\\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase C.Quote:\n\t\t\t\t\t\t\tresult += '\"';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tresult += String.fromCharCode(escaped);\n\t\t\t\t\t}\n\t\t\t\t\tchunkStart = pos;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tpos++;\n\t\t\t}\n\t\t}\n\n\t\tthrow new LexerError(\"Unterminated string literal\", start);\n\t}\n\n\t/**\n\t * Read a number literal\n\t */\n\tprivate readNumber(): Token {\n\t\tconst input = this.input;\n\t\tconst length = this.length;\n\t\tconst start = this.pos;\n\t\tlet pos = this.pos;\n\n\t\t// Handle negative sign\n\t\tif (input.charCodeAt(pos) === C.Minus) {\n\t\t\tpos++;\n\t\t}\n\n\t\t// Read integer part\n\t\twhile (pos < length) {\n\t\t\tconst code = input.charCodeAt(pos);\n\t\t\tif (code < C.Zero || code > C.Nine) break;\n\t\t\tpos++;\n\t\t}\n\n\t\t// Check for decimal\n\t\tif (pos < length && input.charCodeAt(pos) === C.Dot && pos + 1 < length) {\n\t\t\tconst nextCode = input.charCodeAt(pos + 1);\n\t\t\tif (nextCode >= C.Zero && nextCode <= C.Nine) {\n\t\t\t\tpos++; // skip dot\n\t\t\t\twhile (pos < length) {\n\t\t\t\t\tconst code = input.charCodeAt(pos);\n\t\t\t\t\tif (code < C.Zero || code > C.Nine) break;\n\t\t\t\t\tpos++;\n\t\t\t\t}\n\t\t\t\tthis.pos = pos;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"NUMBER\",\n\t\t\t\t\tvalue: parseFloat(input.slice(start, pos)),\n\t\t\t\t\tstart,\n\t\t\t\t\tend: pos,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tthis.pos = pos;\n\t\treturn {\n\t\t\ttype: \"NUMBER\",\n\t\t\tvalue: parseInt(input.slice(start, pos), 10),\n\t\t\tstart,\n\t\t\tend: pos,\n\t\t};\n\t}\n\n\t/**\n\t * Read identifier with fast keyword detection\n\t */\n\tprivate readIdentifier(): Token {\n\t\tconst input = this.input;\n\t\tconst length = this.length;\n\t\tconst start = this.pos;\n\t\tlet pos = this.pos;\n\n\t\t// Read all alphanumeric characters\n\t\twhile (pos < length) {\n\t\t\tconst code = input.charCodeAt(pos);\n\t\t\tif (\n\t\t\t\t(code >= C.LowerA && code <= C.LowerZ) ||\n\t\t\t\t(code >= C.UpperA && code <= C.UpperZ) ||\n\t\t\t\t(code >= C.Zero && code <= C.Nine) ||\n\t\t\t\tcode === C.Underscore\n\t\t\t) {\n\t\t\t\tpos++;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tthis.pos = pos;\n\t\tconst len = pos - start;\n\n\t\t// Keyword detection based on length and first char\n\t\tif (len >= 2 && len <= 6) {\n\t\t\tconst firstCode = input.charCodeAt(start) | 0x20; // lowercase\n\n\t\t\tif (len === 2) {\n\t\t\t\t// \"or\"\n\t\t\t\tif (firstCode === 111 && (input.charCodeAt(start + 1) | 0x20) === 114) {\n\t\t\t\t\treturn { type: \"OR\", value: \"or\", start, end: pos };\n\t\t\t\t}\n\t\t\t} else if (len === 3) {\n\t\t\t\t// \"and\", \"not\"\n\t\t\t\tif (firstCode === 97) {\n\t\t\t\t\t// 'a'\n\t\t\t\t\tif (\n\t\t\t\t\t\t(input.charCodeAt(start + 1) | 0x20) === 110 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 2) | 0x20) === 100\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn { type: \"AND\", value: \"and\", start, end: pos };\n\t\t\t\t\t}\n\t\t\t\t} else if (firstCode === 110) {\n\t\t\t\t\t// 'n'\n\t\t\t\t\tif (\n\t\t\t\t\t\t(input.charCodeAt(start + 1) | 0x20) === 111 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 2) | 0x20) === 116\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn { type: \"NOT\", value: \"not\", start, end: pos };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (len === 4) {\n\t\t\t\t// \"true\"\n\t\t\t\tif (firstCode === 116) {\n\t\t\t\t\t// 't'\n\t\t\t\t\tif (\n\t\t\t\t\t\t(input.charCodeAt(start + 1) | 0x20) === 114 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 2) | 0x20) === 117 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 3) | 0x20) === 101\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn { type: \"TRUE\", value: true, start, end: pos };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (len === 5) {\n\t\t\t\t// \"false\"\n\t\t\t\tif (firstCode === 102) {\n\t\t\t\t\t// 'f'\n\t\t\t\t\tif (\n\t\t\t\t\t\t(input.charCodeAt(start + 1) | 0x20) === 97 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 2) | 0x20) === 108 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 3) | 0x20) === 115 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 4) | 0x20) === 101\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn { type: \"FALSE\", value: false, start, end: pos };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (len === 6) {\n\t\t\t\t// \"exists\"\n\t\t\t\tif (firstCode === 101) {\n\t\t\t\t\t// 'e'\n\t\t\t\t\tif (\n\t\t\t\t\t\t(input.charCodeAt(start + 1) | 0x20) === 120 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 2) | 0x20) === 105 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 3) | 0x20) === 115 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 4) | 0x20) === 116 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 5) | 0x20) === 115\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn { type: \"EXISTS\", value: \"exists\", start, end: pos };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn { type: \"IDENT\", value: input.slice(start, pos), start, end: pos };\n\t}\n\n\t/**\n\t * Get the next token\n\t */\n\tnext(): Token {\n\t\tconst input = this.input;\n\t\tconst length = this.length;\n\n\t\tlet pos = this.pos;\n\t\twhile (pos < length) {\n\t\t\tconst c = input.charCodeAt(pos);\n\t\t\tif (c === C.Space || c === C.Tab || c === C.Newline || c === C.CarriageReturn) {\n\t\t\t\tpos++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (c === C.Slash && pos + 1 < length && input.charCodeAt(pos + 1) === C.Slash) {\n\t\t\t\tpos += 2;\n\t\t\t\twhile (pos < length && input.charCodeAt(pos) !== C.Newline) {\n\t\t\t\t\tpos++;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tthis.pos = pos;\n\n\t\tif (pos >= this.length) {\n\t\t\treturn { type: \"EOF\", value: \"\", start: pos, end: pos };\n\t\t}\n\n\t\tconst code = input.charCodeAt(pos);\n\n\t\t// Single character tokens (most common first)\n\t\tswitch (code) {\n\t\t\tcase C.LParen:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"LPAREN\", value: \"(\", start: pos, end: pos + 1 };\n\t\t\tcase C.RParen:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"RPAREN\", value: \")\", start: pos, end: pos + 1 };\n\t\t\tcase C.LBracket:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"LBRACKET\", value: \"[\", start: pos, end: pos + 1 };\n\t\t\tcase C.RBracket:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"RBRACKET\", value: \"]\", start: pos, end: pos + 1 };\n\t\t\tcase C.Comma:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"COMMA\", value: \",\", start: pos, end: pos + 1 };\n\t\t\tcase C.Question:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"QUESTION\", value: \"?\", start: pos, end: pos + 1 };\n\t\t\tcase C.Equals:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"EQ\", value: \"=\", start: pos, end: pos + 1 };\n\t\t\tcase C.Tilde:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"LIKE\", value: \"~\", start: pos, end: pos + 1 };\n\t\t\tcase C.Colon:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"COLON\", value: \":\", start: pos, end: pos + 1 };\n\t\t}\n\n\t\t// Two-character operators\n\t\tconst nextCode = pos + 1 < this.length ? input.charCodeAt(pos + 1) : 0;\n\n\t\tif (code === C.Bang) {\n\t\t\tif (nextCode === C.Equals) {\n\t\t\t\tthis.pos = pos + 2;\n\t\t\t\treturn { type: \"NEQ\", value: \"!=\", start: pos, end: pos + 2 };\n\t\t\t}\n\t\t\tif (nextCode === C.Colon) {\n\t\t\t\tthis.pos = pos + 2;\n\t\t\t\treturn { type: \"NOT_COLON\", value: \"!:\", start: pos, end: pos + 2 };\n\t\t\t}\n\t\t}\n\n\t\tif (code === C.GreaterThan) {\n\t\t\tif (nextCode === C.Equals) {\n\t\t\t\tthis.pos = pos + 2;\n\t\t\t\treturn { type: \"GTE\", value: \">=\", start: pos, end: pos + 2 };\n\t\t\t}\n\t\t\tthis.pos = pos + 1;\n\t\t\treturn { type: \"GT\", value: \">\", start: pos, end: pos + 1 };\n\t\t}\n\n\t\tif (code === C.LessThan) {\n\t\t\tif (nextCode === C.Equals) {\n\t\t\t\tthis.pos = pos + 2;\n\t\t\t\treturn { type: \"LTE\", value: \"<=\", start: pos, end: pos + 2 };\n\t\t\t}\n\t\t\tthis.pos = pos + 1;\n\t\t\treturn { type: \"LT\", value: \"<\", start: pos, end: pos + 1 };\n\t\t}\n\n\t\tif (code === C.Dot) {\n\t\t\tif (nextCode === C.Dot) {\n\t\t\t\tthis.pos = pos + 2;\n\t\t\t\treturn { type: \"DOTDOT\", value: \"..\", start: pos, end: pos + 2 };\n\t\t\t}\n\t\t\tthis.pos = pos + 1;\n\t\t\treturn { type: \"DOT\", value: \".\", start: pos, end: pos + 1 };\n\t\t}\n\n\t\t// String literal\n\t\tif (code === C.Quote) {\n\t\t\treturn this.readString();\n\t\t}\n\n\t\t// Number\n\t\tif (code >= C.Zero && code <= C.Nine) {\n\t\t\treturn this.readNumber();\n\t\t}\n\t\tif (code === C.Minus && nextCode >= C.Zero && nextCode <= C.Nine) {\n\t\t\treturn this.readNumber();\n\t\t}\n\n\t\t// Identifier or keyword\n\t\tif (\n\t\t\t(code >= C.LowerA && code <= C.LowerZ) ||\n\t\t\t(code >= C.UpperA && code <= C.UpperZ) ||\n\t\t\tcode === C.Underscore\n\t\t) {\n\t\t\treturn this.readIdentifier();\n\t\t}\n\n\t\tthrow new LexerError(`Unexpected character: '${input[pos]}'`, pos);\n\t}\n}\n",
"/**\n * A Lexer for the Filtron query language\n */\n\n/**\n * Token types produced by the lexer\n */\nexport type TokenType =\n\t| \"LPAREN\"\n\t| \"RPAREN\"\n\t| \"LBRACKET\"\n\t| \"RBRACKET\"\n\t| \"COMMA\"\n\t| \"QUESTION\"\n\t| \"DOT\"\n\t| \"DOTDOT\"\n\t| \"AND\"\n\t| \"OR\"\n\t| \"NOT\"\n\t| \"EXISTS\"\n\t| \"TRUE\"\n\t| \"FALSE\"\n\t| \"EQ\"\n\t| \"NEQ\"\n\t| \"GT\"\n\t| \"GTE\"\n\t| \"LT\"\n\t| \"LTE\"\n\t| \"LIKE\"\n\t| \"COLON\"\n\t| \"NOT_COLON\"\n\t| \"STRING\"\n\t| \"NUMBER\"\n\t| \"IDENT\"\n\t| \"EOF\";\n\n/** Base token properties */\ninterface TokenBase {\n\tstart: number;\n\tend: number;\n}\n\n/** Tokens with string values (punctuation, operators, keywords, identifiers) */\nexport interface StringToken extends TokenBase {\n\ttype:\n\t\t| \"LPAREN\"\n\t\t| \"RPAREN\"\n\t\t| \"LBRACKET\"\n\t\t| \"RBRACKET\"\n\t\t| \"COMMA\"\n\t\t| \"QUESTION\"\n\t\t| \"DOT\"\n\t\t| \"DOTDOT\"\n\t\t| \"AND\"\n\t\t| \"OR\"\n\t\t| \"NOT\"\n\t\t| \"EXISTS\"\n\t\t| \"EQ\"\n\t\t| \"NEQ\"\n\t\t| \"GT\"\n\t\t| \"GTE\"\n\t\t| \"LT\"\n\t\t| \"LTE\"\n\t\t| \"LIKE\"\n\t\t| \"COLON\"\n\t\t| \"NOT_COLON\"\n\t\t| \"STRING\"\n\t\t| \"IDENT\"\n\t\t| \"EOF\";\n\tvalue: string;\n}\n\n/** Tokens with number values */\nexport interface NumberToken extends TokenBase {\n\ttype: \"NUMBER\";\n\tvalue: number;\n}\n\n/** Tokens with boolean values */\nexport interface BooleanToken extends TokenBase {\n\ttype: \"TRUE\" | \"FALSE\";\n\tvalue: boolean;\n}\n\n/**\n * Discriminated union of all token types for proper type narrowing\n */\nexport type Token = StringToken | NumberToken | BooleanToken;\n\n// Character codes\nconst C = {\n\tTab: 9,\n\tNewline: 10,\n\tCarriageReturn: 13,\n\tSpace: 32,\n\tBang: 33,\n\tQuote: 34,\n\tLParen: 40,\n\tRParen: 41,\n\tComma: 44,\n\tMinus: 45,\n\tDot: 46,\n\tSlash: 47,\n\tZero: 48,\n\tNine: 57,\n\tColon: 58,\n\tLessThan: 60,\n\tEquals: 61,\n\tGreaterThan: 62,\n\tQuestion: 63,\n\tUpperA: 65,\n\tUpperZ: 90,\n\tLBracket: 91,\n\tBackslash: 92,\n\tRBracket: 93,\n\tUnderscore: 95,\n\tLowerA: 97,\n\tLowerN: 110,\n\tLowerR: 114,\n\tLowerT: 116,\n\tLowerZ: 122,\n\tTilde: 126,\n} as const;\n\n/**\n * Lexer error with position information\n */\nexport class LexerError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic position: number,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"LexerError\";\n\t}\n}\n\n/**\n * Lexer for tokenizing Filtron query strings\n */\nexport class Lexer {\n\tprivate pos = 0;\n\tprivate readonly input: string;\n\tprivate readonly length: number;\n\n\tconstructor(input: string) {\n\t\tthis.input = input;\n\t\tthis.length = input.length;\n\t}\n\n\t/**\n\t * Read a string literal - fast path for no escapes\n\t */\n\tprivate readString(): Token {\n\t\tconst input = this.input;\n\t\tconst length = this.length;\n\t\tconst start = this.pos;\n\t\tlet pos = this.pos + 1; // skip opening quote\n\n\t\t// Fast path: scan for closing quote or backslash\n\t\tlet hasEscape = false;\n\t\tconst scanStart = pos;\n\t\twhile (pos < length) {\n\t\t\tconst code = input.charCodeAt(pos);\n\t\t\tif (code === C.Quote) {\n\t\t\t\t// No escapes - just slice\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"STRING\",\n\t\t\t\t\tvalue: input.slice(scanStart, pos),\n\t\t\t\t\tstart,\n\t\t\t\t\tend: this.pos,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (code === C.Backslash) {\n\t\t\t\thasEscape = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tpos++;\n\t\t}\n\n\t\t// Slow path: handle escapes\n\t\tif (hasEscape) {\n\t\t\tpos = scanStart;\n\t\t\tlet result = \"\";\n\t\t\tlet chunkStart = pos;\n\n\t\t\twhile (pos < length) {\n\t\t\t\tconst code = input.charCodeAt(pos);\n\n\t\t\t\tif (code === C.Quote) {\n\t\t\t\t\tresult += input.slice(chunkStart, pos);\n\t\t\t\t\tthis.pos = pos + 1;\n\t\t\t\t\treturn { type: \"STRING\", value: result, start, end: this.pos };\n\t\t\t\t}\n\n\t\t\t\tif (code === C.Backslash) {\n\t\t\t\t\tresult += input.slice(chunkStart, pos);\n\t\t\t\t\tpos++;\n\t\t\t\t\tconst escaped = input.charCodeAt(pos);\n\t\t\t\t\tpos++;\n\t\t\t\t\tswitch (escaped) {\n\t\t\t\t\t\tcase C.LowerN:\n\t\t\t\t\t\t\tresult += \"\\n\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase C.LowerT:\n\t\t\t\t\t\t\tresult += \"\\t\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase C.LowerR:\n\t\t\t\t\t\t\tresult += \"\\r\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase C.Backslash:\n\t\t\t\t\t\t\tresult += \"\\\\\";\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase C.Quote:\n\t\t\t\t\t\t\tresult += '\"';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tresult += String.fromCharCode(escaped);\n\t\t\t\t\t}\n\t\t\t\t\tchunkStart = pos;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tpos++;\n\t\t\t}\n\t\t}\n\n\t\tthrow new LexerError(\"Unterminated string literal\", start);\n\t}\n\n\t/**\n\t * Read a number literal\n\t */\n\tprivate readNumber(): Token {\n\t\tconst input = this.input;\n\t\tconst length = this.length;\n\t\tconst start = this.pos;\n\t\tlet pos = this.pos;\n\n\t\t// Handle negative sign\n\t\tlet negative = false;\n\t\tif (input.charCodeAt(pos) === C.Minus) {\n\t\t\tnegative = true;\n\t\t\tpos++;\n\t\t}\n\n\t\t// Read integer part directly\n\t\tlet value = 0;\n\t\twhile (pos < length) {\n\t\t\tconst code = input.charCodeAt(pos);\n\t\t\tif (code < C.Zero || code > C.Nine) break;\n\t\t\tvalue = value * 10 + (code - C.Zero);\n\t\t\tpos++;\n\t\t}\n\n\t\t// Check for decimal\n\t\tif (pos < length && input.charCodeAt(pos) === C.Dot && pos + 1 < length) {\n\t\t\tconst nextCode = input.charCodeAt(pos + 1);\n\t\t\tif (nextCode >= C.Zero && nextCode <= C.Nine) {\n\t\t\t\tpos++; // skip dot\n\t\t\t\tlet fraction = 0;\n\t\t\t\tlet divisor = 1;\n\t\t\t\twhile (pos < length) {\n\t\t\t\t\tconst code = input.charCodeAt(pos);\n\t\t\t\t\tif (code < C.Zero || code > C.Nine) break;\n\t\t\t\t\tfraction = fraction * 10 + (code - C.Zero);\n\t\t\t\t\tdivisor *= 10;\n\t\t\t\t\tpos++;\n\t\t\t\t}\n\t\t\t\tthis.pos = pos;\n\t\t\t\tconst floatValue = value + fraction / divisor;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"NUMBER\",\n\t\t\t\t\tvalue: negative ? -floatValue : floatValue,\n\t\t\t\t\tstart,\n\t\t\t\t\tend: pos,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tthis.pos = pos;\n\t\treturn {\n\t\t\ttype: \"NUMBER\",\n\t\t\tvalue: negative ? -value : value,\n\t\t\tstart,\n\t\t\tend: pos,\n\t\t};\n\t}\n\n\t/**\n\t * Read identifier with fast keyword detection\n\t */\n\tprivate readIdentifier(): Token {\n\t\tconst input = this.input;\n\t\tconst length = this.length;\n\t\tconst start = this.pos;\n\t\tlet pos = this.pos;\n\n\t\t// Read all alphanumeric characters\n\t\twhile (pos < length) {\n\t\t\tconst code = input.charCodeAt(pos);\n\t\t\tif (\n\t\t\t\t(code >= C.LowerA && code <= C.LowerZ) ||\n\t\t\t\t(code >= C.UpperA && code <= C.UpperZ) ||\n\t\t\t\t(code >= C.Zero && code <= C.Nine) ||\n\t\t\t\tcode === C.Underscore\n\t\t\t) {\n\t\t\t\tpos++;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tthis.pos = pos;\n\t\tconst len = pos - start;\n\n\t\t// Keyword detection based on length and first char\n\t\tif (len >= 2 && len <= 6) {\n\t\t\tconst firstCode = input.charCodeAt(start) | 0x20; // lowercase\n\n\t\t\tif (len === 2) {\n\t\t\t\t// \"or\"\n\t\t\t\tif (firstCode === 111 && (input.charCodeAt(start + 1) | 0x20) === 114) {\n\t\t\t\t\treturn { type: \"OR\", value: \"or\", start, end: pos };\n\t\t\t\t}\n\t\t\t} else if (len === 3) {\n\t\t\t\t// \"and\", \"not\"\n\t\t\t\tif (firstCode === 97) {\n\t\t\t\t\t// 'a'\n\t\t\t\t\tif (\n\t\t\t\t\t\t(input.charCodeAt(start + 1) | 0x20) === 110 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 2) | 0x20) === 100\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn { type: \"AND\", value: \"and\", start, end: pos };\n\t\t\t\t\t}\n\t\t\t\t} else if (firstCode === 110) {\n\t\t\t\t\t// 'n'\n\t\t\t\t\tif (\n\t\t\t\t\t\t(input.charCodeAt(start + 1) | 0x20) === 111 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 2) | 0x20) === 116\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn { type: \"NOT\", value: \"not\", start, end: pos };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (len === 4) {\n\t\t\t\t// \"true\"\n\t\t\t\tif (firstCode === 116) {\n\t\t\t\t\t// 't'\n\t\t\t\t\tif (\n\t\t\t\t\t\t(input.charCodeAt(start + 1) | 0x20) === 114 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 2) | 0x20) === 117 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 3) | 0x20) === 101\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn { type: \"TRUE\", value: true, start, end: pos };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (len === 5) {\n\t\t\t\t// \"false\"\n\t\t\t\tif (firstCode === 102) {\n\t\t\t\t\t// 'f'\n\t\t\t\t\tif (\n\t\t\t\t\t\t(input.charCodeAt(start + 1) | 0x20) === 97 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 2) | 0x20) === 108 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 3) | 0x20) === 115 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 4) | 0x20) === 101\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn { type: \"FALSE\", value: false, start, end: pos };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (len === 6) {\n\t\t\t\t// \"exists\"\n\t\t\t\tif (firstCode === 101) {\n\t\t\t\t\t// 'e'\n\t\t\t\t\tif (\n\t\t\t\t\t\t(input.charCodeAt(start + 1) | 0x20) === 120 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 2) | 0x20) === 105 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 3) | 0x20) === 115 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 4) | 0x20) === 116 &&\n\t\t\t\t\t\t(input.charCodeAt(start + 5) | 0x20) === 115\n\t\t\t\t\t) {\n\t\t\t\t\t\treturn { type: \"EXISTS\", value: \"exists\", start, end: pos };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn { type: \"IDENT\", value: input.slice(start, pos), start, end: pos };\n\t}\n\n\t/**\n\t * Get the next token\n\t */\n\tnext(): Token {\n\t\tconst input = this.input;\n\t\tconst length = this.length;\n\n\t\tlet pos = this.pos;\n\t\twhile (pos < length) {\n\t\t\tconst c = input.charCodeAt(pos);\n\t\t\tif (c === C.Space || c === C.Tab || c === C.Newline || c === C.CarriageReturn) {\n\t\t\t\tpos++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (c === C.Slash && pos + 1 < length && input.charCodeAt(pos + 1) === C.Slash) {\n\t\t\t\tpos += 2;\n\t\t\t\twhile (pos < length && input.charCodeAt(pos) !== C.Newline) {\n\t\t\t\t\tpos++;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tthis.pos = pos;\n\n\t\tif (pos >= this.length) {\n\t\t\treturn { type: \"EOF\", value: \"\", start: pos, end: pos };\n\t\t}\n\n\t\tconst code = input.charCodeAt(pos);\n\n\t\t// Single character tokens (most common first)\n\t\tswitch (code) {\n\t\t\tcase C.LParen:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"LPAREN\", value: \"(\", start: pos, end: pos + 1 };\n\t\t\tcase C.RParen:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"RPAREN\", value: \")\", start: pos, end: pos + 1 };\n\t\t\tcase C.LBracket:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"LBRACKET\", value: \"[\", start: pos, end: pos + 1 };\n\t\t\tcase C.RBracket:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"RBRACKET\", value: \"]\", start: pos, end: pos + 1 };\n\t\t\tcase C.Comma:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"COMMA\", value: \",\", start: pos, end: pos + 1 };\n\t\t\tcase C.Question:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"QUESTION\", value: \"?\", start: pos, end: pos + 1 };\n\t\t\tcase C.Equals:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"EQ\", value: \"=\", start: pos, end: pos + 1 };\n\t\t\tcase C.Tilde:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"LIKE\", value: \"~\", start: pos, end: pos + 1 };\n\t\t\tcase C.Colon:\n\t\t\t\tthis.pos = pos + 1;\n\t\t\t\treturn { type: \"COLON\", value: \":\", start: pos, end: pos + 1 };\n\t\t}\n\n\t\t// Two-character operators\n\t\tconst nextCode = pos + 1 < this.length ? input.charCodeAt(pos + 1) : 0;\n\n\t\tif (code === C.Bang) {\n\t\t\tif (nextCode === C.Equals) {\n\t\t\t\tthis.pos = pos + 2;\n\t\t\t\treturn { type: \"NEQ\", value: \"!=\", start: pos, end: pos + 2 };\n\t\t\t}\n\t\t\tif (nextCode === C.Colon) {\n\t\t\t\tthis.pos = pos + 2;\n\t\t\t\treturn { type: \"NOT_COLON\", value: \"!:\", start: pos, end: pos + 2 };\n\t\t\t}\n\t\t}\n\n\t\tif (code === C.GreaterThan) {\n\t\t\tif (nextCode === C.Equals) {\n\t\t\t\tthis.pos = pos + 2;\n\t\t\t\treturn { type: \"GTE\", value: \">=\", start: pos, end: pos + 2 };\n\t\t\t}\n\t\t\tthis.pos = pos + 1;\n\t\t\treturn { type: \"GT\", value: \">\", start: pos, end: pos + 1 };\n\t\t}\n\n\t\tif (code === C.LessThan) {\n\t\t\tif (nextCode === C.Equals) {\n\t\t\t\tthis.pos = pos + 2;\n\t\t\t\treturn { type: \"LTE\", value: \"<=\", start: pos, end: pos + 2 };\n\t\t\t}\n\t\t\tthis.pos = pos + 1;\n\t\t\treturn { type: \"LT\", value: \"<\", start: pos, end: pos + 1 };\n\t\t}\n\n\t\tif (code === C.Dot) {\n\t\t\tif (nextCode === C.Dot) {\n\t\t\t\tthis.pos = pos + 2;\n\t\t\t\treturn { type: \"DOTDOT\", value: \"..\", start: pos, end: pos + 2 };\n\t\t\t}\n\t\t\tthis.pos = pos + 1;\n\t\t\treturn { type: \"DOT\", value: \".\", start: pos, end: pos + 1 };\n\t\t}\n\n\t\t// String literal\n\t\tif (code === C.Quote) {\n\t\t\treturn this.readString();\n\t\t}\n\n\t\t// Number\n\t\tif (code >= C.Zero && code <= C.Nine) {\n\t\t\treturn this.readNumber();\n\t\t}\n\t\tif (code === C.Minus && nextCode >= C.Zero && nextCode <= C.Nine) {\n\t\t\treturn this.readNumber();\n\t\t}\n\n\t\t// Identifier or keyword\n\t\tif (\n\t\t\t(code >= C.LowerA && code <= C.LowerZ) ||\n\t\t\t(code >= C.UpperA && code <= C.UpperZ) ||\n\t\t\tcode === C.Underscore\n\t\t) {\n\t\t\treturn this.readIdentifier();\n\t\t}\n\n\t\tthrow new LexerError(`Unexpected character: '${input[pos]}'`, pos);\n\t}\n}\n",
"/**\n * Recursive Descent Parser for Filtron\n * https://en.wikipedia.org/wiki/Recursive_descent_parser\n *\n * Grammar (in order of precedence, lowest to highest):\n *\n * Query = OrExpression\n * OrExpression = AndExpression (OR AndExpression)*\n * AndExpression = NotExpression (AND NotExpression)*\n * NotExpression = NOT NotExpression | PrimaryExpression\n * PrimaryExpression = '(' OrExpression ')' | FieldExpression\n * FieldExpression = FieldName ('?' | EXISTS | ComparisonOp Value RangeSuffix? | OneOfOp '[' Values ']')?\n * FieldName = IDENT ('.' IDENT)*\n * Value = STRING | NUMBER | BOOLEAN | DottedIdent\n * Values = Value (',' Value)*\n * RangeSuffix = '..' NUMBER\n */\n\nimport type {\n\tASTNode,\n\tValue,\n\tComparisonOperator,\n\tComparisonExpression,\n\tOneOfExpression,\n\tNotOneOfExpression,\n\tExistsExpression,\n\tBooleanFieldExpression,\n\tRangeExpression,\n} from \"./types\";\nimport { Lexer, type Token, type TokenType } from \"./lexer\";\n\n/**\n * Parser error with position information\n */\nexport class ParseError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic position: number,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"ParseError\";\n\t}\n}\n\n/**\n * Parser for Filtron queries\n */\nclass Parser {\n\tprivate lexer: Lexer;\n\tprivate current: Token;\n\tprivate nextToken: Token | null = null;\n\n\tconstructor(input: string) {\n\t\tthis.lexer = new Lexer(input);\n\t\tthis.current = this.lexer.next();\n\t}\n\n\t/**\n\t * Advance to the next token and return the previous one\n\t */\n\tprivate advance(): Token {\n\t\tconst prev = this.current;\n\t\tif (this.nextToken) {\n\t\t\tthis.current = this.nextToken;\n\t\t\tthis.nextToken = null;\n\t\t} else {\n\t\t\tthis.current = this.lexer.next();\n\t\t}\n\t\treturn prev;\n\t}\n\n\t/**\n\t * Check if current token matches the given type\n\t */\n\tprivate check(type: TokenType): boolean {\n\t\treturn this.current.type === type;\n\t}\n\n\t/**\n\t * Consume a token of the expected type, or throw an error\n\t */\n\tprivate expect(type: TokenType, message?: string): Token {\n\t\tif (this.current.type !== type) {\n\t\t\tconst msg = message ?? `Expected ${type}, got ${this.current.type}`;\n\t\t\tthrow new ParseError(msg, this.current.start);\n\t\t}\n\t\treturn this.advance();\n\t}\n\n\t/**\n\t * Parse a complete query\n\t */\n\tparse(): ASTNode {\n\t\tif (this.check(\"EOF\")) {\n\t\t\tthrow new ParseError(\"Empty query\", 0);\n\t\t}\n\n\t\tconst result = this.parseOrExpression();\n\n\t\tif (!this.check(\"EOF\")) {\n\t\t\tthrow new ParseError(`Unexpected token: ${this.current.type}`, this.current.start);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Parse OR expression\n\t * OrExpression = AndExpression (OR AndExpression)*\n\t */\n\tprivate parseOrExpression(): ASTNode {\n\t\tlet left = this.parseAndExpression();\n\n\t\twhile (this.check(\"OR\")) {\n\t\t\tthis.advance();\n\t\t\tconst right = this.parseAndExpression();\n\t\t\tleft = { type: \"or\", left, right };\n\t\t}\n\n\t\treturn left;\n\t}\n\n\t/**\n\t * Parse AND expression\n\t * AndExpression = NotExpression (AND NotExpression)*\n\t */\n\tprivate parseAndExpression(): ASTNode {\n\t\tlet left = this.parseNotExpression();\n\n\t\twhile (this.check(\"AND\")) {\n\t\t\tthis.advance();\n\t\t\tconst right = this.parseNotExpression();\n\t\t\tleft = { type: \"and\", left, right };\n\t\t}\n\n\t\treturn left;\n\t}\n\n\t/**\n\t * Parse NOT expression\n\t * NotExpression = NOT NotExpression | PrimaryExpression\n\t */\n\tprivate parseNotExpression(): ASTNode {\n\t\tif (this.check(\"NOT\")) {\n\t\t\tthis.advance();\n\t\t\tconst expression = this.parseNotExpression();\n\t\t\treturn { type: \"not\", expression };\n\t\t}\n\n\t\treturn this.parsePrimaryExpression();\n\t}\n\n\t/**\n\t * Parse primary expression (highest precedence)\n\t * PrimaryExpression = '(' OrExpression ')' | FieldExpression\n\t */\n\tprivate parsePrimaryExpression(): ASTNode {\n\t\t// Parenthesized expression\n\t\tif (this.check(\"LPAREN\")) {\n\t\t\tthis.advance();\n\t\t\tconst expr = this.parseOrExpression();\n\t\t\tthis.expect(\"RPAREN\", \"Expected closing parenthesis\");\n\t\t\treturn expr;\n\t\t}\n\n\t\treturn this.parseFieldExpression();\n\t}\n\n\t/**\n\t * Parse field expression\n\t * FieldExpression = FieldName ('?' | EXISTS | ComparisonOp Value RangeSuffix? | OneOfOp '[' Values ']')?\n\t */\n\tprivate parseFieldExpression(): ASTNode {\n\t\tconst field = this.parseFieldName();\n\t\tconst t = this.current.type;\n\n\t\t// Exists check with ? or EXISTS\n\t\tif (t === \"QUESTION\" || t === \"EXISTS\") {\n\t\t\tthis.advance();\n\t\t\treturn { type: \"exists\", field } as ExistsExpression;\n\t\t}\n\n\t\t// OneOf: field : [values]\n\t\tif (t === \"COLON\" && this.peekNextIsLBracket()) {\n\t\t\tthis.advance();\n\t\t\treturn this.parseOneOfArray(field, \"oneOf\");\n\t\t}\n\n\t\t// NotOneOf: field !: [values]\n\t\tif (t === \"NOT_COLON\") {\n\t\t\tthis.advance();\n\t\t\treturn this.parseOneOfArray(field, \"notOneOf\");\n\t\t}\n\n\t\t// Comparison with operator\n\t\tif (\n\t\t\tt === \"EQ\" ||\n\t\t\tt === \"NEQ\" ||\n\t\t\tt === \"GT\" ||\n\t\t\tt === \"GTE\" ||\n\t\t\tt === \"LT\" ||\n\t\t\tt === \"LTE\" ||\n\t\t\tt === \"LIKE\" ||\n\t\t\tt === \"COLON\"\n\t\t) {\n\t\t\tconst opToken = this.advance();\n\t\t\tconst operator = this.tokenToOperator(opToken);\n\n\t\t\t// Check for range expression: field = min..max\n\t\t\tif (operator === \"=\" && this.check(\"NUMBER\")) {\n\t\t\t\tconst minToken = this.advance();\n\t\t\t\tconst min = minToken.value as number;\n\n\t\t\t\tif (this.check(\"DOTDOT\")) {\n\t\t\t\t\tthis.advance();\n\t\t\t\t\tconst maxToken = this.expect(\"NUMBER\", \"Expected number after '..'\");\n\t\t\t\t\tconst max = maxToken.value as number;\n\t\t\t\t\treturn { type: \"range\", field, min, max } as RangeExpression;\n\t\t\t\t}\n\n\t\t\t\t// Not a range, just a regular comparison with a number\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"comparison\",\n\t\t\t\t\tfield,\n\t\t\t\t\toperator,\n\t\t\t\t\tvalue: { type: \"number\", value: min },\n\t\t\t\t} as ComparisonExpression;\n\t\t\t}\n\n\t\t\tconst value = this.parseValue();\n\t\t\treturn {\n\t\t\t\ttype: \"comparison\",\n\t\t\t\tfield,\n\t\t\t\toperator,\n\t\t\t\tvalue,\n\t\t\t} as ComparisonExpression;\n\t\t}\n\n\t\t// Boolean field shorthand (just the field name)\n\t\treturn { type: \"booleanField\", field } as BooleanFieldExpression;\n\t}\n\n\t/**\n\t * Check if the token after the current one is LBRACKET\n\t * (used to distinguish : as oneOf vs : as comparison operator)\n\t */\n\tprivate peekNextIsLBracket(): boolean {\n\t\tif (!this.nextToken) {\n\t\t\tthis.nextToken = this.lexer.next();\n\t\t}\n\t\treturn this.nextToken.type === \"LBRACKET\";\n\t}\n\n\t/**\n\t * Convert a token to its corresponding comparison operator\n\t */\n\tprivate tokenToOperator(token: Token): ComparisonOperator {\n\t\tswitch (token.type) {\n\t\t\tcase \"EQ\":\n\t\t\t\treturn \"=\";\n\t\t\tcase \"NEQ\":\n\t\t\t\treturn \"!=\";\n\t\t\tcase \"GT\":\n\t\t\t\treturn \">\";\n\t\t\tcase \"GTE\":\n\t\t\t\treturn \">=\";\n\t\t\tcase \"LT\":\n\t\t\t\treturn \"<\";\n\t\t\tcase \"LTE\":\n\t\t\t\treturn \"<=\";\n\t\t\tcase \"LIKE\":\n\t\t\t\treturn \"~\";\n\t\t\tcase \"COLON\":\n\t\t\t\treturn \":\";\n\t\t\tdefault:\n\t\t\t\tthrow new ParseError(`Invalid operator: ${token.type}`, token.start);\n\t\t}\n\t}\n\n\t/**\n\t * Parse a field name (possibly dotted)\n\t * FieldName = IDENT ('.' IDENT)*\n\t */\n\tprivate parseFieldName(): string {\n\t\tconst first = this.expect(\"IDENT\", \"Expected field name\");\n\t\tlet name = first.value as string;\n\n\t\twhile (this.check(\"DOT\")) {\n\t\t\tthis.advance(); // consume .\n\t\t\tconst next = this.expect(\"IDENT\", \"Expected identifier after '.'\");\n\t\t\tname += \".\" + next.value;\n\t\t}\n\n\t\treturn name;\n\t}\n\n\t/**\n\t * Parse oneOf/notOneOf array\n\t * '[' Values ']'\n\t */\n\tprivate parseOneOfArray(\n\t\tfield: string,\n\t\ttype: \"oneOf\" | \"notOneOf\",\n\t): OneOfExpression | NotOneOfExpression {\n\t\tthis.expect(\"LBRACKET\", \"Expected '[' after operator\");\n\n\t\tconst values: Value[] = [];\n\n\t\t// Handle non-empty array\n\t\tif (!this.check(\"RBRACKET\")) {\n\t\t\tvalues.push(this.parseValue());\n\n\t\t\twhile (this.check(\"COMMA\")) {\n\t\t\t\tthis.advance(); // consume ,\n\t\t\t\tvalues.push(this.parseValue());\n\t\t\t}\n\t\t}\n\n\t\tthis.expect(\"RBRACKET\", \"Expected ']' to close array\");\n\n\t\tif (values.length === 0) {\n\t\t\tthrow new ParseError(\"Array cannot be empty\", this.current.start);\n\t\t}\n\n\t\treturn { type, field, values };\n\t}\n\n\t/**\n\t * Parse a value\n\t * Value = STRING | NUMBER | BOOLEAN | DottedIdent\n\t */\n\tprivate parseValue(): Value {\n\t\tconst t = this.current.type;\n\n\t\t// String literal\n\t\tif (t === \"STRING\") {\n\t\t\tconst token = this.advance();\n\t\t\treturn { type: \"string\", value: token.value as string };\n\t\t}\n\n\t\t// Number literal\n\t\tif (t === \"NUMBER\") {\n\t\t\tconst token = this.advance();\n\t\t\treturn { type: \"number\", value: token.value as number };\n\t\t}\n\n\t\t// Boolean literal\n\t\tif (t === \"TRUE\") {\n\t\t\tthis.advance();\n\t\t\treturn { type: \"boolean\", value: true };\n\t\t}\n\t\tif (t === \"FALSE\") {\n\t\t\tthis.advance();\n\t\t\treturn { type: \"boolean\", value: false };\n\t\t}\n\n\t\t// Identifier (possibly dotted)\n\t\tif (t === \"IDENT\") {\n\t\t\tconst first = this.advance();\n\t\t\tlet value = first.value as string;\n\n\t\t\twhile (this.current.type === \"DOT\") {\n\t\t\t\tthis.advance(); // consume .\n\t\t\t\tconst next = this.expect(\"IDENT\", \"Expected identifier after '.'\");\n\t\t\t\tvalue += \".\" + next.value;\n\t\t\t}\n\n\t\t\treturn { type: \"identifier\", value };\n\t\t}\n\n\t\tthrow new ParseError(`Expected value, got ${t}`, this.current.start);\n\t}\n}\n\n/**\n * Parse a Filtron query string into an AST\n *\n * @param input - The query string to parse\n * @returns The parsed AST\n * @throws ParseError if the query is invalid\n */\nexport function parseQuery(input: string): ASTNode {\n\tconst parser = new Parser(input);\n\treturn parser.parse();\n}\n",
"/**\n * The Filtron parser public API\n */\n\nimport type { ASTNode } from \"./types\";\nimport { LexerError } from \"./lexer\";\nimport { parseQuery, ParseError as RDParseError } from \"./rd-parser\";\n\n/**\n * Result of a successful parse operation\n */\nexport interface ParseSuccess {\n\tsuccess: true;\n\tast: ASTNode;\n}\n\n/**\n * Result of a failed parse operation\n */\nexport interface ParseError {\n\tsuccess: false;\n\terror: string;\n\tmessage: string;\n}\n\n/**\n * The generic parse result\n */\nexport type ParseResult = ParseSuccess | ParseError;\n\n/**\n * Parses a Filtron query string into an Abstract Syntax Tree (AST).\n *\n * @param query - The Filtron query string to parse\n * @returns A ParseResult containing either the AST or an error message\n *\n * @example\n * ```typescript\n * const result = parse('age > 18 AND status = \"active\"');\n * if (result.success) {\n * console.log(result.ast);\n * } else {\n * console.error(result.error);\n * }\n * ```\n */\nexport const parse = (query: string): ParseResult => {\n\ttry {\n\t\tconst ast = parseQuery(query);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tast,\n\t\t};\n\t} catch (error) {\n\t\tlet message: string;\n\n\t\tif (error instanceof RDParseError || error instanceof LexerError) {\n\t\t\tmessage = error.message;\n\t\t} else if (error instanceof Error) {\n\t\t\tmessage = error.message;\n\t\t} else {\n\t\t\tmessage = String(error);\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: message,\n\t\t\tmessage,\n\t\t};\n\t}\n};\n\n/**\n * Parses a Filtron query string and throws an error if parsing fails.\n * Use this when you want to handle errors with try/catch instead of checking the result.\n *\n * @param query - The Filtron query string to parse\n * @returns The parsed AST\n * @throws Error if parsing fails\n *\n * @example\n * ```typescript\n * try {\n * const ast = parseOrThrow('age > 18');\n * console.log(ast);\n * } catch (error) {\n * console.error('Parse failed:', error.message);\n * }\n * ```\n */\nexport const parseOrThrow = (query: string): ASTNode => {\n\tconst result = parse(query);\n\n\tif (result.success) {\n\t\treturn result.ast;\n\t}\n\n\tthrow new Error(`Failed to parse Filtron query: ${result.error}`);\n};\n"
"/**\n * The Filtron parser public API\n */\n\nimport type { ASTNode } from \"./types\";\nimport { LexerError } from \"./lexer\";\nimport { parseQuery, ParseError as RDParseError } from \"./rd-parser\";\n\n/**\n * Error thrown by parseOrThrow when parsing fails.\n * Includes the position in the query where the error occurred.\n */\nexport class FiltronParseError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic position?: number,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"FiltronParseError\";\n\t}\n}\n\n/**\n * Result of a successful parse operation\n */\nexport interface ParseSuccess {\n\tsuccess: true;\n\tast: ASTNode;\n}\n\n/**\n * Result of a failed parse operation\n */\nexport interface ParseError {\n\tsuccess: false;\n\terror: string;\n\tmessage: string;\n\tposition?: number;\n}\n\n/**\n * The generic parse result\n */\nexport type ParseResult = ParseSuccess | ParseError;\n\n/**\n * Parses a Filtron query string into an Abstract Syntax Tree (AST).\n *\n * @param query - The Filtron query string to parse\n * @returns A ParseResult containing either the AST or an error\n *\n * @example\n * ```typescript\n * const result = parse('age > 18 AND status = \"active\"');\n * if (result.success) {\n * console.log(result.ast);\n * } else {\n * console.error(result.error);\n * }\n * ```\n */\nexport const parse = (query: string): ParseResult => {\n\ttry {\n\t\tconst ast = parseQuery(query);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tast,\n\t\t};\n\t} catch (error) {\n\t\tlet message: string;\n\t\tlet position: number | undefined;\n\n\t\tif (error instanceof RDParseError || error instanceof LexerError) {\n\t\t\tmessage = error.message;\n\t\t\tposition = error.position;\n\t\t} else if (error instanceof Error) {\n\t\t\tmessage = error.message;\n\t\t} else {\n\t\t\tmessage = String(error);\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: message,\n\t\t\tmessage,\n\t\t\tposition,\n\t\t};\n\t}\n};\n\n/**\n * Parses a Filtron query string and throws an error if parsing fails.\n * Use this when you want to handle errors with try/catch instead of checking the result.\n *\n * @param query - The Filtron query string to parse\n * @returns The parsed AST\n * @throws FiltronParseError if parsing fails, with position information\n *\n * @example\n * ```typescript\n * try {\n * const ast = parseOrThrow('age > 18');\n * console.log(ast);\n * } catch (error) {\n * if (error instanceof FiltronParseError) {\n * console.error('Parse failed at position', error.position, ':', error.message);\n * }\n * }\n * ```\n */\nexport const parseOrThrow = (query: string): ASTNode => {\n\tconst result = parse(query);\n\n\tif (result.success) {\n\t\treturn result.ast;\n\t}\n\n\tthrow new FiltronParseError(`Failed to parse Filtron query: ${result.error}`, result.position);\n};\n"
],
"mappings": "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",
"debugId": "839D03E8D259923E64756E2164756E21",
"mappings": "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",
"debugId": "55F7033D8A7F4FE964756E2164756E21",
"names": []
}

@@ -14,5 +14,7 @@ /**

*/
export { parse, parseOrThrow } from "./parser";
export { parse, parseOrThrow, FiltronParseError } from "./parser";
export type { ParseResult, ParseSuccess, ParseError } from "./parser";
export { Lexer, LexerError } from "./lexer";
export type { Token, TokenType, StringToken, NumberToken, BooleanToken } from "./lexer";
export type { ASTNode, Value, ComparisonOperator, OrExpression, AndExpression, NotExpression, ComparisonExpression, OneOfExpression, NotOneOfExpression, ExistsExpression, BooleanFieldExpression, RangeExpression, StringValue, NumberValue, BooleanValue, IdentifierValue, } from "./types";
//# sourceMappingURL=index.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC/C,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGtE,YAAY,EACX,OAAO,EACP,KAAK,EACL,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,WAAW,EACX,WAAW,EACX,YAAY,EACZ,eAAe,GACf,MAAM,SAAS,CAAC"}
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAClE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGtE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC5C,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGxF,YAAY,EACX,OAAO,EACP,KAAK,EACL,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,WAAW,EACX,WAAW,EACX,YAAY,EACZ,eAAe,GACf,MAAM,SAAS,CAAC"}

@@ -1,1 +0,1 @@

{"version":3,"file":"lexer.d.ts","sourceRoot":"","sources":["../../src/lexer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,SAAS,GAClB,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,UAAU,GACV,OAAO,GACP,UAAU,GACV,KAAK,GACL,QAAQ,GACR,KAAK,GACL,IAAI,GACJ,KAAK,GACL,QAAQ,GACR,MAAM,GACN,OAAO,GACP,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,KAAK,GACL,MAAM,GACN,OAAO,GACP,WAAW,GACX,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,KAAK,CAAC;AAET,4BAA4B;AAC5B,UAAU,SAAS;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,gFAAgF;AAChF,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC7C,IAAI,EACD,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,UAAU,GACV,OAAO,GACP,UAAU,GACV,KAAK,GACL,QAAQ,GACR,KAAK,GACL,IAAI,GACJ,KAAK,GACL,QAAQ,GACR,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,KAAK,GACL,MAAM,GACN,OAAO,GACP,WAAW,GACX,QAAQ,GACR,OAAO,GACP,KAAK,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;CACd;AAED,gCAAgC;AAChC,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC7C,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACd;AAED,iCAAiC;AACjC,MAAM,WAAW,YAAa,SAAQ,SAAS;IAC9C,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;CACf;AAED;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,CAAC;AAqC7D;;GAEG;AACH,qBAAa,UAAW,SAAQ,KAAK;IAG5B,QAAQ,EAAE,MAAM;gBADvB,OAAO,EAAE,MAAM,EACR,QAAQ,EAAE,MAAM;CAKxB;AAED;;GAEG;AACH,qBAAa,KAAK;IACjB,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,KAAK,EAAE,MAAM;IAKzB;;OAEG;IACH,OAAO,CAAC,UAAU;IA8ElB;;OAEG;IACH,OAAO,CAAC,UAAU;IA+ClB;;OAEG;IACH,OAAO,CAAC,cAAc;IAiGtB;;OAEG;IACH,IAAI,IAAI,KAAK;CA4Hb"}
{"version":3,"file":"lexer.d.ts","sourceRoot":"","sources":["../../src/lexer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,SAAS,GAClB,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,UAAU,GACV,OAAO,GACP,UAAU,GACV,KAAK,GACL,QAAQ,GACR,KAAK,GACL,IAAI,GACJ,KAAK,GACL,QAAQ,GACR,MAAM,GACN,OAAO,GACP,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,KAAK,GACL,MAAM,GACN,OAAO,GACP,WAAW,GACX,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,KAAK,CAAC;AAET,4BAA4B;AAC5B,UAAU,SAAS;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,gFAAgF;AAChF,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC7C,IAAI,EACD,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,UAAU,GACV,OAAO,GACP,UAAU,GACV,KAAK,GACL,QAAQ,GACR,KAAK,GACL,IAAI,GACJ,KAAK,GACL,QAAQ,GACR,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,KAAK,GACL,MAAM,GACN,OAAO,GACP,WAAW,GACX,QAAQ,GACR,OAAO,GACP,KAAK,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;CACd;AAED,gCAAgC;AAChC,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC7C,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACd;AAED,iCAAiC;AACjC,MAAM,WAAW,YAAa,SAAQ,SAAS;IAC9C,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;CACf;AAED;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,CAAC;AAqC7D;;GAEG;AACH,qBAAa,UAAW,SAAQ,KAAK;IAG5B,QAAQ,EAAE,MAAM;gBADvB,OAAO,EAAE,MAAM,EACR,QAAQ,EAAE,MAAM;CAKxB;AAED;;GAEG;AACH,qBAAa,KAAK;IACjB,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,KAAK,EAAE,MAAM;IAKzB;;OAEG;IACH,OAAO,CAAC,UAAU;IA8ElB;;OAEG;IACH,OAAO,CAAC,UAAU;IAwDlB;;OAEG;IACH,OAAO,CAAC,cAAc;IAiGtB;;OAEG;IACH,IAAI,IAAI,KAAK;CA4Hb"}

@@ -6,2 +6,10 @@ /**

/**
* Error thrown by parseOrThrow when parsing fails.
* Includes the position in the query where the error occurred.
*/
export declare class FiltronParseError extends Error {
position?: number | undefined;
constructor(message: string, position?: number | undefined);
}
/**
* Result of a successful parse operation

@@ -20,2 +28,3 @@ */

message: string;
position?: number;
}

@@ -30,3 +39,3 @@ /**

* @param query - The Filtron query string to parse
* @returns A ParseResult containing either the AST or an error message
* @returns A ParseResult containing either the AST or an error
*

@@ -50,3 +59,3 @@ * @example

* @returns The parsed AST
* @throws Error if parsing fails
* @throws FiltronParseError if parsing fails, with position information
*

@@ -59,3 +68,5 @@ * @example

* } catch (error) {
* console.error('Parse failed:', error.message);
* if (error instanceof FiltronParseError) {
* console.error('Parse failed at position', error.position, ':', error.message);
* }
* }

@@ -62,0 +73,0 @@ * ```

@@ -1,1 +0,1 @@

{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAIvC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,OAAO,EAAE,IAAI,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,UAAU,CAAC;AAEpD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,KAAG,WAwBrC,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,KAAG,OAQ5C,CAAC"}
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAIvC;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAGnC,QAAQ,CAAC,EAAE,MAAM;gBADxB,OAAO,EAAE,MAAM,EACR,QAAQ,CAAC,EAAE,MAAM,YAAA;CAKzB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,OAAO,EAAE,IAAI,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,UAAU,CAAC;AAEpD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,KAAG,WA2BrC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,KAAG,OAQ5C,CAAC"}
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@filtron/core",
"version": "1.3.2",
"version": "1.4.0",
"description": "Filtron parses human-friendly filter strings into structured queries you can use anywhere — SQL databases, in-memory arrays, or your own custom backend.",

@@ -30,2 +30,4 @@ "keywords": [

"dist",
"examples",
"filtron.tmLanguage.json",
"LICENSE",

@@ -43,3 +45,4 @@ "README.md"

"default": "./dist/index.js"
}
},
"./filtron.tmLanguage.json": "./filtron.tmLanguage.json"
},

@@ -55,3 +58,3 @@ "scripts": {

"@filtron/benchmark": "1.0.0",
"@types/bun": "1.3.5",
"@types/bun": "1.3.6",
"typescript": "5.9.3"

@@ -71,3 +74,3 @@ },

},
"packageManager": "bun@1.3.3"
"packageManager": "bun@1.3.6"
}
+53
-39

@@ -11,3 +11,3 @@ # @filtron/core

Let users filter data with readable expressions instead of building complex query UIs:
Let users filter data with readable expressions:

@@ -20,3 +20,3 @@ ```

**Use cases:** Search UIs, API query parameters, admin dashboards, real-time data filtering.
Filtron works best when your data has dynamic or user-defined fields that aren't part of your type system: e-commerce catalogs, log aggregation, CMS taxonomies, or multi-tenant platforms with custom metadata.

@@ -42,5 +42,5 @@ ## Installation

if (result.success) {
console.log(result.ast);
console.log(result.ast);
} else {
console.error(result.error);
console.error(result.error);
}

@@ -53,3 +53,3 @@ ```

// Comparisons
parse('age > 18');
parse("age > 18");
parse('status = "active"');

@@ -59,10 +59,10 @@ parse('role != "guest"');

// Boolean logic
parse('age > 18 AND verified');
parse('admin OR moderator');
parse('NOT suspended');
parse('(admin OR mod) AND active');
parse("age > 18 AND verified");
parse("admin OR moderator");
parse("NOT suspended");
parse("(admin OR mod) AND active");
// Field existence
parse('email?');
parse('profile EXISTS');
parse("email?");
parse("profile EXISTS");

@@ -76,7 +76,7 @@ // Contains (substring)

// Ranges
parse('age = 18..65');
parse('price = 9.99..99.99');
parse("age = 18..65");
parse("price = 9.99..99.99");
// Nested fields
parse('user.profile.age >= 18');
parse("user.profile.age >= 18");
```

@@ -104,8 +104,9 @@

```typescript
const result = parse('age > 18');
const result = parse("age > 18");
if (result.success) {
result.ast; // ASTNode
result.ast; // ASTNode
} else {
result.error; // string
result.error; // string - error message
result.position; // number - position in input where error occurred
}

@@ -116,9 +117,14 @@ ```

Parses a filter expression, throwing on invalid input.
Parses a filter expression, throwing `FiltronParseError` on invalid input.
```typescript
import { parseOrThrow, FiltronParseError } from "@filtron/core";
try {
const ast = parseOrThrow('age > 18');
const ast = parseOrThrow("age > 18");
} catch (error) {
console.error(error.message);
if (error instanceof FiltronParseError) {
console.error(error.message); // error description
console.error(error.position); // position in input where error occurred
}
}

@@ -132,23 +138,31 @@ ```

```typescript
import type {
ParseResult,
ASTNode,
AndExpression,
OrExpression,
NotExpression,
ComparisonExpression,
ExistsExpression,
BooleanFieldExpression,
OneOfExpression,
NotOneOfExpression,
RangeExpression,
Value,
ComparisonOperator,
StringValue,
NumberValue,
BooleanValue,
IdentifierValue,
import {
FiltronParseError, // Error class thrown by parseOrThrow
type ParseResult,
type ASTNode,
type AndExpression,
type OrExpression,
type NotExpression,
type ComparisonExpression,
type ExistsExpression,
type BooleanFieldExpression,
type OneOfExpression,
type NotOneOfExpression,
type RangeExpression,
type Value,
type ComparisonOperator,
type StringValue,
type NumberValue,
type BooleanValue,
type IdentifierValue,
} from "@filtron/core";
```
The Lexer types are also available if you want to use them for syntax highlighting or other purposes:
```typescript
import { Lexer, LexerError } from "@filtron/core";
import type { Token, TokenType, StringToken, NumberToken, BooleanToken } from "@filtron/core";
```
### AST structure

@@ -196,3 +210,3 @@

Hand-written recursive descent parser. ~9 KB minified, zero dependencies.
Recursive descent parser. ~9 KB minified, zero dependencies.

@@ -199,0 +213,0 @@ | Query complexity | Parse time | Throughput |

MIT License
Copyright (c) 2026 Johan Bergström
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.