UNPKG

jora

Version:

JavaScript object query engine

341 lines (318 loc) 9.56 kB
'use strict'; // Token type constants - using numeric codes for better performance const TOKEN_NUMBER = 0; const TOKEN_STRING = 1; const TOKEN_REGEXP = 2; const TOKEN_LITERAL = 3; const TOKEN_IDENT = 4; const TOKEN_$IDENT = 5; // Special references const TOKEN_AT = 6; // DATA const TOKEN_HASH = 7; // CONTEXT const TOKEN_$ = 8; // CURRENT const TOKEN_$$ = 9; // ARG1 // Keywords const TOKEN_AND = 10; const TOKEN_OR = 11; const TOKEN_NOT = 12; const TOKEN_NO = 13; const TOKEN_IS = 14; const TOKEN_IN = 15; const TOKEN_NOTIN = 16; const TOKEN_HAS = 17; const TOKEN_HASNO = 18; const TOKEN_ORDER = 19; // Method calls const TOKEN_METHOD_OPEN = 20; // METHOD( const TOKEN_$METHOD_OPEN = 21; // $METHOD( // Template tokens const TOKEN_TEMPLATE = 22; const TOKEN_TPL_START = 23; const TOKEN_TPL_CONTINUE = 24; const TOKEN_TPL_END = 25; // Operators const TOKEN_DOT = 26; const TOKEN_DOT_DOT = 27; const TOKEN_DOT_DOT_DOT = 28; const TOKEN_DOT_OPEN_PAREN = 29; const TOKEN_DOT_OPEN_BRACKET = 30; const TOKEN_DOT_DOT_OPEN_PAREN = 31; const TOKEN_PIPE = 32; const TOKEN_ARROW = 33; // => const TOKEN_EQUALS = 34; const TOKEN_NOT_EQUALS = 35; // != const TOKEN_MATCH = 36; // ~= const TOKEN_LESS_THAN = 37; const TOKEN_LESS_THAN_EQUALS = 38; const TOKEN_GREATER_THAN = 39; const TOKEN_GREATER_THAN_EQUALS = 40; const TOKEN_PLUS = 41; const TOKEN_MINUS = 42; const TOKEN_MULTIPLY = 43; const TOKEN_DIVIDE = 44; const TOKEN_MODULO = 45; const TOKEN_NULLISH_COALESCING = 46; // ?? const TOKEN_QUESTION = 47; // Punctuation const TOKEN_OPEN_PAREN = 48; const TOKEN_CLOSE_PAREN = 49; const TOKEN_OPEN_BRACKET = 50; const TOKEN_CLOSE_BRACKET = 51; const TOKEN_OPEN_BRACE = 52; const TOKEN_CLOSE_BRACE = 53; const TOKEN_COMMA = 54; const TOKEN_COLON = 55; const TOKEN_SEMICOLON = 56; // Special - must be last const TOKEN_BAD = 57; const TOKEN_EOF = 58; const TOKEN_MAX = 59; // Token names for debugging and error messages const tokenNames = { [TOKEN_NUMBER]: 'NUMBER', [TOKEN_STRING]: 'STRING', [TOKEN_REGEXP]: 'REGEXP', [TOKEN_LITERAL]: 'LITERAL', [TOKEN_IDENT]: 'IDENT', [TOKEN_$IDENT]: '$IDENT', [TOKEN_AT]: '@', [TOKEN_HASH]: '#', [TOKEN_$]: '$', [TOKEN_$$]: '$$', [TOKEN_AND]: 'AND', [TOKEN_OR]: 'OR', [TOKEN_NOT]: 'NOT', [TOKEN_NO]: 'NO', [TOKEN_IS]: 'IS', [TOKEN_IN]: 'IN', [TOKEN_NOTIN]: 'NOTIN', [TOKEN_HAS]: 'HAS', [TOKEN_HASNO]: 'HASNO', [TOKEN_ORDER]: 'ORDER', [TOKEN_METHOD_OPEN]: 'METHOD(', [TOKEN_$METHOD_OPEN]: '$METHOD(', [TOKEN_TEMPLATE]: 'TEMPLATE', [TOKEN_TPL_START]: 'TPL_START', [TOKEN_TPL_CONTINUE]: 'TPL_CONTINUE', [TOKEN_TPL_END]: 'TPL_END', [TOKEN_DOT]: '.', [TOKEN_DOT_DOT]: '..', [TOKEN_DOT_DOT_DOT]: '...', [TOKEN_DOT_OPEN_PAREN]: '.(', [TOKEN_DOT_OPEN_BRACKET]: '.[', [TOKEN_DOT_DOT_OPEN_PAREN]: '..(', [TOKEN_PIPE]: '|', [TOKEN_ARROW]: '=>', [TOKEN_EQUALS]: '=', [TOKEN_NOT_EQUALS]: '!=', [TOKEN_MATCH]: '~=', [TOKEN_LESS_THAN]: '<', [TOKEN_LESS_THAN_EQUALS]: '<=', [TOKEN_GREATER_THAN]: '>', [TOKEN_GREATER_THAN_EQUALS]: '>=', [TOKEN_PLUS]: '+', [TOKEN_MINUS]: '-', [TOKEN_MULTIPLY]: '*', [TOKEN_DIVIDE]: '/', [TOKEN_MODULO]: '%', [TOKEN_NULLISH_COALESCING]: '??', [TOKEN_QUESTION]: '?', [TOKEN_OPEN_PAREN]: '(', [TOKEN_CLOSE_PAREN]: ')', [TOKEN_OPEN_BRACKET]: '[', [TOKEN_CLOSE_BRACKET]: ']', [TOKEN_OPEN_BRACE]: '{', [TOKEN_CLOSE_BRACE]: '}', [TOKEN_COMMA]: ',', [TOKEN_COLON]: ':', [TOKEN_SEMICOLON]: ';', [TOKEN_BAD]: 'BAD_TOKEN', [TOKEN_EOF]: 'EOF' }; // Bracket balance mappings const BALANCE_TOKEN_PAIR = createTokenTable( TOKEN_OPEN_PAREN, TOKEN_CLOSE_PAREN, // "(" -> ")" TOKEN_DOT_OPEN_PAREN, TOKEN_CLOSE_PAREN, // ".(" -> ")" TOKEN_DOT_DOT_OPEN_PAREN, TOKEN_CLOSE_PAREN, // "..(" -> ")" TOKEN_METHOD_OPEN, TOKEN_CLOSE_PAREN, // "METHOD(" -> ")" TOKEN_$METHOD_OPEN, TOKEN_CLOSE_PAREN, // "$METHOD(" -> ")" TOKEN_OPEN_BRACKET, TOKEN_CLOSE_BRACKET, // "[" -> "]" TOKEN_DOT_OPEN_BRACKET, TOKEN_CLOSE_BRACKET, // ".[" -> "]" TOKEN_OPEN_BRACE, TOKEN_CLOSE_BRACE, // "{" -> "}" TOKEN_TPL_START, TOKEN_TPL_END // "`{" -> "}`" ); // Keyword lookup const KEYWORDS = { 'has no': TOKEN_HASNO, 'not in': TOKEN_NOTIN, 'and': TOKEN_AND, 'or': TOKEN_OR, 'not': TOKEN_NOT, 'has': TOKEN_HAS, 'is': TOKEN_IS, 'in': TOKEN_IN, 'no': TOKEN_NO, 'asc': TOKEN_ORDER, 'ascN': TOKEN_ORDER, 'ascA': TOKEN_ORDER, 'ascNA': TOKEN_ORDER, 'ascAN': TOKEN_ORDER, 'desc': TOKEN_ORDER, 'descN': TOKEN_ORDER, 'descA': TOKEN_ORDER, 'descNA': TOKEN_ORDER, 'descAN': TOKEN_ORDER }; // String to token mapping const STR_TO_TOKEN = { '...': TOKEN_DOT_DOT_DOT, '..(': TOKEN_DOT_DOT_OPEN_PAREN, '..': TOKEN_DOT_DOT, '.(': TOKEN_DOT_OPEN_PAREN, '.[': TOKEN_DOT_OPEN_BRACKET, '=>': TOKEN_ARROW, '!=': TOKEN_NOT_EQUALS, '~=': TOKEN_MATCH, '<=': TOKEN_LESS_THAN_EQUALS, '>=': TOKEN_GREATER_THAN_EQUALS, '??': TOKEN_NULLISH_COALESCING, '@': TOKEN_AT, '#': TOKEN_HASH, '.': TOKEN_DOT, '|': TOKEN_PIPE, '=': TOKEN_EQUALS, '<': TOKEN_LESS_THAN, '>': TOKEN_GREATER_THAN, '+': TOKEN_PLUS, '-': TOKEN_MINUS, '*': TOKEN_MULTIPLY, '/': TOKEN_DIVIDE, '%': TOKEN_MODULO, '?': TOKEN_QUESTION, '(': TOKEN_OPEN_PAREN, ')': TOKEN_CLOSE_PAREN, '[': TOKEN_OPEN_BRACKET, ']': TOKEN_CLOSE_BRACKET, '{': TOKEN_OPEN_BRACE, '}': TOKEN_CLOSE_BRACE, ',': TOKEN_COMMA, ':': TOKEN_COLON, ';': TOKEN_SEMICOLON }; // Keyword tokens — used to determine empty ident range behavior in tolerant mode const KEYWORD_TOKENS = createTokenSet( TOKEN_AND, TOKEN_OR, TOKEN_NOT, TOKEN_NO, TOKEN_IN, TOKEN_NOTIN, TOKEN_HAS, TOKEN_HASNO, TOKEN_IS, TOKEN_ORDER ); const PREVENT_KEYWORD = createTokenSet( TOKEN_DOT, TOKEN_DOT_DOT ); const PREVENT_PRIMITIVE = createTokenSet( TOKEN_NUMBER, TOKEN_STRING, TOKEN_TEMPLATE, TOKEN_TPL_END, TOKEN_REGEXP, TOKEN_LITERAL, TOKEN_IDENT, TOKEN_$$, TOKEN_$IDENT, TOKEN_$, TOKEN_AT, TOKEN_HASH, TOKEN_CLOSE_PAREN, TOKEN_CLOSE_BRACKET, TOKEN_CLOSE_BRACE, TOKEN_DOT ); function createTokenSet(...tokens) { const set = new Int8Array(TOKEN_MAX); for (const token of tokens) { set[token] = 1; } return set; } function createTokenTable(...pairs) { const table = new Int8Array(TOKEN_MAX).fill(-1); for (let i = 0; i < pairs.length; i += 2) { table[pairs[i]] = pairs[i + 1]; } return table; } exports.BALANCE_TOKEN_PAIR = BALANCE_TOKEN_PAIR; exports.KEYWORDS = KEYWORDS; exports.KEYWORD_TOKENS = KEYWORD_TOKENS; exports.PREVENT_KEYWORD = PREVENT_KEYWORD; exports.PREVENT_PRIMITIVE = PREVENT_PRIMITIVE; exports.STR_TO_TOKEN = STR_TO_TOKEN; exports.TOKEN_$ = TOKEN_$; exports.TOKEN_$$ = TOKEN_$$; exports.TOKEN_$IDENT = TOKEN_$IDENT; exports.TOKEN_$METHOD_OPEN = TOKEN_$METHOD_OPEN; exports.TOKEN_AND = TOKEN_AND; exports.TOKEN_ARROW = TOKEN_ARROW; exports.TOKEN_AT = TOKEN_AT; exports.TOKEN_BAD = TOKEN_BAD; exports.TOKEN_CLOSE_BRACE = TOKEN_CLOSE_BRACE; exports.TOKEN_CLOSE_BRACKET = TOKEN_CLOSE_BRACKET; exports.TOKEN_CLOSE_PAREN = TOKEN_CLOSE_PAREN; exports.TOKEN_COLON = TOKEN_COLON; exports.TOKEN_COMMA = TOKEN_COMMA; exports.TOKEN_DIVIDE = TOKEN_DIVIDE; exports.TOKEN_DOT = TOKEN_DOT; exports.TOKEN_DOT_DOT = TOKEN_DOT_DOT; exports.TOKEN_DOT_DOT_DOT = TOKEN_DOT_DOT_DOT; exports.TOKEN_DOT_DOT_OPEN_PAREN = TOKEN_DOT_DOT_OPEN_PAREN; exports.TOKEN_DOT_OPEN_BRACKET = TOKEN_DOT_OPEN_BRACKET; exports.TOKEN_DOT_OPEN_PAREN = TOKEN_DOT_OPEN_PAREN; exports.TOKEN_EOF = TOKEN_EOF; exports.TOKEN_EQUALS = TOKEN_EQUALS; exports.TOKEN_GREATER_THAN = TOKEN_GREATER_THAN; exports.TOKEN_GREATER_THAN_EQUALS = TOKEN_GREATER_THAN_EQUALS; exports.TOKEN_HAS = TOKEN_HAS; exports.TOKEN_HASH = TOKEN_HASH; exports.TOKEN_HASNO = TOKEN_HASNO; exports.TOKEN_IDENT = TOKEN_IDENT; exports.TOKEN_IN = TOKEN_IN; exports.TOKEN_IS = TOKEN_IS; exports.TOKEN_LESS_THAN = TOKEN_LESS_THAN; exports.TOKEN_LESS_THAN_EQUALS = TOKEN_LESS_THAN_EQUALS; exports.TOKEN_LITERAL = TOKEN_LITERAL; exports.TOKEN_MATCH = TOKEN_MATCH; exports.TOKEN_METHOD_OPEN = TOKEN_METHOD_OPEN; exports.TOKEN_MINUS = TOKEN_MINUS; exports.TOKEN_MODULO = TOKEN_MODULO; exports.TOKEN_MULTIPLY = TOKEN_MULTIPLY; exports.TOKEN_NO = TOKEN_NO; exports.TOKEN_NOT = TOKEN_NOT; exports.TOKEN_NOTIN = TOKEN_NOTIN; exports.TOKEN_NOT_EQUALS = TOKEN_NOT_EQUALS; exports.TOKEN_NULLISH_COALESCING = TOKEN_NULLISH_COALESCING; exports.TOKEN_NUMBER = TOKEN_NUMBER; exports.TOKEN_OPEN_BRACE = TOKEN_OPEN_BRACE; exports.TOKEN_OPEN_BRACKET = TOKEN_OPEN_BRACKET; exports.TOKEN_OPEN_PAREN = TOKEN_OPEN_PAREN; exports.TOKEN_OR = TOKEN_OR; exports.TOKEN_ORDER = TOKEN_ORDER; exports.TOKEN_PIPE = TOKEN_PIPE; exports.TOKEN_PLUS = TOKEN_PLUS; exports.TOKEN_QUESTION = TOKEN_QUESTION; exports.TOKEN_REGEXP = TOKEN_REGEXP; exports.TOKEN_SEMICOLON = TOKEN_SEMICOLON; exports.TOKEN_STRING = TOKEN_STRING; exports.TOKEN_TEMPLATE = TOKEN_TEMPLATE; exports.TOKEN_TPL_CONTINUE = TOKEN_TPL_CONTINUE; exports.TOKEN_TPL_END = TOKEN_TPL_END; exports.TOKEN_TPL_START = TOKEN_TPL_START; exports.createTokenSet = createTokenSet; exports.createTokenTable = createTokenTable; exports.tokenNames = tokenNames;