import moment from 'moment'; import { split } from '../utils/filter'; import { is } from '../utils/helper'; const parseExpr = (valueExpr) => { let valueExpr0 = valueExpr.replace(/\s+/, ''); let operator; if (valueExpr0.indexOf('=') === 0) { return { operator: 'exact', exact: valueExpr0.slice(1), }; } else if (valueExpr0.indexOf('~') === 0) { operator = 'range'; const ret = { operator, }; valueExpr0 = valueExpr0.slice(1).replace(/\s+/, ''); ret.downClose = valueExpr0[0] === '['; valueExpr0 = valueExpr0.slice(1).replace(/\s+/, ''); let pos = valueExpr0.indexOf(','); if (pos === -1) { throw new Error('Invalid input.'); } ret.down = Number.parseFloat(valueExpr0.slice(0, pos)); valueExpr0 = valueExpr0.slice(pos + 1); pos = valueExpr0.indexOf(']'); if (pos !== -1) { ret.upClose = true; ret.up = Number.parseFloat(valueExpr0.slice(0, pos)); return ret; } pos = valueExpr0.indexOf(')'); if (pos !== -1) { ret.upClose = false; ret.up = Number.parseFloat(valueExpr0.slice(0, pos)); return ret; } throw new Error('Invalid input.'); } else if (valueExpr0.indexOf('@') === 0) { operator = 'like'; return { operator, like: valueExpr0.slice(1), }; } else if (valueExpr0.indexOf('^') === 0) { operator = 'list'; return { operator, list: valueExpr0.slice(1).split(','), }; } else { throw new Error('Invalid input.'); } }; const toFunction = (keysExpr, valueExpr) => { const parsedExpr = parseExpr(valueExpr); return (obj) => { const value = obj[keysExpr.slice(2)]; // 略过'f-' if (value === undefined) { return true; } if (value === null) { return parsedExpr.operator === 'exact' && parsedExpr.exact === '' || parsedExpr.exact === null; } if (parsedExpr.operator === 'exact') { if (Number.isFinite(value)) { return value === Number.parseFloat(parsedExpr.exact); } if (moment.isMoment(value)) { return value.isSame(Number.parseFloat(parsedExpr.exact)); } if (moment.isDate(value)) { return value.isSame(Number.parseFloat(parsedExpr.exact)); } if (is(value, 'String')) { return value === parsedExpr.exact; } } else if (parsedExpr.operator === 'range') { if (Number.isFinite(value)) { let ret = true; if (!(/^\s*$/).test(parsedExpr.down)) { if (parsedExpr.downClose) { ret = ret && value >= Number.parseFloat(parsedExpr.down); } else { ret = ret && value > Number.parseFloat(parsedExpr.down); } } if (!(/^\s*$/).test(parsedExpr.up)) { if (parsedExpr.upClose) { ret = ret && value <= Number.parseFloat(parsedExpr.up); } else { ret = ret && value < Number.parseFloat(parsedExpr.up); } } return ret; } else if (moment.isDate(value) || moment.isMoment(value) || is(value, 'String')) { let ret = true; if (!(/^\s*$/).test(parsedExpr.down)) { const a = moment(value); const b = moment(Number.parseFloat(parsedExpr.down)); if (parsedExpr.downClose) { ret = ret && (a.isAfter(b) || a.isSame(b)); } else { ret = ret && a.isAfter(b); } } if (!(/^\s*$/).test(parsedExpr.up)) { const a = moment(value); const b = moment(Number.parseFloat(parsedExpr.up)); if (parsedExpr.upClose) { ret = ret && (a.isBefore(b) || a.isSame(b)); } else { ret = ret && a.isBefore(b); } } return ret; } } else if (parsedExpr.operator === 'like') { if (is(value, 'String')) { const reg = new RegExp(`^${parsedExpr.like .replace(/%/g, '[\\s\\S]*') .replace(/_/g, '[\\s\\S]') .replace(/\[!([\s\S]+)]/, '[^$1]')}$`); return reg.test(value); } } else if (parsedExpr.operator === 'list') { for (const test of parsedExpr.list) { // noinspection EqualityComparisonWithCoercionJS if (test == value) { // eslint-disable-line eqeqeq return true; } } return false; } throw new Error(`Invalid input.${keysExpr}|${valueExpr}.`); }; }; const toFilters = (keysExpr, valueExpr) => { const keys = split(keysExpr); const values = split(valueExpr); if (keys.length !== values.length) { throw new Error('Invalid input.'); } return (obj) => { const len = keys.length; const fucs = []; for (let i = 0; i < len; ++i) { const key = keys[i]; const value = values[i]; fucs.push(toFunction(key, value)); } for (let i = 0; i < len; ++i) { if (fucs[i](obj)) { return true; } } return false; }; }; export default toFilters;