UNPKG

jora

Version:

JavaScript object query engine

311 lines (259 loc) 8.68 kB
'use strict'; const compileBuildin = require('./lang/compile-buildin.cjs'); const compare = require('./utils/compare.cjs'); const stableSort = require('./utils/stable-sort.cjs'); const statistics = require('./utils/statistics.cjs'); const misc = require('./utils/misc.cjs'); function noop() {} function self(value) { return value; } function matchEntry(match) { if (match === null) { return null; } return { matched: match.slice(), start: match.index, end: match.index + match[0].length, input: match.input, groups: match.groups || null }; } function replaceMatchEntry(args) { const last = args.pop(); const groups = typeof last === 'string' ? null : last; const input = groups === null ? last : args.pop(); const start = args.pop(); return { matched: args, start, end: start + args[0].length, input, groups }; } const replaceAll = String.prototype.replaceAll || function(pattern, replacement) { return misc.isRegExp(pattern) ? this.replace(pattern, replacement) : this.split(pattern).join(String(replacement)); }; const methods = Object.freeze({ bool: compileBuildin.bool, filter: compileBuildin.filter, map: compileBuildin.map, pick: compileBuildin.pick, indexOf: compileBuildin.indexOf, lastIndexOf: compileBuildin.lastIndexOf, keys(current) { return Object.keys(current || {}); }, values(current) { const values = new Set(); for (const key in current) { if (misc.hasOwn(current, key)) { misc.addToSet(values, current[key]); } } return [...values]; }, entries(current) { const entries = []; for (const key in current) { if (misc.hasOwn(current, key)) { entries.push({ key, value: current[key] }); } } return entries; }, fromEntries(current) { const result = Object.create(null); if (Array.isArray(current)) { for (const entry of current) { if (entry) { result[entry.key] = entry.value; } } } return result; }, size(current) { if (misc.isPlainObject(current)) { return Object.keys(current).length; } return (current && current.length) || 0; }, sort(current, comparator = compare.cmp) { if (!misc.isArray(current)) { return current; } if (typeof comparator === 'function' && comparator.length !== 2) { const getter = comparator; comparator = (a, b) => { a = getter(a); b = getter(b); if (Array.isArray(a) && Array.isArray(b)) { if (a.length !== b.length) { return a.length < b.length ? -1 : 1; } for (let i = 0; i < a.length; i++) { const ret = compare.cmp(a[i], b[i]); if (ret !== 0) { return ret; } } return 0; } return compare.cmp(a, b); }; } return stableSort.stableSort(current, comparator); }, reverse(current) { return misc.isArray(current) ? current.slice().reverse() : current; }, slice(current, from, to) { return typeof current === 'string' || misc.isArray(current) ? current.slice(from, to) : Array.prototype.slice.call(current, from, to); }, group(current, keyGetter, valueGetter) { const map = new Map(); const result = []; if (typeof keyGetter !== 'function') { keyGetter = noop; } if (typeof valueGetter !== 'function') { valueGetter = self; } if (!misc.isArray(current)) { current = [current]; } for (const item of current) { const keys = keyGetter(item); if (misc.isArray(keys)) { if (keys.length > 0) { const value = valueGetter(item); for (const key of keys) { misc.addToMapSet(map, key, value); } } else { misc.addToMapSet(map, undefined, valueGetter(item)); } } else { misc.addToMapSet(map, keys, valueGetter(item)); } } for (const [key, value] of map) { result.push({ key, value: [...value] }); } return result; }, join(current, separator) { return misc.isArray(current) ? current.join(separator) : String(current); }, match(current, pattern, matchAll) { const input = String(current); const flags = misc.isRegExp(pattern) ? pattern.flags : ''; if (matchAll || flags.includes('g')) { const result = []; let cursor = new RegExp(pattern, (flags || '').replace(/g|$/, 'g')); let match; while (match = cursor.exec(input)) { result.push(matchEntry(match)); } return result; } return matchEntry(input.match(pattern)); }, reduce(current, fn, initValue = undefined) { if (misc.isArray(current)) { return initValue !== undefined ? current.reduce((res, current) => fn(current, res), initValue) : current.reduce((res, current) => fn(current, res)); } return fn(current, initValue); }, // array/string split(current, pattern) { if (misc.isArray(current)) { const patternFn = typeof pattern === 'function' ? pattern : Object.is.bind(null, pattern); const result = []; let start = 0; let end = 0; for (; end < current.length; end++) { if (patternFn(current[end])) { result.push(current.slice(start, end)); start = end + 1; } } result.push(current.slice(start, end)); return result; } return String(current).split(pattern); }, replace(current, pattern, replacement) { if (misc.isArray(current)) { const patternFn = typeof pattern === 'function' ? pattern : Object.is.bind(null, pattern); const result = [...current]; for (let i = 0; i < result.length; i++) { const value = result[i]; if (patternFn(value)) { result[i] = typeof replacement === 'function' ? replacement(value) : replacement; } } return result; } if (misc.isRegExp(pattern) && !pattern.flags.includes('g')) { pattern = new RegExp(pattern, pattern.flags + 'g'); } return replaceAll.call( String(current), pattern, typeof replacement === 'function' ? (...args) => replacement(replaceMatchEntry(args)) : replacement ); }, // strings toLowerCase(current, locales) { return String(current).toLocaleLowerCase(locales); }, toUpperCase(current, locales) { return String(current).toLocaleUpperCase(locales); }, trim(current) { return String(current).trim(); }, // all Math static method with exclusion of 'max', 'min', 'log', `log1p` and 'random' ...[ 'abs', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'cbrt', 'ceil', 'clz32', 'cos', 'cosh', 'exp', 'expm1', 'floor', 'fround', 'hypot', 'imul', 'log10', 'log2', 'pow', 'round', 'sign', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc' ].reduce((res, method) => { res[method] = Math[method]; return res; }, {}), ln: Math.log, ln1p: Math.log1p, // statistics numbers: statistics.numbers, count: statistics.count, sum: statistics.sum, avg: statistics.mean, variance: statistics.variance, stdev: statistics.stdev, min: statistics.min, max: statistics.max, percentile: statistics.percentile, p: statistics.percentile, // alias for percentile() median: statistics.median }); module.exports = methods;