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.0.0
to
1.1.0
+12
dist/index.js.map
{
"version": 3,
"sources": ["../src/lexer.ts", "../src/rd-parser.ts", "../src/parser.ts"],
"sourcesContent": [
"/**\n * Lexer for Filtron query language\n *\n * Tokenizes input strings into a stream of tokens for the parser.\n */\n\n/**\n * Token types produced by the lexer\n */\nexport type TokenType =\n\t// Grouping\n\t| \"LPAREN\"\n\t| \"RPAREN\"\n\t| \"LBRACKET\"\n\t| \"RBRACKET\"\n\t// Punctuation\n\t| \"COMMA\"\n\t| \"QUESTION\"\n\t| \"DOT\"\n\t| \"DOTDOT\"\n\t// Keywords (case-insensitive)\n\t| \"AND\"\n\t| \"OR\"\n\t| \"NOT\"\n\t| \"EXISTS\"\n\t| \"TRUE\"\n\t| \"FALSE\"\n\t// Operators\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// Literals\n\t| \"STRING\"\n\t| \"NUMBER\"\n\t| \"IDENT\"\n\t// End of input\n\t| \"EOF\";\n\n/**\n * A token produced by the lexer\n */\nexport interface Token {\n\ttype: TokenType;\n\tvalue: string | number | boolean;\n\tstart: number;\n\tend: number;\n}\n\n/**\n * Keywords mapped to their token types\n */\nconst KEYWORDS: Record<string, TokenType> = {\n\tand: \"AND\",\n\tor: \"OR\",\n\tnot: \"NOT\",\n\texists: \"EXISTS\",\n\ttrue: \"TRUE\",\n\tfalse: \"FALSE\",\n};\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 * Get the current character without advancing\n\t */\n\tprivate peek(): string {\n\t\treturn this.pos < this.length ? this.input[this.pos] : \"\";\n\t}\n\n\t/**\n\t * Get the next character without advancing\n\t */\n\tprivate peekNext(): string {\n\t\treturn this.pos + 1 < this.length ? this.input[this.pos + 1] : \"\";\n\t}\n\n\t/**\n\t * Advance and return the current character\n\t */\n\tprivate advance(): string {\n\t\treturn this.pos < this.length ? this.input[this.pos++] : \"\";\n\t}\n\n\t/**\n\t * Skip whitespace and comments\n\t */\n\tprivate skipWhitespaceAndComments(): void {\n\t\twhile (this.pos < this.length) {\n\t\t\tconst char = this.peek();\n\n\t\t\t// Skip whitespace\n\t\t\tif (char === \" \" || char === \"\\t\" || char === \"\\n\" || char === \"\\r\") {\n\t\t\t\tthis.advance();\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Skip single-line comments: // ...\n\t\t\tif (char === \"/\" && this.peekNext() === \"/\") {\n\t\t\t\tthis.advance(); // skip /\n\t\t\t\tthis.advance(); // skip /\n\t\t\t\twhile (this.pos < this.length && this.peek() !== \"\\n\") {\n\t\t\t\t\tthis.advance();\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Read a string literal (double-quoted)\n\t */\n\tprivate readString(): Token {\n\t\tconst start = this.pos;\n\t\tthis.advance(); // skip opening quote\n\n\t\tlet value = \"\";\n\t\twhile (this.pos < this.length) {\n\t\t\tconst char = this.peek();\n\n\t\t\tif (char === '\"') {\n\t\t\t\tthis.advance(); // skip closing quote\n\t\t\t\treturn { type: \"STRING\", value, start, end: this.pos };\n\t\t\t}\n\n\t\t\tif (char === \"\\\\\") {\n\t\t\t\tthis.advance(); // skip backslash\n\t\t\t\tconst escaped = this.advance();\n\t\t\t\tswitch (escaped) {\n\t\t\t\t\tcase \"n\":\n\t\t\t\t\t\tvalue += \"\\n\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"t\":\n\t\t\t\t\t\tvalue += \"\\t\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"r\":\n\t\t\t\t\t\tvalue += \"\\r\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"\\\\\":\n\t\t\t\t\t\tvalue += \"\\\\\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase '\"':\n\t\t\t\t\t\tvalue += '\"';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\t// Keep unknown escapes as-is\n\t\t\t\t\t\tvalue += escaped;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tvalue += this.advance();\n\t\t}\n\n\t\tthrow new LexerError(\"Unterminated string literal\", start);\n\t}\n\n\t/**\n\t * Read a number literal (integer or float, possibly negative)\n\t */\n\tprivate readNumber(): Token {\n\t\tconst start = this.pos;\n\t\tlet numStr = \"\";\n\n\t\t// Handle negative sign\n\t\tif (this.peek() === \"-\") {\n\t\t\tnumStr += this.advance();\n\t\t}\n\n\t\t// Read integer part\n\t\twhile (/[0-9]/.test(this.peek())) {\n\t\t\tnumStr += this.advance();\n\t\t}\n\n\t\t// Check for decimal part\n\t\tif (this.peek() === \".\" && /[0-9]/.test(this.peekNext())) {\n\t\t\tnumStr += this.advance(); // the dot\n\t\t\twhile (/[0-9]/.test(this.peek())) {\n\t\t\t\tnumStr += this.advance();\n\t\t\t}\n\t\t\treturn { type: \"NUMBER\", value: parseFloat(numStr), start, end: this.pos };\n\t\t}\n\n\t\treturn { type: \"NUMBER\", value: parseInt(numStr, 10), start, end: this.pos };\n\t}\n\n\t/**\n\t * Read an identifier or keyword\n\t */\n\tprivate readIdentifier(): Token {\n\t\tconst start = this.pos;\n\t\tlet ident = \"\";\n\n\t\twhile (this.pos < this.length) {\n\t\t\tconst char = this.peek();\n\t\t\tif (/[a-zA-Z0-9_]/.test(char)) {\n\t\t\t\tident += this.advance();\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Check if it's a keyword\n\t\tconst lower = ident.toLowerCase();\n\t\tconst keywordType = KEYWORDS[lower];\n\t\tif (keywordType) {\n\t\t\tif (keywordType === \"TRUE\") {\n\t\t\t\treturn { type: \"TRUE\", value: true, start, end: this.pos };\n\t\t\t}\n\t\t\tif (keywordType === \"FALSE\") {\n\t\t\t\treturn { type: \"FALSE\", value: false, start, end: this.pos };\n\t\t\t}\n\t\t\treturn { type: keywordType, value: lower, start, end: this.pos };\n\t\t}\n\n\t\treturn { type: \"IDENT\", value: ident, start, end: this.pos };\n\t}\n\n\t/**\n\t * Get the next token\n\t */\n\tnext(): Token {\n\t\tthis.skipWhitespaceAndComments();\n\n\t\tif (this.pos >= this.length) {\n\t\t\treturn { type: \"EOF\", value: \"\", start: this.pos, end: this.pos };\n\t\t}\n\n\t\tconst start = this.pos;\n\t\tconst char = this.peek();\n\n\t\t// Single character tokens\n\t\tswitch (char) {\n\t\t\tcase \"(\":\n\t\t\t\tthis.advance();\n\t\t\t\treturn { type: \"LPAREN\", value: \"(\", start, end: this.pos };\n\t\t\tcase \")\":\n\t\t\t\tthis.advance();\n\t\t\t\treturn { type: \"RPAREN\", value: \")\", start, end: this.pos };\n\t\t\tcase \"[\":\n\t\t\t\tthis.advance();\n\t\t\t\treturn { type: \"LBRACKET\", value: \"[\", start, end: this.pos };\n\t\t\tcase \"]\":\n\t\t\t\tthis.advance();\n\t\t\t\treturn { type: \"RBRACKET\", value: \"]\", start, end: this.pos };\n\t\t\tcase \",\":\n\t\t\t\tthis.advance();\n\t\t\t\treturn { type: \"COMMA\", value: \",\", start, end: this.pos };\n\t\t\tcase \"?\":\n\t\t\t\tthis.advance();\n\t\t\t\treturn { type: \"QUESTION\", value: \"?\", start, end: this.pos };\n\t\t}\n\n\t\t// Two-character operators (check these before single-char versions)\n\t\tif (char === \"!\" && this.peekNext() === \"=\") {\n\t\t\tthis.advance();\n\t\t\tthis.advance();\n\t\t\treturn { type: \"NEQ\", value: \"!=\", start, end: this.pos };\n\t\t}\n\t\tif (char === \"!\" && this.peekNext() === \":\") {\n\t\t\tthis.advance();\n\t\t\tthis.advance();\n\t\t\treturn { type: \"NOT_COLON\", value: \"!:\", start, end: this.pos };\n\t\t}\n\t\tif (char === \">\" && this.peekNext() === \"=\") {\n\t\t\tthis.advance();\n\t\t\tthis.advance();\n\t\t\treturn { type: \"GTE\", value: \">=\", start, end: this.pos };\n\t\t}\n\t\tif (char === \"<\" && this.peekNext() === \"=\") {\n\t\t\tthis.advance();\n\t\t\tthis.advance();\n\t\t\treturn { type: \"LTE\", value: \"<=\", start, end: this.pos };\n\t\t}\n\t\tif (char === \".\" && this.peekNext() === \".\") {\n\t\t\tthis.advance();\n\t\t\tthis.advance();\n\t\t\treturn { type: \"DOTDOT\", value: \"..\", start, end: this.pos };\n\t\t}\n\n\t\t// Single character operators\n\t\tswitch (char) {\n\t\t\tcase \".\":\n\t\t\t\tthis.advance();\n\t\t\t\treturn { type: \"DOT\", value: \".\", start, end: this.pos };\n\t\t\tcase \"=\":\n\t\t\t\tthis.advance();\n\t\t\t\treturn { type: \"EQ\", value: \"=\", start, end: this.pos };\n\t\t\tcase \">\":\n\t\t\t\tthis.advance();\n\t\t\t\treturn { type: \"GT\", value: \">\", start, end: this.pos };\n\t\t\tcase \"<\":\n\t\t\t\tthis.advance();\n\t\t\t\treturn { type: \"LT\", value: \"<\", start, end: this.pos };\n\t\t\tcase \"~\":\n\t\t\t\tthis.advance();\n\t\t\t\treturn { type: \"LIKE\", value: \"~\", start, end: this.pos };\n\t\t\tcase \":\":\n\t\t\t\tthis.advance();\n\t\t\t\treturn { type: \"COLON\", value: \":\", start, end: this.pos };\n\t\t}\n\n\t\t// String literal\n\t\tif (char === '\"') {\n\t\t\treturn this.readString();\n\t\t}\n\n\t\t// Number (including negative numbers)\n\t\tif (/[0-9]/.test(char) || (char === \"-\" && /[0-9]/.test(this.peekNext()))) {\n\t\t\treturn this.readNumber();\n\t\t}\n\n\t\t// Identifier or keyword\n\t\tif (/[a-zA-Z_]/.test(char)) {\n\t\t\treturn this.readIdentifier();\n\t\t}\n\n\t\tthrow new LexerError(`Unexpected character: '${char}'`, this.pos);\n\t}\n}\n",
"/**\n * Recursive Descent Parser for Filtron\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 * Recursive descent parser for Filtron queries\n */\nclass Parser {\n\tprivate lexer: Lexer;\n\tprivate current: Token;\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\tthis.current = this.lexer.next();\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 * Check if current token matches any of the given types\n\t */\n\tprivate checkAny(...types: TokenType[]): boolean {\n\t\treturn types.includes(this.current.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 (lowest precedence)\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(); // consume OR\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(); // consume AND\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(); // consume NOT\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(); // consume (\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\n\t\t// Exists check with ?\n\t\tif (this.check(\"QUESTION\")) {\n\t\t\tthis.advance(); // consume ?\n\t\t\treturn { type: \"exists\", field } as ExistsExpression;\n\t\t}\n\n\t\t// Exists check with EXISTS keyword\n\t\tif (this.check(\"EXISTS\")) {\n\t\t\tthis.advance(); // consume EXISTS\n\t\t\treturn { type: \"exists\", field } as ExistsExpression;\n\t\t}\n\n\t\t// OneOf: field : [values]\n\t\tif (this.check(\"COLON\") && this.peekNextIsLBracket()) {\n\t\t\tthis.advance(); // consume :\n\t\t\treturn this.parseOneOfArray(field, \"oneOf\");\n\t\t}\n\n\t\t// NotOneOf: field !: [values]\n\t\tif (this.check(\"NOT_COLON\")) {\n\t\t\tthis.advance(); // consume !:\n\t\t\treturn this.parseOneOfArray(field, \"notOneOf\");\n\t\t}\n\n\t\t// Comparison with operator\n\t\tif (this.isComparisonOperator()) {\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(); // consume ..\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 { type: \"comparison\", field, operator, value } 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\t * Note: We manually save/restore lexer state because this.current is already\n\t * one token ahead of the lexer's position, and we need to peek further ahead.\n\t */\n\tprivate peekNextIsLBracket(): boolean {\n\t\tconst savedPos = this.lexer[\"pos\"];\n\t\tconst savedCurrent = this.current;\n\t\tconst next = this.lexer.next();\n\t\tthis.lexer[\"pos\"] = savedPos;\n\t\tthis.current = savedCurrent;\n\t\treturn next.type === \"LBRACKET\";\n\t}\n\n\t/**\n\t * Check if current token is a comparison operator\n\t */\n\tprivate isComparisonOperator(): boolean {\n\t\treturn this.checkAny(\"EQ\", \"NEQ\", \"GT\", \"GTE\", \"LT\", \"LTE\", \"LIKE\", \"COLON\");\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\t// String literal\n\t\tif (this.check(\"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 (this.check(\"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 (this.check(\"TRUE\")) {\n\t\t\tthis.advance();\n\t\t\treturn { type: \"boolean\", value: true };\n\t\t}\n\t\tif (this.check(\"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 (this.check(\"IDENT\")) {\n\t\t\tconst first = this.advance();\n\t\t\tlet value = first.value as string;\n\n\t\t\twhile (this.check(\"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 ${this.current.type}`, 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 * Filtron Parser\n *\n * High-performance recursive descent parser for Filtron query language.\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 * Result of a parse operation - either success or error\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"
],
"mappings": "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",
"debugId": "D0558EABEFF0FABB64756E2164756E21",
"names": []
}
import type {
ASTNode,
ComparisonExpression,
BooleanFieldExpression,
AndExpression,
OrExpression,
NotExpression,
ExistsExpression,
OneOfExpression,
NotOneOfExpression,
RangeExpression,
} from "./types";
/**
* Fast path: Parse simple comparison expression
* Handles: field = value, field > 123, nested.field != "test"
*
* Returns null if pattern doesn't match or value is too complex
*/
export declare function parseSimpleComparison(query: string): ComparisonExpression | null;
/**
* Fast path: Parse simple boolean field expression
* Handles: verified, user.premium, active
*
* Returns null if pattern doesn't match or is a keyword
*/
export declare function parseSimpleBooleanField(query: string): BooleanFieldExpression | null;
/**
* Fast path: Parse exists expression with ? operator
* Handles: email?, user.profile.avatar?
*
* Returns null if pattern doesn't match
*/
export declare function parseExistsQuestion(query: string): ExistsExpression | null;
/**
* Fast path: Parse exists expression with exists keyword
* Handles: email exists, user.profile.avatar EXISTS
*
* Returns null if pattern doesn't match
*/
export declare function parseExistsKeyword(query: string): ExistsExpression | null;
/**
* Fast path: Parse oneOf expression
* Handles: status : ["active", "pending"], role : [1, 2, 3]
*
* Returns null if pattern doesn't match or values are complex
*/
export declare function parseOneOf(query: string): OneOfExpression | null;
/**
* Fast path: Parse notOneOf expression
* Handles: status !: ["banned", "deleted"], role !: [0]
*
* Returns null if pattern doesn't match or values are complex
*/
export declare function parseNotOneOf(query: string): NotOneOfExpression | null;
/**
* Fast path: Parse range expression
* Handles: age = 18..65, price = 0..100, score = -10..10
*
* Returns null if pattern doesn't match
*/
export declare function parseRange(query: string): RangeExpression | null;
/**
* Fast path: Parse NOT expression (single negation)
* Handles: NOT verified, NOT (field = value), NOT status : ["active"]
*
* Returns null if expression is too complex
*/
export declare function parseSimpleNot(query: string): NotExpression | null;
/**
* Fast path: Parse simple AND expression
* Handles: expr1 AND expr2 (where both are simple expressions)
* Also handles chains: expr1 AND expr2 AND expr3 (up to 5 terms for performance)
*
* Returns null if pattern doesn't match or expressions are complex
*/
export declare function parseSimpleAnd(query: string): AndExpression | null;
/**
* Fast path: Parse simple OR expression
* Handles: expr1 OR expr2 (where both are simple expressions)
* Also handles chains: expr1 OR expr2 OR expr3 (up to 5 terms for performance)
*
* Returns null if pattern doesn't match or expressions are complex
*/
export declare function parseSimpleOr(query: string): OrExpression | null;
/**
* Fast path: Try to parse query using optimized fast paths
*
* Returns null if no fast path matches (fallback to full Ohm.js parser)
*
*/
export declare function tryFastPath(query: string): ASTNode | null;
//# sourceMappingURL=fast-path.d.ts.map
{"version":3,"file":"fast-path.d.ts","sourceRoot":"","sources":["../../src/fast-path.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,OAAO,EACP,oBAAoB,EACpB,sBAAsB,EACtB,aAAa,EACb,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,eAAe,EAGf,MAAM,SAAS,CAAC;AAmRjB;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI,CAgChF;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,sBAAsB,GAAG,IAAI,CAkBpF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAmB1E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAmBzE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CA2BhE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CA2BtE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CA2BhE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CA6BlE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAoDlE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CA0DhE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CA0GzD"}
/**
* Lexer for Filtron query language
*
* Tokenizes input strings into a stream of tokens for the parser.
*/
/**
* Token types produced by the lexer
*/
export type TokenType = "LPAREN" | "RPAREN" | "LBRACKET" | "RBRACKET" | "COMMA" | "QUESTION" | "DOT" | "DOTDOT" | "AND" | "OR" | "NOT" | "EXISTS" | "TRUE" | "FALSE" | "EQ" | "NEQ" | "GT" | "GTE" | "LT" | "LTE" | "LIKE" | "COLON" | "NOT_COLON" | "STRING" | "NUMBER" | "IDENT" | "EOF";
/**
* A token produced by the lexer
*/
export interface Token {
type: TokenType;
value: string | number | boolean;
start: number;
end: number;
}
/**
* Lexer error with position information
*/
export declare class LexerError extends Error {
position: number;
constructor(message: string, position: number);
}
/**
* Lexer for tokenizing Filtron query strings
*/
export declare class Lexer {
private pos;
private readonly input;
private readonly length;
constructor(input: string);
/**
* Get the current character without advancing
*/
private peek;
/**
* Get the next character without advancing
*/
private peekNext;
/**
* Advance and return the current character
*/
private advance;
/**
* Skip whitespace and comments
*/
private skipWhitespaceAndComments;
/**
* Read a string literal (double-quoted)
*/
private readString;
/**
* Read a number literal (integer or float, possibly negative)
*/
private readNumber;
/**
* Read an identifier or keyword
*/
private readIdentifier;
/**
* Get the next token
*/
next(): Token;
}
//# sourceMappingURL=lexer.d.ts.map
{"version":3,"file":"lexer.d.ts","sourceRoot":"","sources":["../../src/lexer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,MAAM,SAAS,GAElB,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,UAAU,GAEV,OAAO,GACP,UAAU,GACV,KAAK,GACL,QAAQ,GAER,KAAK,GACL,IAAI,GACJ,KAAK,GACL,QAAQ,GACR,MAAM,GACN,OAAO,GAEP,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,KAAK,GACL,MAAM,GACN,OAAO,GACP,WAAW,GAEX,QAAQ,GACR,QAAQ,GACR,OAAO,GAEP,KAAK,CAAC;AAET;;GAEG;AACH,MAAM,WAAW,KAAK;IACrB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACZ;AAcD;;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,IAAI;IAIZ;;OAEG;IACH,OAAO,CAAC,QAAQ;IAIhB;;OAEG;IACH,OAAO,CAAC,OAAO;IAIf;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAwBjC;;OAEG;IACH,OAAO,CAAC,UAAU;IA6ClB;;OAEG;IACH,OAAO,CAAC,UAAU;IA0BlB;;OAEG;IACH,OAAO,CAAC,cAAc;IA6BtB;;OAEG;IACH,IAAI,IAAI,KAAK;CAkGb"}
/**
* Recursive Descent Parser for Filtron
*
* Grammar (in order of precedence, lowest to highest):
*
* Query = OrExpression
* OrExpression = AndExpression (OR AndExpression)*
* AndExpression = NotExpression (AND NotExpression)*
* NotExpression = NOT NotExpression | PrimaryExpression
* PrimaryExpression = '(' OrExpression ')' | FieldExpression
* FieldExpression = FieldName ('?' | EXISTS | ComparisonOp Value RangeSuffix? | OneOfOp '[' Values ']')?
* FieldName = IDENT ('.' IDENT)*
* Value = STRING | NUMBER | BOOLEAN | DottedIdent
* Values = Value (',' Value)*
* RangeSuffix = '..' NUMBER
*/
import type { ASTNode } from "./types";
/**
* Parser error with position information
*/
export declare class ParseError extends Error {
position: number;
constructor(message: string, position: number);
}
/**
* Parse a Filtron query string into an AST
*
* @param input - The query string to parse
* @returns The parsed AST
* @throws ParseError if the query is invalid
*/
export declare function parseQuery(input: string): ASTNode;
//# sourceMappingURL=rd-parser.d.ts.map
{"version":3,"file":"rd-parser.d.ts","sourceRoot":"","sources":["../../src/rd-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EACX,OAAO,EASP,MAAM,SAAS,CAAC;AAGjB;;GAEG;AACH,qBAAa,UAAW,SAAQ,KAAK;IAG5B,QAAQ,EAAE,MAAM;gBADvB,OAAO,EAAE,MAAM,EACR,QAAQ,EAAE,MAAM;CAKxB;AA8UD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGjD"}
+6
-59

@@ -1,60 +0,7 @@

import{makeRecipe as m}from"ohm-js";var x=m(["grammar",{source:`Filtron {
Query = OrExpression
var I={and:"AND",or:"OR",not:"NOT",exists:"EXISTS",true:"TRUE",false:"FALSE"};class x extends Error{position;constructor(O,V){super(O);this.position=V;this.name="LexerError"}}class C{pos=0;input;length;constructor(O){this.input=O,this.length=O.length}peek(){return this.pos<this.length?this.input[this.pos]:""}peekNext(){return this.pos+1<this.length?this.input[this.pos+1]:""}advance(){return this.pos<this.length?this.input[this.pos++]:""}skipWhitespaceAndComments(){while(this.pos<this.length){let O=this.peek();if(O===" "||O==="\t"||O===`
`||O==="\r"){this.advance();continue}if(O==="/"&&this.peekNext()==="/"){this.advance(),this.advance();while(this.pos<this.length&&this.peek()!==`
`)this.advance();continue}break}}readString(){let O=this.pos;this.advance();let V="";while(this.pos<this.length){let N=this.peek();if(N==='"')return this.advance(),{type:"STRING",value:V,start:O,end:this.pos};if(N==="\\"){this.advance();let A=this.advance();switch(A){case"n":V+=`
`;break;case"t":V+="\t";break;case"r":V+="\r";break;case"\\":V+="\\";break;case'"':V+='"';break;default:V+=A}continue}V+=this.advance()}throw new x("Unterminated string literal",O)}readNumber(){let O=this.pos,V="";if(this.peek()==="-")V+=this.advance();while(/[0-9]/.test(this.peek()))V+=this.advance();if(this.peek()==="."&&/[0-9]/.test(this.peekNext())){V+=this.advance();while(/[0-9]/.test(this.peek()))V+=this.advance();return{type:"NUMBER",value:parseFloat(V),start:O,end:this.pos}}return{type:"NUMBER",value:parseInt(V,10),start:O,end:this.pos}}readIdentifier(){let O=this.pos,V="";while(this.pos<this.length){let M=this.peek();if(/[a-zA-Z0-9_]/.test(M))V+=this.advance();else break}let N=V.toLowerCase(),A=I[N];if(A){if(A==="TRUE")return{type:"TRUE",value:!0,start:O,end:this.pos};if(A==="FALSE")return{type:"FALSE",value:!1,start:O,end:this.pos};return{type:A,value:N,start:O,end:this.pos}}return{type:"IDENT",value:V,start:O,end:this.pos}}next(){if(this.skipWhitespaceAndComments(),this.pos>=this.length)return{type:"EOF",value:"",start:this.pos,end:this.pos};let O=this.pos,V=this.peek();switch(V){case"(":return this.advance(),{type:"LPAREN",value:"(",start:O,end:this.pos};case")":return this.advance(),{type:"RPAREN",value:")",start:O,end:this.pos};case"[":return this.advance(),{type:"LBRACKET",value:"[",start:O,end:this.pos};case"]":return this.advance(),{type:"RBRACKET",value:"]",start:O,end:this.pos};case",":return this.advance(),{type:"COMMA",value:",",start:O,end:this.pos};case"?":return this.advance(),{type:"QUESTION",value:"?",start:O,end:this.pos}}if(V==="!"&&this.peekNext()==="=")return this.advance(),this.advance(),{type:"NEQ",value:"!=",start:O,end:this.pos};if(V==="!"&&this.peekNext()===":")return this.advance(),this.advance(),{type:"NOT_COLON",value:"!:",start:O,end:this.pos};if(V===">"&&this.peekNext()==="=")return this.advance(),this.advance(),{type:"GTE",value:">=",start:O,end:this.pos};if(V==="<"&&this.peekNext()==="=")return this.advance(),this.advance(),{type:"LTE",value:"<=",start:O,end:this.pos};if(V==="."&&this.peekNext()===".")return this.advance(),this.advance(),{type:"DOTDOT",value:"..",start:O,end:this.pos};switch(V){case".":return this.advance(),{type:"DOT",value:".",start:O,end:this.pos};case"=":return this.advance(),{type:"EQ",value:"=",start:O,end:this.pos};case">":return this.advance(),{type:"GT",value:">",start:O,end:this.pos};case"<":return this.advance(),{type:"LT",value:"<",start:O,end:this.pos};case"~":return this.advance(),{type:"LIKE",value:"~",start:O,end:this.pos};case":":return this.advance(),{type:"COLON",value:":",start:O,end:this.pos}}if(V==='"')return this.readString();if(/[0-9]/.test(V)||V==="-"&&/[0-9]/.test(this.peekNext()))return this.readNumber();if(/[a-zA-Z_]/.test(V))return this.readIdentifier();throw new x(`Unexpected character: '${V}'`,this.pos)}}class B extends Error{position;constructor(O,V){super(O);this.position=V;this.name="ParseError"}}class z{lexer;current;constructor(O){this.lexer=new C(O),this.current=this.lexer.next()}advance(){let O=this.current;return this.current=this.lexer.next(),O}check(O){return this.current.type===O}checkAny(...O){return O.includes(this.current.type)}expect(O,V){if(this.current.type!==O){let N=V??`Expected ${O}, got ${this.current.type}`;throw new B(N,this.current.start)}return this.advance()}parse(){if(this.check("EOF"))throw new B("Empty query",0);let O=this.parseOrExpression();if(!this.check("EOF"))throw new B(`Unexpected token: ${this.current.type}`,this.current.start);return O}parseOrExpression(){let O=this.parseAndExpression();while(this.check("OR")){this.advance();let V=this.parseAndExpression();O={type:"or",left:O,right:V}}return O}parseAndExpression(){let O=this.parseNotExpression();while(this.check("AND")){this.advance();let V=this.parseNotExpression();O={type:"and",left:O,right:V}}return O}parseNotExpression(){if(this.check("NOT"))return this.advance(),{type:"not",expression:this.parseNotExpression()};return this.parsePrimaryExpression()}parsePrimaryExpression(){if(this.check("LPAREN")){this.advance();let O=this.parseOrExpression();return this.expect("RPAREN","Expected closing parenthesis"),O}return this.parseFieldExpression()}parseFieldExpression(){let O=this.parseFieldName();if(this.check("QUESTION"))return this.advance(),{type:"exists",field:O};if(this.check("EXISTS"))return this.advance(),{type:"exists",field:O};if(this.check("COLON")&&this.peekNextIsLBracket())return this.advance(),this.parseOneOfArray(O,"oneOf");if(this.check("NOT_COLON"))return this.advance(),this.parseOneOfArray(O,"notOneOf");if(this.isComparisonOperator()){let V=this.advance(),N=this.tokenToOperator(V);if(N==="="&&this.check("NUMBER")){let j=this.advance().value;if(this.check("DOTDOT")){this.advance();let H=this.expect("NUMBER","Expected number after '..'").value;return{type:"range",field:O,min:j,max:H}}return{type:"comparison",field:O,operator:N,value:{type:"number",value:j}}}let A=this.parseValue();return{type:"comparison",field:O,operator:N,value:A}}return{type:"booleanField",field:O}}peekNextIsLBracket(){let O=this.lexer.pos,V=this.current,N=this.lexer.next();return this.lexer.pos=O,this.current=V,N.type==="LBRACKET"}isComparisonOperator(){return this.checkAny("EQ","NEQ","GT","GTE","LT","LTE","LIKE","COLON")}tokenToOperator(O){switch(O.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 B(`Invalid operator: ${O.type}`,O.start)}}parseFieldName(){let V=this.expect("IDENT","Expected field name").value;while(this.check("DOT")){this.advance();let N=this.expect("IDENT","Expected identifier after '.'");V+="."+N.value}return V}parseOneOfArray(O,V){this.expect("LBRACKET","Expected '[' after operator");let N=[];if(!this.check("RBRACKET")){N.push(this.parseValue());while(this.check("COMMA"))this.advance(),N.push(this.parseValue())}if(this.expect("RBRACKET","Expected ']' to close array"),N.length===0)throw new B("Array cannot be empty",this.current.start);return{type:V,field:O,values:N}}parseValue(){if(this.check("STRING"))return{type:"string",value:this.advance().value};if(this.check("NUMBER"))return{type:"number",value:this.advance().value};if(this.check("TRUE"))return this.advance(),{type:"boolean",value:!0};if(this.check("FALSE"))return this.advance(),{type:"boolean",value:!1};if(this.check("IDENT")){let V=this.advance().value;while(this.check("DOT")){this.advance();let N=this.expect("IDENT","Expected identifier after '.'");V+="."+N.value}return{type:"identifier",value:V}}throw new B(`Expected value, got ${this.current.type}`,this.current.start)}}function F(O){return new z(O).parse()}var G=(O)=>{try{return{success:!0,ast:F(O)}}catch(V){let N;if(V instanceof B||V instanceof x)N=V.message;else if(V instanceof Error)N=V.message;else N=String(V);return{success:!1,error:N,message:N}}},J=(O)=>{let V=G(O);if(V.success)return V.ast;throw Error(`Failed to parse Filtron query: ${V.error}`)};export{J as parseOrThrow,G as parse};
OrExpression = AndExpression (or AndExpression)*
AndExpression = NotExpression (and NotExpression)*
NotExpression = not NotExpression -- negation
| PrimaryExpression
PrimaryExpression = "(" OrExpression ")" -- parens
| FieldExpression
FieldExpression = FieldName "?" -- existsQuestion
| FieldName exists -- existsKeyword
| FieldName notOneOfOp "[" NonemptyListOf<Value, ","> "]" -- notOneOf
| FieldName oneOfOp "[" NonemptyListOf<Value, ","> "]" -- oneOf
| FieldName ComparisonOp Value -- comparison
| FieldName -- booleanField
FieldName = ident ("." ident)*
oneOfOp = ":"
notOneOfOp = "!:"
ComparisonOp = "!=" | ">=" | "<=" | "=" | "~" | ">" | "<" | ":"
Value = stringLiteral
| numberLiteral
| booleanLiteral
| ident ("." ident)* -- dottedIdent
| ident -- simpleIdent
stringLiteral = "\\"" stringChar* "\\""
stringChar = ~("\\"" | "\\\\") any -- nonEscaped
| "\\\\" any -- escaped
numberLiteral = "-"? digit+ "." digit+ -- float
| "-"? digit+ -- int
booleanLiteral = true | false
ident = ~keyword identStart identPart*
identStart = letter | "_"
identPart = alnum | "_"
// Keywords (case-insensitive)
keyword = or | and | not | exists | true | false
or = caseInsensitive<"or"> ~identPart
and = caseInsensitive<"and"> ~identPart
not = caseInsensitive<"not"> ~identPart
exists = caseInsensitive<"exists"> ~identPart
true = caseInsensitive<"true"> ~identPart
false = caseInsensitive<"false"> ~identPart
// Whitespace
space += comment
comment = "//" (~"\\n" any)*
}`},"Filtron",null,"Query",{Query:["define",{sourceInterval:[12,32]},null,[],["app",{sourceInterval:[20,32]},"OrExpression",[]]],OrExpression:["define",{sourceInterval:[36,84]},null,[],["seq",{sourceInterval:[51,84]},["app",{sourceInterval:[51,64]},"AndExpression",[]],["star",{sourceInterval:[65,84]},["seq",{sourceInterval:[66,82]},["app",{sourceInterval:[66,68]},"or",[]],["app",{sourceInterval:[69,82]},"AndExpression",[]]]]]],AndExpression:["define",{sourceInterval:[88,138]},null,[],["seq",{sourceInterval:[104,138]},["app",{sourceInterval:[104,117]},"NotExpression",[]],["star",{sourceInterval:[118,138]},["seq",{sourceInterval:[119,136]},["app",{sourceInterval:[119,122]},"and",[]],["app",{sourceInterval:[123,136]},"NotExpression",[]]]]]],NotExpression_negation:["define",{sourceInterval:[158,187]},null,[],["seq",{sourceInterval:[158,175]},["app",{sourceInterval:[158,161]},"not",[]],["app",{sourceInterval:[162,175]},"NotExpression",[]]]],NotExpression:["define",{sourceInterval:[142,223]},null,[],["alt",{sourceInterval:[158,223]},["app",{sourceInterval:[158,175]},"NotExpression_negation",[]],["app",{sourceInterval:[206,223]},"PrimaryExpression",[]]]],PrimaryExpression_parens:["define",{sourceInterval:[247,277]},null,[],["seq",{sourceInterval:[247,267]},["terminal",{sourceInterval:[247,250]},"("],["app",{sourceInterval:[251,263]},"OrExpression",[]],["terminal",{sourceInterval:[264,267]},")"]]],PrimaryExpression:["define",{sourceInterval:[227,315]},null,[],["alt",{sourceInterval:[247,315]},["app",{sourceInterval:[247,267]},"PrimaryExpression_parens",[]],["app",{sourceInterval:[300,315]},"FieldExpression",[]]]],FieldExpression_existsQuestion:["define",{sourceInterval:[337,368]},null,[],["seq",{sourceInterval:[337,350]},["app",{sourceInterval:[337,346]},"FieldName",[]],["terminal",{sourceInterval:[347,350]},"?"]]],FieldExpression_existsKeyword:["define",{sourceInterval:[389,422]},null,[],["seq",{sourceInterval:[389,405]},["app",{sourceInterval:[389,398]},"FieldName",[]],["app",{sourceInterval:[399,405]},"exists",[]]]],FieldExpression_notOneOf:["define",{sourceInterval:[443,510]},null,[],["seq",{sourceInterval:[443,498]},["app",{sourceInterval:[443,452]},"FieldName",[]],["app",{sourceInterval:[453,463]},"notOneOfOp",[]],["terminal",{sourceInterval:[464,467]},"["],["app",{sourceInterval:[468,494]},"NonemptyListOf",[["app",{sourceInterval:[483,488]},"Value",[]],["terminal",{sourceInterval:[490,493]},","]]],["terminal",{sourceInterval:[495,498]},"]"]]],FieldExpression_oneOf:["define",{sourceInterval:[531,592]},null,[],["seq",{sourceInterval:[531,583]},["app",{sourceInterval:[531,540]},"FieldName",[]],["app",{sourceInterval:[541,548]},"oneOfOp",[]],["terminal",{sourceInterval:[549,552]},"["],["app",{sourceInterval:[553,579]},"NonemptyListOf",[["app",{sourceInterval:[568,573]},"Value",[]],["terminal",{sourceInterval:[575,578]},","]]],["terminal",{sourceInterval:[580,583]},"]"]]],FieldExpression_comparison:["define",{sourceInterval:[613,655]},null,[],["seq",{sourceInterval:[613,641]},["app",{sourceInterval:[613,622]},"FieldName",[]],["app",{sourceInterval:[623,635]},"ComparisonOp",[]],["app",{sourceInterval:[636,641]},"Value",[]]]],FieldExpression_booleanField:["define",{sourceInterval:[676,701]},null,[],["app",{sourceInterval:[676,685]},"FieldName",[]]],FieldExpression:["define",{sourceInterval:[319,701]},null,[],["alt",{sourceInterval:[337,701]},["app",{sourceInterval:[337,350]},"FieldExpression_existsQuestion",[]],["app",{sourceInterval:[389,405]},"FieldExpression_existsKeyword",[]],["app",{sourceInterval:[443,498]},"FieldExpression_notOneOf",[]],["app",{sourceInterval:[531,583]},"FieldExpression_oneOf",[]],["app",{sourceInterval:[613,641]},"FieldExpression_comparison",[]],["app",{sourceInterval:[676,685]},"FieldExpression_booleanField",[]]]],FieldName:["define",{sourceInterval:[705,735]},null,[],["seq",{sourceInterval:[717,735]},["app",{sourceInterval:[717,722]},"ident",[]],["star",{sourceInterval:[723,735]},["seq",{sourceInterval:[724,733]},["terminal",{sourceInterval:[724,727]},"."],["app",{sourceInterval:[728,733]},"ident",[]]]]]],oneOfOp:["define",{sourceInterval:[739,752]},null,[],["terminal",{sourceInterval:[749,752]},":"]],notOneOfOp:["define",{sourceInterval:[755,772]},null,[],["terminal",{sourceInterval:[768,772]},"!:"]],ComparisonOp:["define",{sourceInterval:[775,838]},null,[],["alt",{sourceInterval:[790,838]},["terminal",{sourceInterval:[790,794]},"!="],["terminal",{sourceInterval:[797,801]},">="],["terminal",{sourceInterval:[804,808]},"<="],["terminal",{sourceInterval:[811,814]},"="],["terminal",{sourceInterval:[817,820]},"~"],["terminal",{sourceInterval:[823,826]},">"],["terminal",{sourceInterval:[829,832]},"<"],["terminal",{sourceInterval:[835,838]},":"]]],Value_dottedIdent:["define",{sourceInterval:[923,956]},null,[],["seq",{sourceInterval:[923,941]},["app",{sourceInterval:[923,928]},"ident",[]],["star",{sourceInterval:[929,941]},["seq",{sourceInterval:[930,939]},["terminal",{sourceInterval:[930,933]},"."],["app",{sourceInterval:[934,939]},"ident",[]]]]]],Value_simpleIdent:["define",{sourceInterval:[967,987]},null,[],["app",{sourceInterval:[967,972]},"ident",[]]],Value:["define",{sourceInterval:[842,987]},null,[],["alt",{sourceInterval:[850,987]},["app",{sourceInterval:[850,863]},"stringLiteral",[]],["app",{sourceInterval:[874,887]},"numberLiteral",[]],["app",{sourceInterval:[898,912]},"booleanLiteral",[]],["app",{sourceInterval:[923,941]},"Value_dottedIdent",[]],["app",{sourceInterval:[967,972]},"Value_simpleIdent",[]]]],stringLiteral:["define",{sourceInterval:[991,1028]},null,[],["seq",{sourceInterval:[1007,1028]},["terminal",{sourceInterval:[1007,1011]},'"'],["star",{sourceInterval:[1012,1023]},["app",{sourceInterval:[1012,1022]},"stringChar",[]]],["terminal",{sourceInterval:[1024,1028]},'"']]],stringChar_nonEscaped:["define",{sourceInterval:[1044,1076]},null,[],["seq",{sourceInterval:[1044,1062]},["not",{sourceInterval:[1044,1058]},["alt",{sourceInterval:[1046,1057]},["terminal",{sourceInterval:[1046,1050]},'"'],["terminal",{sourceInterval:[1053,1057]},"\\"]]],["app",{sourceInterval:[1059,1062]},"any",[]]]],stringChar_escaped:["define",{sourceInterval:[1092,1111]},null,[],["seq",{sourceInterval:[1092,1100]},["terminal",{sourceInterval:[1092,1096]},"\\"],["app",{sourceInterval:[1097,1100]},"any",[]]]],stringChar:["define",{sourceInterval:[1031,1111]},null,[],["alt",{sourceInterval:[1044,1111]},["app",{sourceInterval:[1044,1062]},"stringChar_nonEscaped",[]],["app",{sourceInterval:[1092,1100]},"stringChar_escaped",[]]]],numberLiteral_float:["define",{sourceInterval:[1131,1162]},null,[],["seq",{sourceInterval:[1131,1153]},["opt",{sourceInterval:[1131,1135]},["terminal",{sourceInterval:[1131,1134]},"-"]],["plus",{sourceInterval:[1136,1142]},["app",{sourceInterval:[1136,1141]},"digit",[]]],["terminal",{sourceInterval:[1143,1146]},"."],["plus",{sourceInterval:[1147,1153]},["app",{sourceInterval:[1147,1152]},"digit",[]]]]],numberLiteral_int:["define",{sourceInterval:[1181,1199]},null,[],["seq",{sourceInterval:[1181,1192]},["opt",{sourceInterval:[1181,1185]},["terminal",{sourceInterval:[1181,1184]},"-"]],["plus",{sourceInterval:[1186,1192]},["app",{sourceInterval:[1186,1191]},"digit",[]]]]],numberLiteral:["define",{sourceInterval:[1115,1199]},null,[],["alt",{sourceInterval:[1131,1199]},["app",{sourceInterval:[1131,1153]},"numberLiteral_float",[]],["app",{sourceInterval:[1181,1192]},"numberLiteral_int",[]]]],booleanLiteral:["define",{sourceInterval:[1203,1232]},null,[],["alt",{sourceInterval:[1220,1232]},["app",{sourceInterval:[1220,1224]},"true",[]],["app",{sourceInterval:[1227,1232]},"false",[]]]],ident:["define",{sourceInterval:[1236,1274]},null,[],["seq",{sourceInterval:[1244,1274]},["not",{sourceInterval:[1244,1252]},["app",{sourceInterval:[1245,1252]},"keyword",[]]],["app",{sourceInterval:[1253,1263]},"identStart",[]],["star",{sourceInterval:[1264,1274]},["app",{sourceInterval:[1264,1273]},"identPart",[]]]]],identStart:["define",{sourceInterval:[1277,1302]},null,[],["alt",{sourceInterval:[1290,1302]},["app",{sourceInterval:[1290,1296]},"letter",[]],["terminal",{sourceInterval:[1299,1302]},"_"]]],identPart:["define",{sourceInterval:[1305,1328]},null,[],["alt",{sourceInterval:[1317,1328]},["app",{sourceInterval:[1317,1322]},"alnum",[]],["terminal",{sourceInterval:[1325,1328]},"_"]]],keyword:["define",{sourceInterval:[1365,1413]},null,[],["alt",{sourceInterval:[1375,1413]},["app",{sourceInterval:[1375,1377]},"or",[]],["app",{sourceInterval:[1380,1383]},"and",[]],["app",{sourceInterval:[1386,1389]},"not",[]],["app",{sourceInterval:[1392,1398]},"exists",[]],["app",{sourceInterval:[1401,1405]},"true",[]],["app",{sourceInterval:[1408,1413]},"false",[]]]],or:["define",{sourceInterval:[1416,1453]},null,[],["seq",{sourceInterval:[1421,1453]},["app",{sourceInterval:[1421,1442]},"caseInsensitive",[["terminal",{sourceInterval:[1437,1441]},"or"]]],["not",{sourceInterval:[1443,1453]},["app",{sourceInterval:[1444,1453]},"identPart",[]]]]],and:["define",{sourceInterval:[1456,1495]},null,[],["seq",{sourceInterval:[1462,1495]},["app",{sourceInterval:[1462,1484]},"caseInsensitive",[["terminal",{sourceInterval:[1478,1483]},"and"]]],["not",{sourceInterval:[1485,1495]},["app",{sourceInterval:[1486,1495]},"identPart",[]]]]],not:["define",{sourceInterval:[1498,1537]},null,[],["seq",{sourceInterval:[1504,1537]},["app",{sourceInterval:[1504,1526]},"caseInsensitive",[["terminal",{sourceInterval:[1520,1525]},"not"]]],["not",{sourceInterval:[1527,1537]},["app",{sourceInterval:[1528,1537]},"identPart",[]]]]],exists:["define",{sourceInterval:[1540,1585]},null,[],["seq",{sourceInterval:[1549,1585]},["app",{sourceInterval:[1549,1574]},"caseInsensitive",[["terminal",{sourceInterval:[1565,1573]},"exists"]]],["not",{sourceInterval:[1575,1585]},["app",{sourceInterval:[1576,1585]},"identPart",[]]]]],true:["define",{sourceInterval:[1588,1629]},null,[],["seq",{sourceInterval:[1595,1629]},["app",{sourceInterval:[1595,1618]},"caseInsensitive",[["terminal",{sourceInterval:[1611,1617]},"true"]]],["not",{sourceInterval:[1619,1629]},["app",{sourceInterval:[1620,1629]},"identPart",[]]]]],false:["define",{sourceInterval:[1632,1675]},null,[],["seq",{sourceInterval:[1640,1675]},["app",{sourceInterval:[1640,1664]},"caseInsensitive",[["terminal",{sourceInterval:[1656,1663]},"false"]]],["not",{sourceInterval:[1665,1675]},["app",{sourceInterval:[1666,1675]},"identPart",[]]]]],space:["extend",{sourceInterval:[1695,1711]},null,[],["app",{sourceInterval:[1704,1711]},"comment",[]]],comment:["define",{sourceInterval:[1714,1741]},null,[],["seq",{sourceInterval:[1724,1741]},["terminal",{sourceInterval:[1724,1728]},"//"],["star",{sourceInterval:[1729,1741]},["seq",{sourceInterval:[1730,1739]},["not",{sourceInterval:[1730,1735]},["terminal",{sourceInterval:[1731,1735]},`
`]],["app",{sourceInterval:[1736,1739]},"any",[]]]]]]}]),I=x;var i={Query(e){return e.toAST()},OrExpression(e,n,s){let a=e.toAST(),l=s.children,t=l.length;for(let r=0;r<t;r++)a={type:"or",left:a,right:l[r].toAST()};return a},AndExpression(e,n,s){let a=e.toAST(),l=s.children,t=l.length;for(let r=0;r<t;r++)a={type:"and",left:a,right:l[r].toAST()};return a},NotExpression_negation(e,n){return{type:"not",expression:n.toAST()}},NotExpression(e){return e.toAST()},PrimaryExpression_parens(e,n,s){return n.toAST()},PrimaryExpression(e){return e.toAST()},FieldExpression_existsQuestion(e,n){return{type:"exists",field:e.toAST()}},FieldExpression_existsKeyword(e,n){return{type:"exists",field:e.toAST()}},FieldExpression_notOneOf(e,n,s,a,l){let r=a.asIteration().children,p=r.length,u=Array.from({length:p});for(let o=0;o<p;o++)u[o]=r[o].toAST();return{type:"notOneOf",field:e.toAST(),values:u}},FieldExpression_oneOf(e,n,s,a,l){let r=a.asIteration().children,p=r.length,u=Array.from({length:p});for(let o=0;o<p;o++)u[o]=r[o].toAST();return{type:"oneOf",field:e.toAST(),values:u}},FieldExpression_comparison(e,n,s){return{type:"comparison",field:e.toAST(),operator:n.sourceString,value:s.toAST()}},FieldExpression_booleanField(e){return{type:"booleanField",field:e.toAST()}},FieldName(e,n,s){let a=s.children,l=a.length;if(l===0)return e.sourceString;let t=e.sourceString;for(let r=0;r<l;r++)t+="."+a[r].sourceString;return t},Value(e){return e.toAST()},stringLiteral(e,n,s){let a=n.children,l=a.length;if(l===0)return{type:"string",value:""};let t="";for(let r=0;r<l;r++){let u=a[r].sourceString;if(u.length>1&&u[0]==="\\"){let o=u[1];switch(o){case"n":t+=`
`;break;case"t":t+="\t";break;case"r":t+="\r";break;case"\\":t+="\\";break;case'"':t+='"';break;default:t+=o}}else t+=u}return{type:"string",value:t}},numberLiteral_float(e,n,s,a){return{type:"number",value:Number.parseFloat(e.sourceString+n.sourceString+"."+a.sourceString)}},numberLiteral_int(e,n){return{type:"number",value:Number.parseInt(e.sourceString+n.sourceString,10)}},booleanLiteral(e){return{type:"boolean",value:e.sourceString.toLowerCase()==="true"}},ident(e,n){return{type:"identifier",value:this.sourceString}},Value_dottedIdent(e,n,s){let a=s.children,l=a.length;if(l===0)return{type:"identifier",value:e.sourceString};let t=e.sourceString;for(let r=0;r<l;r++)t+="."+a[r].sourceString;return{type:"identifier",value:t}},Value_simpleIdent(e){return e.toAST()},or(e){return e},and(e){return e},not(e){return e},exists(e){return e},true(e){return e},false(e){return e},oneOfOp(e){return e},notOneOfOp(e){return e},ComparisonOp(e){return e}};var v=I,c=v.createSemantics();c.addOperation("toAST",i);var d=(e)=>{try{let n=v.match(e);if(n.failed())return{success:!1,error:n.message??"Parse error",message:n.message??"Parse error"};return{success:!0,ast:c(n).toAST()}}catch(n){let s=n instanceof Error?n.message:String(n);return{success:!1,error:s,message:s}}},E=(e)=>{let n=d(e);if(n.success)return n.ast;throw Error(`Failed to parse Filtron query: ${n.error}`)};export{E as parseOrThrow,d as parse};
//# debugId=D0558EABEFF0FABB64756E2164756E21
//# sourceMappingURL=index.js.map

@@ -16,3 +16,3 @@ /**

export type { ParseResult, ParseSuccess, ParseError } from "./parser";
export type { ASTNode, Value, ComparisonOperator, OrExpression, AndExpression, NotExpression, ComparisonExpression, OneOfExpression, NotOneOfExpression, ExistsExpression, BooleanFieldExpression, StringValue, NumberValue, BooleanValue, IdentifierValue, } from "./types";
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,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,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"}

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

/**
* Filtron Parser
*
* High-performance recursive descent parser for Filtron query language.
*/
import type { ASTNode } from "./types";

@@ -2,0 +7,0 @@ /**

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

{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAWvC;;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,WA0BrC,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;;;;GAIG;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"}
import type { FiltronActionDict } from "./grammar.ohm-bundle.js";
import type { ASTNode, Value } from "./types";
type SemanticReturnType = ASTNode | Value | Value[] | string | number | [number, number];
/**
* Semantic actions for converting Ohm parse tree to Filtron AST
*/
export declare const semanticActions: FiltronActionDict<ASTNode | Value | Value[] | string>;
//# sourceMappingURL=semantics.d.ts.map
export declare const semanticActions: FiltronActionDict<SemanticReturnType>;
export {};
//# sourceMappingURL=semantics.d.ts.map

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

{"version":3,"file":"semantics.d.ts","sourceRoot":"","sources":["../../src/semantics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,iBAAiB,CAC9C,OAAO,GAAG,KAAK,GAAG,KAAK,EAAE,GAAG,MAAM,CA6RlC,CAAC"}
{"version":3,"file":"semantics.d.ts","sourceRoot":"","sources":["../../src/semantics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,OAAO,EAAmB,KAAK,EAAE,MAAM,SAAS,CAAC;AAG/D,KAAK,kBAAkB,GAAG,OAAO,GAAG,KAAK,GAAG,KAAK,EAAE,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAsBzF;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,iBAAiB,CAAC,kBAAkB,CAuRjE,CAAC"}

@@ -7,3 +7,3 @@ /**

*/
export type ASTNode = OrExpression | AndExpression | NotExpression | ComparisonExpression | OneOfExpression | NotOneOfExpression | ExistsExpression | BooleanFieldExpression;
export type ASTNode = OrExpression | AndExpression | NotExpression | ComparisonExpression | OneOfExpression | NotOneOfExpression | ExistsExpression | BooleanFieldExpression | RangeExpression;
/**

@@ -85,2 +85,12 @@ * Value type - represents literal values in expressions

/**
* Range expression - checks if a field value is between two numbers (inclusive)
* Example: age = 18..65, price = 0..100
*/
export interface RangeExpression {
type: "range";
field: string;
min: number;
max: number;
}
/**
* String value - a quoted string literal

@@ -87,0 +97,0 @@ */

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

{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,OAAO,GAChB,YAAY,GACZ,aAAa,GACb,aAAa,GACb,oBAAoB,GACpB,eAAe,GACf,kBAAkB,GAClB,gBAAgB,GAChB,sBAAsB,CAAC;AAE1B;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,GAAG,eAAe,CAAC;AAE/E;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC3B,GAAG,GACH,IAAI,GACJ,GAAG,GACH,GAAG,GACH,IAAI,GACJ,GAAG,GACH,IAAI,GACJ,GAAG,CAAC;AAEP;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,KAAK,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,KAAK,CAAC;IACZ,UAAU,EAAE,OAAO,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,KAAK,CAAC;CACb;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,EAAE,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,EAAE,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACtC,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACd"}
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,OAAO,GAChB,YAAY,GACZ,aAAa,GACb,aAAa,GACb,oBAAoB,GACpB,eAAe,GACf,kBAAkB,GAClB,gBAAgB,GAChB,sBAAsB,GACtB,eAAe,CAAC;AAEnB;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,GAAG,eAAe,CAAC;AAE/E;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC;AAElF;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,KAAK,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,KAAK,CAAC;IACZ,UAAU,EAAE,OAAO,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,KAAK,CAAC;CACb;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,EAAE,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,EAAE,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACtC,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACd"}
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@filtron/core",
"version": "1.0.0",
"version": "1.1.0",
"description": "A fast, type-safe query language parser for filtering data in real-time APIs",

@@ -12,9 +12,6 @@ "keywords": [

"query-language",
"ast",
"ohm",
"typescript",
"filtering",
"search",
"query-parser",
"sql-where"
"query-parser"
],

@@ -49,14 +46,10 @@ "homepage": "https://github.com/jbergstroem/filtron#readme",

"scripts": {
"bench": "bun --expose-gc run benchmark.ts",
"build": "bun run build:grammar && bun build --minify --splitting --outdir=dist --external ohm-js index.ts && tsc --emitDeclarationOnly --declaration --declarationMap --outDir dist --skipLibCheck",
"build:grammar": "bun run ohm generateBundles --withTypes --esm src/grammar.ohm",
"bench": "bun run build && bun --expose-gc run benchmark.ts",
"build": "bun build --minify --splitting --sourcemap=linked --outdir=dist index.ts && tsc --emitDeclarationOnly --declaration --declarationMap --outDir dist --skipLibCheck",
"prepublishOnly": "bun run build && bun test",
"test": "bun test"
"test": "bun test",
"typecheck": "tsc --noemit"
},
"dependencies": {
"ohm-js": "17.2.1"
},
"devDependencies": {
"@ohm-js/cli": "2.0.1",
"@types/bun": "1.3.2",
"@types/bun": "1.3.3",
"mitata": "1.0.34",

@@ -77,3 +70,3 @@ "typescript": "5.9.3"

},
"packageManager": "bun@1.3.2"
"packageManager": "bun@1.3.3"
}
+17
-51

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

# Filtron
# @filtron/core
Fast, type-safe query language parser for filtering data in real-time APIs. Built with [Ohm.js](https://ohmjs.org/).
Fast, type-safe query language parser for filtering data in real-time APIs.

@@ -10,6 +10,5 @@ [![npm version](https://img.shields.io/npm/v/@filtron/core.svg)](https://www.npmjs.com/package/@filtron/core)

- **Fast**: ~50μs parse time, 18K+ parses/sec
- **Small**: 15 KB minified, 56 KB installed
- **Fast**: High-performance recursive descent parser — 250ns-3μs per query
- **Small**: ~8 KB minified, zero runtime dependencies
- **Type-safe**: Full TypeScript support with discriminated union AST
- **Snack-sized dependencies**: Only `ohm-js` runtime required

@@ -73,2 +72,6 @@ ## Installation

// Range expressions
parse("age = 18..65");
parse("price = 9.99..99.99");
// Complex queries

@@ -90,2 +93,3 @@ parse('(role = "admin" OR role = "mod") AND status = "active"');

| `?`, `EXISTS` | Field exists | `email?` |
| `..` | Range | `age = 18..65` |
| `AND`, `OR`, `NOT` | Boolean logic | `a AND b OR c` |

@@ -148,40 +152,12 @@

## Packages
## Performance
### [@filtron/sql](./packages/sql)
Filtron uses a hand-written recursive descent parser optimized for speed:
SQL WHERE clause generator with parameterized queries for safe database filtering.
| Query Type | Parse Time | Throughput |
| ---------- | ------------- | ---------------- |
| Simple | ~250-350ns | 3-4M ops/sec |
| Medium | ~600-1700ns | 600K-1.6M ops/sec |
| Complex | ~1.5-3μs | 350-700K ops/sec |
```typescript
import { parse } from "@filtron/core";
import { toSQL } from "@filtron/sql";
const result = parse('age > 18 AND status = "active"');
if (result.success) {
const { sql, params } = toSQL(result.ast);
// sql: "(age > $1 AND status = $2)"
// params: [18, "active"]
const users = await db.query(`SELECT * FROM users WHERE ${sql}`, params);
}
```
**Features:**
- Parameterized queries (PostgreSQL/DuckDB `$1`, MySQL/SQLite/DuckDB `?`)
- Field name mapping and escaping
- Zero SQL injection risk
- Full TypeScript support
See the [@filtron/sql README](./packages/sql/README.md) for full documentation.
## Performance
```
Parse Time: ~50μs per query
Throughput: 18,755 parses/sec
Startup: <1ms with pre-compiled grammar
Memory: Efficient GC, minimal allocation
```
Run benchmarks: `bun run bench`

@@ -191,3 +167,3 @@

- **[Contributing Guide](./CONTRIBUTING.md)** - Development setup and workflow
- **[Contributing Guide](../../CONTRIBUTING.md)** - Development setup and workflow

@@ -197,11 +173,1 @@ ## Inspiration

The Filtron query language syntax was strongly inspired by [dumbql](https://github.com/tomakado/dumbql).
## License
MIT - See [LICENSE](./LICENSE)
## Links
- **GitHub**: https://github.com/jbergstroem/filtron
- **npm**: https://www.npmjs.com/package/@filtron/core
- **Issues**: https://github.com/jbergstroem/filtron/issues