UNPKG

crazy-parser

Version:

A light-weight parser combinator

107 lines (106 loc) 3.85 kB
export const str = input => { if (typeof input != "string") return new TypeError(`Expected string, got ${JSON.stringify(input)}`); return input; }; export const num = (input => { if (typeof input != "number") return new TypeError(`Expected number, got ${JSON.stringify(input)}`); return input; }); export const bool = input => { if (typeof input != "boolean") return new TypeError(`Expected boolean, got ${JSON.stringify(input)}`); return input; }; export const nil = input => { if (input !== null) return new TypeError(`Expected null, got ${JSON.stringify(input)}`); return null; }; export const array = inner => input => { if (!Array.isArray(input)) return new TypeError(`Expected array, got ${JSON.stringify(input)}`); for (let i in input) { const item = input[i]; const result = inner(item); if (result instanceof TypeError) return new TypeError(`Invalid index ${i}: ${result.message}`); } return structuredClone(input); }; export const obj = (inner, fallback) => input => { if (typeof input != "object" || input === null || Array.isArray(input)) return new TypeError(`Expected object, got ${JSON.stringify(input)}`); let _input = input; for (const key in inner) { const validator = inner[key]; if (!(key in _input)) { if (!fallback || !(key in fallback)) return new TypeError(`Missing key: ${key}`); if (input == _input) _input = structuredClone(_input); _input[key] = fallback[key]; continue; } const result = validator(_input[key]); if (result instanceof TypeError) { if (!fallback || !(key in fallback)) return new TypeError(`Invalid key ${key}: ${result.message}`); if (input == _input) _input = structuredClone(_input); _input[key] = fallback[key]; } } return _input; }; export const sequence = (...inners) => input => { if (!Array.isArray(input)) return new TypeError(`Expected tuple, got ${JSON.stringify(input)}`); if (input.length != inners.length) return new TypeError(`Expected tuple of length ${inners.length}, got ${JSON.stringify(input)}`); for (const i in inners) { const validator = inners[i]; const item = input[i]; const result = validator(item); if (result instanceof TypeError) return new TypeError(`Invalid index ${i}: ${result.message}`); } return input; }; export const asum = (...inners) => input => { const errors = []; for (const validator of inners) { const result = validator(input); if (result instanceof TypeError) errors.push(result); else return result; } return new TypeError(`No alternatives matched, got errors: ${errors.map(e => e.message).join("; ")}`); }; export const ands = (...inners) => input => { for (const i in inners) { const validator = inners[i]; const result = validator(input); if (result instanceof TypeError) return new TypeError(`Failed at step ${i}: ${result.message}`); } return input; }; export const eq = value => input => { if (input !== value) return new TypeError(`Expected ${JSON.stringify(value)}, got ${JSON.stringify(input)}`); return value; }; export const where = (validator, predicate, error) => input => { const result = validator(input); if (result instanceof TypeError) return result; if (!predicate(result)) return error ?? new TypeError(`Value did not satisfy predicate, got ${JSON.stringify(result)}`); return result; }; export function lazy(vg) { return (input => vg()(input)); }