amis-formula 1.3.8 → 1.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/doc.js CHANGED
@@ -421,6 +421,23 @@ exports.doc = [
421
421
  },
422
422
  namespace: "数学函数"
423
423
  },
424
+ {
425
+ name: "LAST",
426
+ description: "取数据最后一个",
427
+ example: "LAST(array)",
428
+ params: [
429
+ {
430
+ type: "...number",
431
+ name: "arr",
432
+ description: "要处理的数组"
433
+ }
434
+ ],
435
+ returns: {
436
+ type: "any",
437
+ description: "最后一个值"
438
+ },
439
+ namespace: "数学函数"
440
+ },
424
441
  {
425
442
  name: "LEFT",
426
443
  description: "返回传入文本左侧的指定长度字符串。",
@@ -926,6 +943,23 @@ exports.doc = [
926
943
  },
927
944
  namespace: "文本函数"
928
945
  },
946
+ {
947
+ name: "BASENAME",
948
+ description: "返回路径中的文件名\n\n示例:`/home/amis/a.json`\n\n返回:a.json`",
949
+ example: "BASENAME(text)",
950
+ params: [
951
+ {
952
+ type: "string",
953
+ name: "text",
954
+ description: "要处理的文本"
955
+ }
956
+ ],
957
+ returns: {
958
+ type: "string",
959
+ description: "文件名"
960
+ },
961
+ namespace: "文本函数"
962
+ },
929
963
  {
930
964
  name: "DATE",
931
965
  description: "创建日期对象,可以通过特定格式的字符串,或者数值。\n\n需要注意的是,其中月份的数值是从0开始的,也就是说,\n如果是12月份,你应该传入数值11。",
@@ -1410,5 +1444,27 @@ exports.doc = [
1410
1444
  description: "结果"
1411
1445
  },
1412
1446
  namespace: "其他"
1447
+ },
1448
+ {
1449
+ name: "ARRAYMAP",
1450
+ description: "数组做数据转换,需要搭配箭头函数一起使用,注意箭头函数只支持单表达式用法。",
1451
+ example: "ARRAYMAP(arr, item => item)",
1452
+ params: [
1453
+ {
1454
+ type: "Array<any>",
1455
+ name: "arr",
1456
+ description: "数组"
1457
+ },
1458
+ {
1459
+ type: "Array<any>",
1460
+ name: "iterator",
1461
+ description: "箭头函数"
1462
+ }
1463
+ ],
1464
+ returns: {
1465
+ type: "boolean",
1466
+ description: "结果"
1467
+ },
1468
+ namespace: "其他"
1413
1469
  }
1414
1470
  ]
package/dist/doc.md CHANGED
@@ -256,6 +256,16 @@
256
256
 
257
257
  返回 0-100 之间的随机数
258
258
 
259
+ ### LAST
260
+
261
+ 用法:`LAST(array)`
262
+
263
+ * `arr:...number` 要处理的数组
264
+
265
+ 返回:`any` 最后一个值
266
+
267
+ 取数据最后一个
268
+
259
269
  ## 文本函数
260
270
 
261
271
  ### LEFT
@@ -554,6 +564,20 @@
554
564
 
555
565
  返回文本字符串中从指定位置开始的特定数目的字符
556
566
 
