sh-tools
v2.3.11
Published
基于fetch和xe-utils二次封装,支持宏公式计算
Downloads
1,545
Readme
sh-tools
概述
SH-Tools 提供了一个强大的表达式求值器模块,支持复杂的数学运算、逻辑判断、函数调用和模板字符串解析。特别适合动态计算、规则引擎和配置化计算场景。
安装
npm install sh-tools
引入方式
import { utils, expr } from 'sh-tools'
核心 API
| 函数名 | 参数 | 返回值 | 描述 | 示例 |
|--------|------|--------|------|------|
| utils.calculate(expression, data?) | expression: string - 表达式字符串data?: object - 数据上下文 | any - 计算结果 | 计算表达式并返回结果,支持 {} 模板 | utils.calculate("1+2*3") → 7utils.calculate("用户{name}", {name:"张三"}) → "用户张三" |
| utils.calculateLog(expression, data?) | expression: stringdata?: object | {result, log, treeLog} - 结果和日志 | 计算表达式并返回详细执行日志 | utils.calculateLog("sum([1,2,3])") → {result: 6, log: [...], treeLog: [...]} |
| expr.registerFunction(name, fn, override?) | name: string\|object - 函数名或对象fn: Function - 函数实现override?: boolean - 是否覆盖 | void | 注册自定义函数 | expr.registerFunction('double', x=>x*2)expr.registerFunction({square: x=>x*x}) |
| expr.extendOperator(symbol, config, override?) | symbol: string - 运算符config: object - 配置override?: boolean - 是否覆盖 | void | 扩展自定义运算符 | expr.extendOperator('//', {precedence:11, fn:(a,b)=>Math.floor(a/b)}) |
内置函数
数学函数
| 函数名 | 参数 | 返回值 | 描述 | 示例 |
|--------|------|--------|------|------|
| abs | x: number | number | 绝对值 | abs(-10) → 10 |
| ceil | x: number | number | 向上取整 | ceil(3.14) → 4 |
| floor | x: number | number | 向下取整 | floor(3.14) → 3 |
| round | x: number | number | 四舍五入 | round(3.14) → 3 |
| pow | base: number, exponent: number | number | 幂运算 | pow(2, 3) → 8 |
| sqrt | x: number | number | 平方根 | sqrt(9) → 3 |
| sin | x: number | number | 正弦 | sin(0) → 0 |
| cos | x: number | number | 余弦 | cos(0) → 1 |
| tan | x: number | number | 正切 | tan(0) → 0 |
| log | x: number | number | 自然对数 | log(10) → 2.302... |
| exp | x: number | number | e的幂次 | exp(1) → 2.718... |
| random | min?: number, max?: number | number | 随机数 | random() → 0.123random(1,10) → 5 |
| min | ...args: number[] 或 arr: number[] | number | 最小值 | min(5,2,8,1) → 1min([5,2,8,1]) → 1 |
| max | ...args: number[] 或 arr: number[] | number | 最大值 | max(5,2,8,1) → 8max([5,2,8,1]) → 8 |
| add | a: number, b: number | number | 加法(精确) | add(0.1, 0.2) → 0.3 |
| subtract | a: number, b: number | number | 减法(精确) | subtract(0.3, 0.1) → 0.2 |
| multiply | a: number, b: number | number | 乘法(精确) | multiply(0.1, 0.2) → 0.02 |
| divide | a: number, b: number | number | 除法(精确) | divide(0.3, 0.1) → 3 |
| toFixed | value: number, digits: number | string | 保留小数位 | toFixed(3.14159, 2) → "3.14" |
| toInteger | value: any | number | 转整数 | toInteger("123") → 123toInteger(3.14) → 3 |
| toNumber | value: any | number | 转数字 | toNumber("3.14") → 3.14toNumber("123") → 123 |
| truncate | value: number, digits: number | number | 截断小数位 | truncate(3.14159, 2) → 3.14 |
数组函数
| 函数名 | 参数 | 返回值 | 描述 | 示例 |
|--------|------|--------|------|------|
| sum | arr: number[] | number | 求和 | sum([1,2,3]) → 6 |
| mean | arr: number[] | number | 平均值 | mean([1,2,3,4]) → 2.5 |
| min | arr: number[] | number | 最小值 | min([5,2,8,1]) → 1 |
| max | arr: number[] | number | 最大值 | max([5,2,8,1]) → 8 |
| flatten | arr: any[] | any[] | 扁平化数组 | flatten([[1,2],[3,4]]) → [1,2,3,4] |
| uniq | arr: any[] | any[] | 数组去重 | uniq([1,2,2,3,3,3]) → [1,2,3] |
| includes | arr: any[], value: any | boolean | 包含判断 | includes([1,2,3], 2) → true |
| first | arr: any[] | any | 第一个元素 | first([1,2,3]) → 1 |
| last | arr: any[] | any | 最后一个元素 | last([1,2,3]) → 3 |
| length | arr: any[] | number | 数组长度 | length([1,2,3,4,5]) → 5 |
| slice | arr: any[], start: number, end?: number | any[] | 切片 | slice([1,2,3,4,5], 1, 3) → [2,3] |
| indexOf | arr: any[], value: any, fromIndex?: number | number | 查找索引 | indexOf([1,2,3,2], 2) → 1 |
| union | ...arrays: any[][] | any[] | 数组合并并去重 | union([1,2], [2,3], [3,4]) → [1,2,3,4] |
| pluck | arr: object[], property: string | any[] | 提取属性值 | pluck([{id:1},{id:2},{id:3}], 'id') → [1,2,3] |
| orderBy | arr: any[], field: string, order?: 'asc'\|'desc' | any[] | 排序 | orderBy([{age:30},{age:25}], 'age', 'asc') → [{age:25},{age:30}] |
| groupBy | arr: any[], field: string | object | 分组 | groupBy([{type:'A'},{type:'B'},{type:'A'}], 'type') → {A:[...], B:[...]} |
| countBy | arr: any[], field: string | object | 统计计数 | countBy([{type:'A'},{type:'B'},{type:'A'}], 'type') → {A:2, B:1} |
| toArrayTree | arr: any[], options?: object | any[] | 转树形结构 | toArrayTree([{id:1,pid:0},{id:2,pid:1}]) → [{id:1,children:[{id:2}]}] |
| toTreeArray | tree: any[], options?: object | any[] | 树形转数组 | toTreeArray([{id:1,children:[{id:2}]}]) → [{id:1,pid:0},{id:2,pid:1}] |
| invoke | arr: any[], methodName: string, ...args: any[] | any[] | 调用方法 | invoke([[1,2],[3,4]], 'join', ',') → ['1,2','3,4'] |
| unzip | arr: any[][] | any[][] | 解压数组 | unzip([[1,'a'],[2,'b'],[3,'c']]) → [[1,2,3],['a','b','c']] |
| includeArrays | arr1: any[], arr2: any[] | boolean | 数组包含 | includeArrays([1,2,3,4], [2,3]) → true |
字符串函数
| 函数名 | 参数 | 返回值 | 描述 | 示例 |
|--------|------|--------|------|------|
| trim | str: string | string | 去除两端空格 | trim(' hello ') → 'hello' |
| trimLeft | str: string | string | 去除左侧空格 | trimLeft(' hello') → 'hello' |
| trimRight | str: string | string | 去除右侧空格 | trimRight('hello ') → 'hello' |
| camelCase | str: string | string | 转驼峰命名 | camelCase('hello_world') → 'helloWorld'camelCase('hello-world') → 'helloWorld' |
| kebabCase | str: string | string | 转烤串命名 | kebabCase('helloWorld') → 'hello-world'kebabCase('HelloWorld') → 'hello-world' |
| startsWith | str: string, search: string | boolean | 是否以指定字符串开头 | startsWith('hello', 'he') → truestartsWith('hello', 'lo') → false |
| endsWith | str: string, search: string | boolean | 是否以指定字符串结尾 | endsWith('hello', 'lo') → trueendsWith('hello', 'he') → false |
| toValueString | value: any | string | 转值字符串 | toValueString(123) → '123'toValueString(null) → '' |
| toNumberString | value: any, digits?: number | string | 转数字字符串 | toNumberString(3.14159, 2) → '3.14' |
日期函数
| 函数名 | 参数 | 返回值 | 描述 | 示例 |
|--------|------|--------|------|------|
| now | 无 | number | 当前时间戳 | now() → 1640995200000 |
| timestamp | 无 | number | 当前时间戳 | timestamp() → 1640995200000 |
| toDateString | date: any, format?: string | string | 日期格式化 | toDateString(1640995200000, 'YYYY-MM-DD') → '2022-01-01' |
| getYearDiff | date1: string\|number, date2: string\|number | number | 年份差 | getYearDiff('2020-01-01', '2024-01-01') → 4 |
| getMonthDiff | date1: string\|number, date2: string\|number | number | 月份差 | getMonthDiff('2024-01-01', '2024-06-01') → 5 |
| getDayDiff | date1: string\|number, date2: string\|number | number | 天数差 | getDayDiff('2024-01-01', '2024-01-10') → 9 |
| getHourDiff | time1: string\|number, time2: string\|number | number | 小时差 | getHourDiff('2024-01-01 10:00', '2024-01-01 15:30') → 5.5 |
| getMinuteDiff | time1: string\|number, time2: string\|number | number | 分钟差 | getMinuteDiff('10:30', '11:45') → 75 |
| getSecondDiff | time1: string\|number, time2: string\|number | number | 秒数差 | getSecondDiff('12:00:00', '12:01:30') → 90 |
| getDayOfMonth | date: string\|number | number | 当月第几天 | getDayOfMonth('2024-01-15') → 15 |
对象函数
| 函数名 | 参数 | 返回值 | 描述 | 示例 |
|--------|------|--------|------|------|
| has | obj: object, key: string | boolean | 检查属性是否存在 | has({name:'John'}, 'name') → true |
| get | obj: object, path: string, defaultValue?: any | any | 深度获取属性值 | get({user:{name:'John'}}, 'user.name') → 'John'get({}, 'user.name', '默认值') → '默认值' |
| assign | target: object, ...sources: object[] | object | 对象属性分配 | assign({}, {a:1}, {b:2}) → {a:1,b:2} |
| merge | ...objects: object[] | object | 深度合并对象 | merge({a:{x:1}}, {a:{y:2}, b:3}) → {a:{x:1,y:2},b:3} |
| pick | obj: object, keys: string[] | object | 选取指定属性 | pick({name:'John',age:30,city:'NY'}, ['name','age']) → {name:'John',age:30} |
| omit | obj: object, keys: string[] | object | 排除指定属性 | omit({x:1,y:2,z:3}, ['z']) → {x:1,y:2} |
类型判断函数
| 函数名 | 参数 | 返回值 | 描述 | 示例 |
|--------|------|--------|------|------|
| isNaN | value: any | boolean | 是否是NaN | isNaN(NaN) → trueisNaN(123) → false |
| isArray | value: any | boolean | 是否是数组 | isArray([1,2,3]) → trueisArray({}) → false |
| isFloat | value: any | boolean | 是否是浮点数 | isFloat(3.14) → trueisFloat(3) → false |
| isInteger | value: any | boolean | 是否是整数 | isInteger(3) → trueisInteger(3.14) → false |
| isBoolean | value: any | boolean | 是否是布尔值 | isBoolean(true) → trueisBoolean('true') → false |
| isString | value: any | boolean | 是否是字符串 | isString('hello') → trueisString(123) → false |
| isNumber | value: any | boolean | 是否是数字 | isNumber(123) → trueisNumber('123') → false |
| isPlainObject | value: any | boolean | 是否是纯对象 | isPlainObject({}) → trueisPlainObject([]) → false |
| isDate | value: any | boolean | 是否是日期对象 | isDate(new Date()) → trueisDate('2024-01-01') → false |
| isEmpty | value: any | boolean | 是否为空 | isEmpty([]) → trueisEmpty({}) → trueisEmpty('') → trueisEmpty([1]) → false |
| isNull | value: any | boolean | 是否是null | isNull(null) → trueisNull(undefined) → false |
| isMatch | obj: object, source: object | boolean | 是否部分匹配 | isMatch({a:1,b:2,c:3}, {a:1,b:2}) → true |
| isEqual | value1: any, value2: any | boolean | 深度相等比较 | isEqual({a:[1,2]}, {a:[1,2]}) → trueisEqual({a:1}, {a:1,b:2}) → false |
| getSize | value: any | number | 获取大小 | getSize([1,2,3]) → 3getSize({a:1,b:2}) → 2getSize('hello') → 5 |
工具函数
| 函数名 | 参数 | 返回值 | 描述 | 示例 |
|--------|------|--------|------|------|
| first | arr: any[] 或 ...args: any[] | any | 第一个元素 | first([1,2,3]) → 1first(1,2,3) → 1 |
| last | arr: any[] 或 ...args: any[] | any | 最后一个元素 | last([1,2,3]) → 3last(1,2,3) → 3 |
注意事项
- 参数类型:所有函数参数都经过类型转换,字符串会自动转为数字等
- 空值处理:大部分函数对空值有安全的处理机制
- 错误处理:函数调用出错时会抛出清晰的错误信息
- 性能优化:常用函数做了性能优化,适合高频调用
使用示例
import { utils } from 'sh-tools'
// 数学计算
utils.calculate("abs(-10) + pow(2, 3)") // 18
// 数组操作
utils.calculate("sum([1,2,3,4,5]) / length([1,2,3,4,5])") // 3
// 字符串处理
utils.calculate("trim(' hello ') + ' ' + camelCase('world_test')") // "hello worldTest"
// 日期计算
utils.calculate("getDayDiff('2024-01-01', '2024-01-10') + getHourDiff('10:00', '12:30')") // 12.5
// 对象操作
utils.calculate("merge({a:1}, {b:2}, {c:3})") // {a:1, b:2, c:3}