UNPKG

estree-toolkit

Version:

Traverser, scope tracker, and more tools for working with ESTree AST

135 lines (134 loc) 4.63 kB
import { aliases } from './aliases.mjs'; export const runValidation = (validateFn, value) => { const errorMsg = validateFn(value); if (errorMsg != null) { throw new Error(errorMsg); } }; export const chain = (...validateFns) => (validateFns.reduce((prevFn, fn) => (val) => prevFn(val) || fn(val))); export const OR = (...validateFns) => (value) => { const errorMsgs = []; for (let i = 0; i < validateFns.length; i++) { const errorMsg = validateFns[i](value); if (errorMsg != null) { errorMsgs.push(errorMsg); } else { break; } } if (errorMsgs.length === validateFns.length) { return `The value is not compatible with the required type.\n\nMessages:\n${errorMsgs.join('\n')}`; } return null; }; /* istanbul ignore next */ export const meaningfulType = (value) => { if (value === null) { return 'null'; } else if (Array.isArray(value)) { return 'array'; } else { return typeof value; } }; export const value = (...types) => { if (types.length === 1) { const type = types[0]; return function validate(value) { if (typeof value !== type) { return `Expected the value to be a \`${type}\` but got a \`${meaningfulType(value)}\`. The value is ${JSON.stringify(value)}.`; } return null; }; } else { return function validate(value) { for (let i = 0; i < types.length; i++) { const type = types[i]; if (typeof value === type || (type === 'null' && value === null)) { return null; } } return `Expected the value to be one of \`${JSON.stringify(types)}\` but got a \`${meaningfulType(value)}\`. The value is ${JSON.stringify(value)}.`; }; } }; const reservedKeywords = new Set(` do if in for let new try var case else enum eval false null NaN this true void with break catch class const super throw while yield delete export import public return static switch typeof default extends finally package private continue debugger function arguments interface protected implements instanceof `.trim().split(/[ \n]/).map((s) => s.trim())); export const isReserved = (name) => reservedKeywords.has(name); export const validIdentifier = (jsx) => (name) => { if ((jsx ? /[\s]/ : /[-\s]/).test(name) || /^\d/.test(name) || name.length === 0) { return `${JSON.stringify(name)} is not a valid identifier.`; } return null; }; export const nonNull = (value) => { if (value == null) { return 'Expected the value to be non-null but got null or undefined value.'; } return null; }; export const node = (...types) => { if (types.length === 1) { const type = types[0]; return (value) => { if (value == null || value.type !== type) { return `Expected a "${type}" node but got a \`${meaningfulType(value)}\`. The value is ${JSON.stringify(value)}.`; } return null; }; } else { return (value) => { if (types.indexOf(value.type) === -1) { return `Expected one of (${types.join()}) node but got a \`${meaningfulType(value)}\`. The value is ${JSON.stringify(value)}.`; } return null; }; } }; export const nodeAlias = (alias) => (value) => { if (value == null || !(value.type in aliases[alias])) { return `Expected one of (${Object.keys(aliases[alias]).join()}) node but got a \`${meaningfulType(value)}\`. The value is ${JSON.stringify(value)}.`; } return null; }; export const any = () => null; export const arrayOf = (validateFn) => (value) => { if (Array.isArray(value)) { let errorMsg; for (let i = 0; i < value.length; i++) { errorMsg = validateFn(value[i]); if (errorMsg != null) return `Got unexpected value at index ${i}:\n ${errorMsg}`; } return null; } else { return `Expected the value to be an array but got a \`${meaningfulType(value)}\`. The value is ${JSON.stringify(value)}.`; } }; export const oneOf = (items) => (value) => { if (!items.includes(value)) { return `Expected the value to be one of ${JSON.stringify(items)}, but got ${JSON.stringify(value)}`; } return null; }; export const nullable = (validateFn) => (value) => { if (value === null) { return null; } return validateFn(value); };