567
+ ### BASENAME
568
+
569
+ 用法:`BASENAME(text)`
570
+
571
+ * `text:string` 要处理的文本
572
+
573
+ 返回:`string` 文件名
574
+
575
+ 返回路径中的文件名
576
+
577
+ 示例:`/home/amis/a.json`
578
+
579
+ 返回:a.json`
580
+
557
581
  ## 日期函数
558
582
 
559
583
  ### DATE
@@ -816,3 +840,14 @@ DATEMODIFY(A, -2, 'month')
816
840
 
817
841
  返回数组的长度
818
842
 
843
+ ### ARRAYMAP
844
+
845
+ 用法:`ARRAYMAP(arr, item => item)`
846
+
847
+ * `arr:Array<any>` 数组
848
+ * `iterator:Array<any>` 箭头函数
849
+
850
+ 返回:`boolean` 结果
851
+
852
+ 数组做数据转换,需要搭配箭头函数一起使用,注意箭头函数只支持单表达式用法。
853
+
@@ -200,6 +200,11 @@ export declare class Evaluator {
200
200
  identifier: string;
201
201
  args: Array<any>;
202
202
  }): any;
203
+ anonymousFunction(ast: any): any;
204
+ callAnonymousFunction(ast: {
205
+ args: any[];
206
+ return: any;
207
+ }, args: Array<any>): any;
203
208
  /**
204
209
  * 示例:IF(A, B, C)
205
210
  *
@@ -459,6 +464,16 @@ export declare class Evaluator {
459
464
  * @returns {number} 随机数
460
465
  */
461
466
  fnRAND(): number;
467
+ /**
468
+ * 取数据最后一个
469
+ *
470
+ * @example LAST(array)
471
+ * @param {...number} arr - 要处理的数组
472
+ * @namespace 数学函数
473
+ *
474
+ * @returns {any} 最后一个值
475
+ */
476
+ fnLAST(arr: Array<any>): any;
462
477
  normalizeText(raw: any): string;
463
478
  /**
464
479
  * 返回传入文本左侧的指定长度字符串。
@@ -756,6 +771,20 @@ export declare class Evaluator {
756
771
  * @returns {number} 命中的位置
757
772
  */
758
773
  fnMID(text: string, from: number, len: number): string;
774
+ /**
775
+ * 返回路径中的文件名
776
+ *
777
+ * 示例:`/home/amis/a.json`
778
+ *
779
+ * 返回:a.json`
780
+ *
781
+ * @example BASENAME(text)
782
+ * @param {string} text - 要处理的文本
783
+ * @namespace 文本函数
784
+ *
785
+ * @returns {string} 文件名
786
+ */
787
+ fnBASENAME(text: string): string | undefined;
759
788
  /**
760
789
  * 创建日期对象,可以通过特定格式的字符串,或者数值。
761
790
  *
@@ -996,4 +1025,14 @@ export declare class Evaluator {
996
1025
  * @returns {boolean} 结果
997
1026
  */
998
1027
  fnCOUNT(value: any): number;
1028
+ /**
1029
+ * 数组做数据转换,需要搭配箭头函数一起使用,注意箭头函数只支持单表达式用法。
1030
+ *
1031
+ * @param {Array<any>} arr 数组
1032
+ * @param {Function<any>} iterator 箭头函数
1033
+ * @namespace 其他
1034
+ * @example ARRAYMAP(arr, item => item)
1035
+ * @returns {boolean} 结果
1036
+ */
1037
+ fnARRAYMAP(value: any, iterator: any): any[];
999
1038
  }
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * amis-formula v1.3.8
2
+ * amis-formula v1.3.11
3
3
  * Copyright 2021-2022 fex
4
4
  */
5
5
 
