UNPKG

quis

Version:

A simple DSL for data sorting and filtering

180 lines (165 loc) 5.46 kB
/** * Quis DSL Parser - Main Entry Point * * A lightweight domain-specific language for data sorting and filtering. * Supports key-value pair access, complex boolean expressions, and more. */ import type { Quis, ParseOptions, ParseResult, CustomConditionRegistry, CustomConditionEvaluator, QuitSyntaxError, Expected, Location } from './types.js'; import { Tokenizer } from './tokenizer'; import { Parser } from './parser'; import { Evaluator } from './evaluator'; /** * SyntaxError class for parsing errors */ class QuisSyntaxError extends Error implements QuitSyntaxError { expected: Expected[]; found: string | null; location?: Location; name = 'SyntaxError' as const; constructor(message: string, expected: Expected[], found: string | null, location?: Location) { super(message); this.expected = expected; this.found = found; this.location = location; } format(): string { let result = this.message; if (this.location) { result += ` at line ${this.location.start.line}, column ${this.location.start.column}`; } return result; } } /** * Parse using the AST parser */ function parseExpression(input: string, options: ParseOptions): ParseResult { try { const tokenizer = new Tokenizer(input); const tokens = tokenizer.tokenize(); const parser = new Parser(tokens); const ast = parser.parse(); const evaluator = new Evaluator(options); return evaluator.evaluate(ast); } catch (error) { if (error instanceof Error) { throw new QuisSyntaxError(error.message, [], null); } throw error; } } // Global registry for custom conditions const customConditions: CustomConditionRegistry = {}; /** * Main Quis export with proper typing */ const QuisModule: Quis = { /** * Parse a DSL expression string * @param input - The DSL expression to parse * @param options - Optional parsing configuration * @returns The result of evaluating the expression * * @example * ```typescript * import quis from 'quis'; * * // Simple boolean expression * const result = quis.parse('true && false'); // returns false * * // With variables * const withVars = quis.parse('$user.age > 18', { * values: (name) => name === 'user' ? { age: 25 } : null * }); // returns true * * // With custom conditions * quis.addCustomCondition('contains', (value, expected) => * String(value).includes(String(expected)) * ); * const customResult = quis.parse('$text custom:contains "hello"', { * values: (name) => name === 'text' ? 'hello world' : null * }); // returns true * ``` */ parse: (input: string, options?: ParseOptions): ParseResult => { // Merge global custom conditions with options const mergedOptions: ParseOptions = { ...options, customConditions: { ...customConditions, ...options?.customConditions } }; return parseExpression(input, mergedOptions); }, /** * Enhanced syntax error class for better error handling */ SyntaxError: QuisSyntaxError, /** * Add a custom condition evaluator * @param name - The name of the custom condition * @param evaluator - Function that evaluates the condition * * @example * ```typescript * // Add a custom condition for string contains * quis.addCustomCondition('contains', (value, expected) => * String(value).includes(String(expected)) * ); * * // Use in expressions: $text custom:contains "substring" * ``` */ addCustomCondition: (name: string, evaluator: CustomConditionEvaluator): void => { customConditions[name] = evaluator; }, /** * Remove a custom condition evaluator * @param name - The name of the custom condition to remove * @returns True if the condition was removed, false if it didn't exist */ removeCustomCondition: (name: string): boolean => { if (name in customConditions) { delete customConditions[name]; return true; } return false; }, /** * Get all registered custom conditions * @returns A copy of the custom condition registry */ getCustomConditions: (): CustomConditionRegistry => { return { ...customConditions }; }, /** * Clear all custom conditions */ clearCustomConditions: (): void => { Object.keys(customConditions).forEach(key => { delete customConditions[key]; }); } }; export default QuisModule; // Named exports for convenience and CommonJS compatibility export const parse = QuisModule.parse; export const SyntaxError = QuisModule.SyntaxError; export const addCustomCondition = QuisModule.addCustomCondition; export const removeCustomCondition = QuisModule.removeCustomCondition; export const getCustomConditions = QuisModule.getCustomConditions; export const clearCustomConditions = QuisModule.clearCustomConditions; // Re-export types export type { Quis, Parser, ParseOptions, ParseResult, ValuesCallback, CustomConditionEvaluator, CustomConditionRegistry, Location, Expected, QuitSyntaxError } from './types.js';