@@ -739,7 +739,8 @@ function lexer(input, options) {
739
739
 
740
740
  var argListStates = {
741
741
  START: 0,
742
- COMMA: 1
742
+ COMMA: 1,
743
+ SET: 2
743
744
  };
744
745
  var tempalteStates = {
745
746
  START: 0,
@@ -883,6 +884,32 @@ function parse(input, options) {
883
884
  }
884
885
  return ast;
885
886
  }
887
+ function arrowFunction() {
888
+ var ast = argList() || variable();
889
+ var args = [];
890
+ if ((ast === null || ast === void 0 ? void 0 : ast.type) === 'variable') {
891
+ args = [ast];
892
+ }
893
+ else if ((ast === null || ast === void 0 ? void 0 : ast.type) === 'arg-list') {
894
+ args = ast.body;
895
+ }
896
+ if (Array.isArray(args) && matchPunctuator('=')) {
897
+ next();
898
+ if (matchPunctuator('>')) {
899
+ next();
900
+ var body = assert(expression());
901
+ return {
902
+ type: 'anonymous_function',
903
+ args: args,
904
+ return: body
905
+ };
906
+ }
907
+ else {
908
+ back();
909
+ }
910
+ }
911
+ return ast;
912
+ }
886
913
  function conditionalExpression() {
887
914
  var ast = logicalOrExpression();
888
915
  if (!ast) {
@@ -1026,7 +1053,7 @@ function parse(input, options) {
1026
1053
  return ast;
1027
1054
  }
1028
1055
  function leftHandSideExpression() {
1029
- return functionCall() || primaryExpression();
1056
+ return functionCall() || arrowFunction() || primaryExpression();
1030
1057
  }
1031
1058
  function varibleKey(allowVariable, inObject) {
1032
1059
  if (allowVariable === void 0) { allowVariable = false; }
@@ -1154,11 +1181,11 @@ function parse(input, options) {
1154
1181
  var id = token;
1155
1182
  next();
1156
1183
  if (matchPunctuator('(')) {
1157
- var argList = expressionList();
1184
+ var argList_1 = expressionList();
1158
1185
  return {
1159
1186
  type: 'func_call',
1160
1187
  identifier: id.value,
1161
- args: argList === null || argList === void 0 ? void 0 : argList.body
1188
+ args: argList_1 === null || argList_1 === void 0 ? void 0 : argList_1.body
1162
1189
  };
1163
1190
  }
1164
1191
  else {
@@ -1169,10 +1196,10 @@ function parse(input, options) {
1169
1196
  }
1170
1197
  function arrayLiteral() {
1171
1198
  if (matchPunctuator('[')) {
1172
- var argList = expressionList('[', ']');
1199
+ var argList_2 = expressionList('[', ']');
1173
1200
  return {
1174
1201
  type: 'array',
1175
- members: argList === null || argList === void 0 ? void 0 : argList.body
1202
+ members: argList_2 === null || argList_2 === void 0 ? void 0 : argList_2.body
1176
1203
  };
1177
1204
  }
1178
1205
  return null;
@@ -1206,6 +1233,53 @@ function parse(input, options) {
1206
1233
  }
1207
1234
  return null;
1208
1235
  }
1236
+ function argList(startOP, endOp) {
1237
+ if (startOP === void 0) { startOP = '('; }
1238
+ if (endOp === void 0) { endOp = ')'; }
1239
+ var count = 0;
1240
+ var rollback = function () {
1241
+ while (count-- > 0) {
1242
+ back();
1243
+ }
1244
+ return null;
1245
+ };
1246
+ if (matchPunctuator(startOP)) {
1247
+ next();
1248
+ count++;
1249
+ var args = [];
1250
+ var state = argListStates.START;
1251
+ while (!matchPunctuator(endOp)) {
1252
+ if (state === argListStates.COMMA || state === argListStates.START) {
1253
+ var arg = variable(false);
1254
+ if (!arg) {
1255
+ return rollback();
1256
+ }
1257
+ count++;
1258
+ args.push(arg);
1259
+ state = argListStates.SET;
1260
+ }
1261
+ else if (state === argListStates.SET && matchPunctuator(',')) {
1262
+ next();
1263
+ count++;
1264
+ state = argListStates.COMMA;
1265
+ }
1266
+ else {
1267
+ return rollback();
1268
+ }
1269
+ }
1270
+ if (matchPunctuator(endOp)) {
1271
+ next();
1272
+ return {
1273
+ type: 'arg-list',
1274
+ body: args
1275
+ };
1276
+ }
1277
+ else {
1278
+ return rollback();
1279
+ }
1280
+ }
1281
+ return null;
1282
+ }
1209
1283
  function objectLiteral() {
1210
1284
  if (matchPunctuator('{')) {
1211
1285
  next();
@@ -1296,11 +1370,14 @@ function parse(input, options) {
1296
1370
  body: exp
1297
1371
  };
1298
1372
  }
1299
- function variable() {
1373
+ function variable(allowNameSpace) {
1374
+ if (allowNameSpace === void 0) { allowNameSpace = true; }
1300
1375
  if (token.type === TokenName[TokenEnum.Identifier]) {
1301
1376
  var cToken = token;
1302
1377
  next();
1303
- if (matchPunctuator(':') && ~variableNamespaces.indexOf(cToken.value)) {
1378
+ if (allowNameSpace &&
1379
+ matchPunctuator(':') &&
1380
+ ~variableNamespaces.indexOf(cToken.value)) {
1304
1381
  next();
1305
1382
  var body = assert(postfixExpression());
1306
1383
  return {
@@ -1332,14 +1409,16 @@ function parse(input, options) {
1332
1409
  return {
1333
1410
  type: 'script',
1334
1411
  body: prevToken.value.split('.').reduce(function (prev, key) {
1335
- return prev ? {
1336
- type: 'getter',
1337
- host: prev,
1338
- key: key
1339
- } : {
1340
- type: 'variable',
1341
- name: key
1342
- };
1412
+ return prev
1413
+ ? {
1414
+ type: 'getter',
1415
+ host: prev,
1416
+ key: key
1417
+ }
1418
+ : {
1419
+ type: 'variable',
1420
+ name: key
1421
+ };
1343
1422
  }, null)
1344
1423
  };
1345
1424
  }
@@ -1585,22 +1664,26 @@ var filterDate = function (value, data, format, utc) {
1585
1664
  value = value.trim();
1586
1665
  }
1587
1666
  // todo
1588
- value = tokenize(value, data);
1667
+ var date = new Date();
1668
+ value = tokenize(value, createObject(data, {
1669
+ now: mm().toDate(),
1670
+ today: mm([date.getFullYear(), date.getMonth(), date.getDate()])
1671
+ }), '| raw');
1589
1672
  if (value && typeof value === 'string' && (m = relativeValueRe.exec(value))) {
1590
- var date = new Date();
1673
+ var date_1 = new Date();
1591
1674
  var step = parseInt(m[3], 10);
1592
1675
  var from = m[1]
1593
1676
  ? filterDate(m[1], data, format, utc)
1594
1677
  : mm(/(minute|min|hour|second)s?/.test(m[4])
1595
1678
  ? [
1596
- date.getFullYear(),
1597
- date.getMonth(),
1598
- date.getDate(),
1599
- date.getHours(),
1600
- date.getMinutes(),
1601
- date.getSeconds()
1679
+ date_1.getFullYear(),
1680
+ date_1.getMonth(),
1681
+ date_1.getDate(),
1682
+ date_1.getHours(),
1683
+ date_1.getMinutes(),
1684
+ date_1.getSeconds()
1602
1685
  ]
1603
- : [date.getFullYear(), date.getMonth(), date.getDate()]);
1686
+ : [date_1.getFullYear(), date_1.getMonth(), date_1.getDate()]);
1604
1687
  return m[2] === '-'
1605
1688
  ? from.subtract(step, timeUnitMap[m[4]])
1606
1689
  : from.add(step, timeUnitMap[m[4]]);
@@ -1610,11 +1693,12 @@ var filterDate = function (value, data, format, utc) {
1610
1693
  return mm();
1611
1694
  }
1612
1695
  else if (value === 'today') {
1613
- var date = new Date();
1614
- return mm([date.getFullYear(), date.getMonth(), date.getDate()]);
1696
+ var date_2 = new Date();
1697
+ return mm([date_2.getFullYear(), date_2.getMonth(), date_2.getDate()]);
1615
1698
  }
1616
1699
  else {
1617
- return mm(value, format);
1700
+ var result = mm(value);
1701
+ return result.isValid() ? result : mm(value, format);
1618
1702
  }
1619
1703
  };
1620
1704
  function parseDuration(str) {
@@ -2063,6 +2147,24 @@ var Evaluator = /** @class */ (function () {
2063
2147
  }
2064
2148
  return fn.apply(this, args);
2065
2149
  };
2150
+ Evaluator.prototype.anonymousFunction = function (ast) {
2151
+ return ast;
2152
+ };
2153
+ Evaluator.prototype.callAnonymousFunction = function (ast, args) {
2154
+ var ctx = createObject(this.contextStack[this.contextStack.length - 1]('&') || {}, {});
2155
+ ast.args.forEach(function (arg) {
2156
+ if (arg.type !== 'variable') {
2157
+ throw new Error('expected a variable as argument');
2158
+ }
2159
+ ctx[arg.name] = args.shift();
2160
+ });
2161
+ this.contextStack.push(function (varName) {
2162
+ return varName === '&' ? ctx : ctx[varName];
2163
+ });
2164
+ var result = this.evalute(ast.return);
2165
+ this.contextStack.pop();
2166
+ return result;
2167
+ };
2066
2168
  /**
2067
2169
  * 示例:IF(A, B, C)
2068
2170
  *
@@ -2515,6 +2617,18 @@ var Evaluator = /** @class */ (function () {
2515
2617
  Evaluator.prototype.fnRAND = function () {
2516
2618
  return Math.random();
2517
2619
  };
2620
+ /**
2621
+ * 取数据最后一个
2622
+ *
2623
+ * @example LAST(array)
2624
+ * @param {...number} arr - 要处理的数组
2625
+ * @namespace 数学函数
2626
+ *
2627
+ * @returns {any} 最后一个值
2628
+ */
2629
+ Evaluator.prototype.fnLAST = function (arr) {
2630
+ return arr.length ? arr[arr.length - 1] : null;
2631
+ };
2518
2632
  // 文本函数
2519
2633
  Evaluator.prototype.normalizeText = function (raw) {
2520
2634
  if (raw instanceof Date) {
@@ -2925,6 +3039,23 @@ var Evaluator = /** @class */ (function () {
2925
3039
  text = this.normalizeText(text);
2926
3040
  return text.substring(from, from + len);
2927
3041
  };
3042
+ /**
3043
+ * 返回路径中的文件名
3044
+ *
3045
+ * 示例:`/home/amis/a.json`
3046
+ *
3047
+ * 返回:a.json`
3048
+ *
3049
+ * @example BASENAME(text)
3050
+ * @param {string} text - 要处理的文本
3051
+ * @namespace 文本函数
3052
+ *
3053
+ * @returns {string} 文件名
3054
+ */
3055
+ Evaluator.prototype.fnBASENAME = function (text) {
3056
+ text = this.normalizeText(text);
3057
+ return text.split(/[\\/]/).pop();
3058
+ };
2928
3059
  // 日期函数
2929
3060
  /**
2930
3061
  * 创建日期对象,可以通过特定格式的字符串,或者数值。
@@ -3265,6 +3396,24 @@ var Evaluator = /** @class */ (function () {
3265
3396
  Evaluator.prototype.fnCOUNT = function (value) {
3266
3397
  return Array.isArray(value) ? value.length : value ? 1 : 0;
3267
3398
  };
3399
+ /**
3400
+ * 数组做数据转换,需要搭配箭头函数一起使用,注意箭头函数只支持单表达式用法。
3401
+ *
3402
+ * @param {Array<any>} arr 数组
3403
+ * @param {Function<any>} iterator 箭头函数
3404
+ * @namespace 其他
3405
+ * @example ARRAYMAP(arr, item => item)
3406
+ * @returns {boolean} 结果
3407
+ */
3408
+ Evaluator.prototype.fnARRAYMAP = function (value, iterator) {
3409
+ var _this = this;
3410
+ if (!iterator || iterator.type !== 'anonymous_function') {
3411
+ throw new Error('expected an anonymous function get ' + iterator);
3412
+ }
3413
+ return (Array.isArray(value) ? value : []).map(function (item, index) {
3414
+ return _this.callAnonymousFunction(iterator, [item, index]);
3415
+ });
3416
+ };
3268
3417
  Evaluator.defaultFilters = {};
3269
3418
  return Evaluator;
3270
3419
  }());
@@ -3285,7 +3434,6 @@ function parseJson(str, defaultValue) {
3285
3434
  }
3286
3435
  }
3287
3436
 
3288
- var _this = undefined;
3289
3437
  function makeSorter(key, method, order) {
3290
3438
  return function (a, b) {
3291
3439
  if (!a || !b) {
@@ -3305,6 +3453,7 @@ function makeSorter(key, method, order) {
3305
3453
  }
3306
3454
  var filters = {
3307
3455
  map: function (input, fn) {
3456
+ var _this = this;
3308
3457
  var arg = [];
3309
3458
  for (var _i = 2; _i < arguments.length; _i++) {
3310
3459
  arg[_i - 2] = arguments[_i];
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "amis-formula",
3
- "version": "1.3.8",
3
+ "version": "1.3.11",
4
4
  "description": "负责 amis 里面的表达式实现,内置公式,编辑器等",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
7
7
  "build": "npm run clean-dist && NODE_ENV=production rollup -c && npm run declaration && npm run genDoc",
8
+ "lib": "npm run clean-dist && NODE_ENV=lib rollup -c",
8
9
  "clean-dist": "rimraf dist/*",
9
10
  "declaration": "tsc --allowJs --declaration --emitDeclarationOnly --declarationDir ./dist --rootDir ./src",
10
11
  "test": "jest",
package/rollup.config.js CHANGED
@@ -8,6 +8,8 @@ import license from 'rollup-plugin-license';
8
8
  import {name, version, main, module, browser, author} from './package.json';
9
9
 
10
10
  const isProduction = process.env.NODE_ENV === 'production';
11
+ const isForLib = process.env.NODE_ENV === 'lib';
12
+
11
13
 
12
14
  const settings = {
13
15
  globals: {
@@ -18,16 +20,19 @@ const settings = {
18
20
  };
19
21
 
20
22
  export default {
21
- input: './src/index.ts',
23
+ input: isForLib ? './scripts/lib.ts' : './src/index.ts',
22
24
  output: [
23
25
  {
24
- file: main,
25
- name: main,
26
+ file: isForLib ? 'dist/formula.js' : main,
27
+ name: isForLib ? 'formula' : main,
26
28
  ...settings,
27
- format: 'cjs',
29
+ format: isForLib ? 'iife' : 'cjs',
28
30
  plugins: [
29
- /*isProduction && terser()*/
30
- ]
31
+ isForLib && terser()
32
+ ],
33
+ footer: isForLib ? `var evaluate = formula.evaluate;
34
+ var momentFormat = formula.momentFormat;
35
+ var parse = formula.parse;` : '',
31
36
  }
32
37
  // {
33
38
  // file: module,
@@ -42,7 +47,7 @@ export default {
42
47
  // format: 'umd'
43
48
  // }
44
49
  ],
45
- external: [
50
+ external: isForLib ? [] : [
46
51
  'lodash',
47
52
  'lodash/transform',
48
53
  'lodash/groupBy',