sculp-js 1.0.1 → 1.1.0

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.
Files changed (48) hide show
  1. package/README.md +106 -9
  2. package/lib/cjs/array.js +87 -1
  3. package/lib/cjs/async.js +1 -1
  4. package/lib/cjs/clipboard.js +1 -1
  5. package/lib/cjs/cookie.js +1 -1
  6. package/lib/cjs/date.js +1 -1
  7. package/lib/cjs/dom.js +1 -1
  8. package/lib/cjs/download.js +1 -1
  9. package/lib/cjs/easing.js +1 -1
  10. package/lib/cjs/file.js +1 -1
  11. package/lib/cjs/func.js +1 -1
  12. package/lib/cjs/index.js +2 -1
  13. package/lib/cjs/number.js +1 -1
  14. package/lib/cjs/object.js +1 -1
  15. package/lib/cjs/path.js +1 -1
  16. package/lib/cjs/qs.js +1 -1
  17. package/lib/cjs/random.js +1 -1
  18. package/lib/cjs/string.js +1 -1
  19. package/lib/cjs/tooltip.js +1 -1
  20. package/lib/cjs/type.js +1 -1
  21. package/lib/cjs/unique.js +1 -1
  22. package/lib/cjs/url.js +1 -1
  23. package/lib/cjs/watermark.js +1 -1
  24. package/lib/es/array.js +87 -2
  25. package/lib/es/async.js +1 -1
  26. package/lib/es/clipboard.js +1 -1
  27. package/lib/es/cookie.js +1 -1
  28. package/lib/es/date.js +1 -1
  29. package/lib/es/dom.js +1 -1
  30. package/lib/es/download.js +1 -1
  31. package/lib/es/easing.js +1 -1
  32. package/lib/es/file.js +1 -1
  33. package/lib/es/func.js +1 -1
  34. package/lib/es/index.js +2 -2
  35. package/lib/es/number.js +1 -1
  36. package/lib/es/object.js +1 -1
  37. package/lib/es/path.js +1 -1
  38. package/lib/es/qs.js +1 -1
  39. package/lib/es/random.js +1 -1
  40. package/lib/es/string.js +1 -1
  41. package/lib/es/tooltip.js +1 -1
  42. package/lib/es/type.js +1 -1
  43. package/lib/es/unique.js +1 -1
  44. package/lib/es/url.js +1 -1
  45. package/lib/es/watermark.js +1 -1
  46. package/lib/index.d.ts +40 -1
  47. package/lib/umd/index.js +87 -1
  48. package/package.json +7 -6
package/README.md CHANGED
@@ -1,24 +1,121 @@
1
1
  [![Node.js CI](https://github.com/chandq/sculp-js/actions/workflows/node.js.yml/badge.svg)](https://github.com/chandq/sculp-js/actions/workflows/node.js.yml)
2
2
  [![sculp-js](https://img.shields.io/github/package-json/v/chandq/sculp-js?style=flat-square)](https://github.com/chandq/sculp-js)
3
- [![node](https://img.shields.io/badge/node-v12.0.0-blue)](https://nodejs.org/download/release/v12.0.0/)
3
+ [![node](https://img.shields.io/badge/node-v16.0.0-blue)](https://nodejs.org/download/release/v16.0.0/)
4
4
  [![node](https://img.shields.io/badge/language-typescript-orange.svg)](https://nodejs.org/download/release/v12.0.0/)
5
5
  [![license:MIT](https://img.shields.io/npm/l/vue.svg?sanitize=true)](https://github.com/chandq/sculp-js/blob/main/LICENSE.md)
6
6
  [![Downloads:?](https://img.shields.io/npm/dm/sculp-js.svg?sanitize=true)](https://npmcharts.com/compare/sculp-js?minimal=true)
7
+ [![codecov](https://codecov.io/gh/chandq/sculp-js/graph/badge.svg?token=VZ6TERPGI9)](https://codecov.io/gh/chandq/sculp-js)
7
8
 
8
9
  # sculp-js
9
10
 
10
- > TS + Rollup, 原生实现,不依赖任何第三方库,输出 esm、cjs、umd三种模块方式的产物
11
+ [API文档](https://chandq.github.io/sculp-js/)
11
12
 
12
- js 工具函数库, 包含类型判断模块:type, 数据处理模块:`array`、`object`、`string`、`number`,功能性模块:下载`download`、复制`clipboard`、`cookie`、日期`date`、qs、水印`watermark`, 文件处理模块:`file`,自定义悬浮提示模块: `tooltip`, dom处理模块:`dom`;
13
+ > TS + Rollup, native implementation, without relying on any third-party libraries, outputs products of three module modes: ESM, CJS, and UMD
14
+
15
+ ## Features
16
+
17
+ - Type
18
+
19
+ - isString
20
+ - isBoolean
21
+ - isNumber
22
+ - isUndefined
23
+ - isNull
24
+ - isPrimitive
25
+ - isObject
26
+ - typeIs
13
27
 
14
28
  - Array
15
29
 
16
30
  - arrayLike 判断类数组
17
- - arrayEach 可中断的数组遍历, 支持倒序
18
31
  - arrayEachAsync 异步遍历数组,可中断,支持倒序
19
- - arrayInsertBefore 改变数组元素位置
20
- - arrayRemove 数组删除指定元素
21
- - deepTraversal 深度优先遍历函数, 支持continue、break,可定制id、children
22
- - getTreeIds 在树中找到 id 为某个值的节点,并返回上游的所有父级节点
32
+ - forEachDeep 深度优先遍历函数, 支持continue、break,可定制id、children
33
+ - searchTreeById 在树中找到 id 为某个值的节点,并返回上游的所有父级节点
34
+ - buildTree 根据 id 与 parentId 从对象数组中构建对应的树
35
+
36
+ - Object
37
+
38
+ - isPlainObject
39
+ - objectHas
40
+ - objectAssign 合并
41
+ - objectEach
42
+ - objectEachAsync
43
+ - objectGet
44
+
45
+ - Number
46
+
47
+ - formatNumber
48
+
49
+ - String
50
+
51
+ - stringCamelCase
52
+ - stringKebabCase
53
+ - getStrWidthPx
54
+
55
+ - Unique
56
+
57
+ - uniqueString
58
+ - uniqueNumber
59
+
60
+ - Date
61
+
62
+ - formatDate
63
+ - dateToStart
64
+ - dateToEnd
65
+ - calculateDate
66
+ - calculateDateTime
67
+
68
+ - Download
69
+
70
+ - downloadURL
71
+ - downloadHref
72
+ - downloadBlob
73
+ - downloadData
74
+
75
+ - File
76
+
77
+ - chooseLocalFile
78
+
79
+ - Dom
80
+
81
+ - hasClass
82
+ - addClass
83
+ - removeClass
84
+ - setStyle
85
+ - getStyle
86
+ - getComputedCssVal
87
+
88
+ - Watermark
89
+
90
+ - genCanvasWM
91
+
92
+ - Clipboard
93
+ - copyText
94
+
95
+ ## Install
96
+
97
+ ```js
98
+ npm i sculp-js
99
+ ```
100
+
101
+ ## Usage
102
+
103
+ ```js
104
+ import { forEachDeep } from 'sculp-js';
105
+
106
+ const tree = [
107
+ { id: 1, name: 'row1' },
108
+ {
109
+ id: 2,
110
+ name: 'row2',
111
+ children: [{ id: 21, name: 'row2-1' }]
112
+ },
113
+ { id: 3, name: 'row3' }
114
+ ];
23
115
 
24
- ## [API文档详情](https://chandq.github.io/sculp-js/)
116
+ const arr = [];
117
+ forEachDeep(tree, ({ id, name }) => {
118
+ arr.push(name);
119
+ });
120
+ // arr will be: ['row1', 'row2', 'row2-1', 'row3'];
121
+ ```
package/lib/cjs/array.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -198,11 +198,97 @@ function searchTreeById(tree, nodeId, config) {
198
198
  };
199
199
  return getIds(toFlatArray(tree));
200
200
  }
201
+ /**
202
+ * 使用迭代函数转换数组
203
+ * @param {T} array
204
+ * @param {Function} callback 迭代函数
205
+ * @return {Array}
206
+ */
207
+ function flatMap(array, callback) {
208
+ const result = [];
209
+ array.forEach((value, index) => {
210
+ result.push(...callback(value, index, array));
211
+ });
212
+ return result;
213
+ }
214
+ /**
215
+ * 根据 idProp 与 parentIdProp 从对象数组中构建对应的树
216
+ * 当 A[parentIdProp] === B[idProp] 时,对象A会被移动到对象B的children。
217
+ * 当一个对象的 parentIdProp 不与其他对象的 idProp 字段相等时,该对象被作为树的顶层节点
218
+ * @param {string} idProp 元素ID
219
+ * @param {string} parentIdProp 父元素ID
220
+ * @param {object[]} items 一维数组
221
+ * @returns {WithChildren<T>[]} 树
222
+ * @example
223
+ * const array = [
224
+ * { id: 'node-1', parent: 'root' },
225
+ * { id: 'node-2', parent: 'root' },
226
+ * { id: 'node-3', parent: 'node-2' },
227
+ * { id: 'node-4', parent: 'node-2' },
228
+ * { id: 'node-5', parent: 'node-4' },
229
+ * ]
230
+ * const tree = buildTree('id', 'parent', array)
231
+ * expect(tree).toEqual([
232
+ * { id: 'node-1', parent: 'root' },
233
+ * {
234
+ * id: 'node-2',
235
+ * parent: 'root',
236
+ * children: [
237
+ * { id: 'node-3', parent: 'node-2' },
238
+ * {
239
+ * id: 'node-4',
240
+ * parent: 'node-2',
241
+ * children: [{ id: 'node-5', parent: 'node-4' }],
242
+ * },
243
+ * ],
244
+ * },
245
+ * ])
246
+ */
247
+ function buildTree(idProp, parentIdProp, items) {
248
+ const wrapperMap = new Map();
249
+ const ensure = (id) => {
250
+ if (wrapperMap.has(id)) {
251
+ return wrapperMap.get(id);
252
+ }
253
+ //@ts-ignore
254
+ const wrapper = { id, parent: null, item: null, children: [] };
255
+ wrapperMap.set(id, wrapper);
256
+ return wrapper;
257
+ };
258
+ for (const item of items) {
259
+ const parentWrapper = ensure(item[parentIdProp]);
260
+ const itemWrapper = ensure(item[idProp]);
261
+ //@ts-ignore
262
+ itemWrapper.parent = parentWrapper;
263
+ //@ts-ignore
264
+ parentWrapper.children.push(itemWrapper);
265
+ //@ts-ignore
266
+ itemWrapper.item = item;
267
+ }
268
+ const topLevelWrappers = flatMap(Array.from(wrapperMap.values()).filter(wrapper => wrapper.parent === null), wrapper => wrapper.children);
269
+ return unwrapRecursively(topLevelWrappers);
270
+ function unwrapRecursively(wrapperArray) {
271
+ const result = [];
272
+ for (const wrapper of wrapperArray) {
273
+ if (wrapper.children.length === 0) {
274
+ result.push(wrapper.item);
275
+ }
276
+ else {
277
+ result.push({
278
+ ...wrapper.item,
279
+ children: unwrapRecursively(wrapper.children)
280
+ });
281
+ }
282
+ }
283
+ return result;
284
+ }
285
+ }
201
286
 
202
287
  exports.arrayEach = arrayEach;
203
288
  exports.arrayEachAsync = arrayEachAsync;
204
289
  exports.arrayInsertBefore = arrayInsertBefore;
205
290
  exports.arrayLike = arrayLike;
206
291
  exports.arrayRemove = arrayRemove;
292
+ exports.buildTree = buildTree;
207
293
  exports.forEachDeep = forEachDeep;
208
294
  exports.searchTreeById = searchTreeById;
package/lib/cjs/async.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/cjs/cookie.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/cjs/date.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/cjs/dom.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/cjs/easing.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/cjs/file.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/cjs/func.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/cjs/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -34,6 +34,7 @@ exports.arrayEachAsync = array.arrayEachAsync;
34
34
  exports.arrayInsertBefore = array.arrayInsertBefore;
35
35
  exports.arrayLike = array.arrayLike;
36
36
  exports.arrayRemove = array.arrayRemove;
37
+ exports.buildTree = array.buildTree;
37
38
  exports.forEachDeep = array.forEachDeep;
38
39
  exports.searchTreeById = array.searchTreeById;
39
40
  exports.copyText = clipboard.copyText;
package/lib/cjs/number.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/cjs/object.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/cjs/path.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/cjs/qs.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/cjs/random.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/cjs/string.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/cjs/type.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/cjs/unique.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/cjs/url.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/array.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -196,5 +196,90 @@ function searchTreeById(tree, nodeId, config) {
196
196
  };
197
197
  return getIds(toFlatArray(tree));
198
198
  }
199
+ /**
200
+ * 使用迭代函数转换数组
201
+ * @param {T} array
202
+ * @param {Function} callback 迭代函数
203
+ * @return {Array}
204
+ */
205
+ function flatMap(array, callback) {
206
+ const result = [];
207
+ array.forEach((value, index) => {
208
+ result.push(...callback(value, index, array));
209
+ });
210
+ return result;
211
+ }
212
+ /**
213
+ * 根据 idProp 与 parentIdProp 从对象数组中构建对应的树
214
+ * 当 A[parentIdProp] === B[idProp] 时,对象A会被移动到对象B的children。
215
+ * 当一个对象的 parentIdProp 不与其他对象的 idProp 字段相等时,该对象被作为树的顶层节点
216
+ * @param {string} idProp 元素ID
217
+ * @param {string} parentIdProp 父元素ID
218
+ * @param {object[]} items 一维数组
219
+ * @returns {WithChildren<T>[]} 树
220
+ * @example
221
+ * const array = [
222
+ * { id: 'node-1', parent: 'root' },
223
+ * { id: 'node-2', parent: 'root' },
224
+ * { id: 'node-3', parent: 'node-2' },
225
+ * { id: 'node-4', parent: 'node-2' },
226
+ * { id: 'node-5', parent: 'node-4' },
227
+ * ]
228
+ * const tree = buildTree('id', 'parent', array)
229
+ * expect(tree).toEqual([
230
+ * { id: 'node-1', parent: 'root' },
231
+ * {
232
+ * id: 'node-2',
233
+ * parent: 'root',
234
+ * children: [
235
+ * { id: 'node-3', parent: 'node-2' },
236
+ * {
237
+ * id: 'node-4',
238
+ * parent: 'node-2',
239
+ * children: [{ id: 'node-5', parent: 'node-4' }],
240
+ * },
241
+ * ],
242
+ * },
243
+ * ])
244
+ */
245
+ function buildTree(idProp, parentIdProp, items) {
246
+ const wrapperMap = new Map();
247
+ const ensure = (id) => {
248
+ if (wrapperMap.has(id)) {
249
+ return wrapperMap.get(id);
250
+ }
251
+ //@ts-ignore
252
+ const wrapper = { id, parent: null, item: null, children: [] };
253
+ wrapperMap.set(id, wrapper);
254
+ return wrapper;
255
+ };
256
+ for (const item of items) {
257
+ const parentWrapper = ensure(item[parentIdProp]);
258
+ const itemWrapper = ensure(item[idProp]);
259
+ //@ts-ignore
260
+ itemWrapper.parent = parentWrapper;
261
+ //@ts-ignore
262
+ parentWrapper.children.push(itemWrapper);
263
+ //@ts-ignore
264
+ itemWrapper.item = item;
265
+ }
266
+ const topLevelWrappers = flatMap(Array.from(wrapperMap.values()).filter(wrapper => wrapper.parent === null), wrapper => wrapper.children);
267
+ return unwrapRecursively(topLevelWrappers);
268
+ function unwrapRecursively(wrapperArray) {
269
+ const result = [];
270
+ for (const wrapper of wrapperArray) {
271
+ if (wrapper.children.length === 0) {
272
+ result.push(wrapper.item);
273
+ }
274
+ else {
275
+ result.push({
276
+ ...wrapper.item,
277
+ children: unwrapRecursively(wrapper.children)
278
+ });
279
+ }
280
+ }
281
+ return result;
282
+ }
283
+ }
199
284
 
200
- export { arrayEach, arrayEachAsync, arrayInsertBefore, arrayLike, arrayRemove, forEachDeep, searchTreeById };
285
+ export { arrayEach, arrayEachAsync, arrayInsertBefore, arrayLike, arrayRemove, buildTree, forEachDeep, searchTreeById };
package/lib/es/async.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/cookie.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/date.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/dom.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/easing.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/file.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/func.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
6
6
 
7
- export { arrayEach, arrayEachAsync, arrayInsertBefore, arrayLike, arrayRemove, forEachDeep, searchTreeById } from './array.js';
7
+ export { arrayEach, arrayEachAsync, arrayInsertBefore, arrayLike, arrayRemove, buildTree, forEachDeep, searchTreeById } from './array.js';
8
8
  export { copyText } from './clipboard.js';
9
9
  export { cookieDel, cookieGet, cookieSet } from './cookie.js';
10
10
  export { calculateDate, calculateDateTime, dateParse, dateToEnd, dateToStart, formatDate, isValidDate } from './date.js';
package/lib/es/number.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/object.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/path.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/qs.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/random.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/string.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/tooltip.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/type.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/unique.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/es/url.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
package/lib/index.d.ts CHANGED
@@ -97,6 +97,45 @@ interface ITreeConf {
97
97
  * @returns {[IdLike[], ITreeItem<V>[]]} - 由parentId...childId, parentObject-childObject组成的二维数组
98
98
  */
99
99
  declare function searchTreeById<V>(tree: ArrayLike<V>, nodeId: IdLike, config?: ITreeConf): [IdLike[], ArrayLike<V>[]];
100
+ type WithChildren<T> = T & {
101
+ children?: WithChildren<T>[];
102
+ };
103
+ /**
104
+ * 根据 idProp 与 parentIdProp 从对象数组中构建对应的树
105
+ * 当 A[parentIdProp] === B[idProp] 时,对象A会被移动到对象B的children。
106
+ * 当一个对象的 parentIdProp 不与其他对象的 idProp 字段相等时,该对象被作为树的顶层节点
107
+ * @param {string} idProp 元素ID
108
+ * @param {string} parentIdProp 父元素ID
109
+ * @param {object[]} items 一维数组
110
+ * @returns {WithChildren<T>[]} 树
111
+ * @example
112
+ * const array = [
113
+ * { id: 'node-1', parent: 'root' },
114
+ * { id: 'node-2', parent: 'root' },
115
+ * { id: 'node-3', parent: 'node-2' },
116
+ * { id: 'node-4', parent: 'node-2' },
117
+ * { id: 'node-5', parent: 'node-4' },
118
+ * ]
119
+ * const tree = buildTree('id', 'parent', array)
120
+ * expect(tree).toEqual([
121
+ * { id: 'node-1', parent: 'root' },
122
+ * {
123
+ * id: 'node-2',
124
+ * parent: 'root',
125
+ * children: [
126
+ * { id: 'node-3', parent: 'node-2' },
127
+ * {
128
+ * id: 'node-4',
129
+ * parent: 'node-2',
130
+ * children: [{ id: 'node-5', parent: 'node-4' }],
131
+ * },
132
+ * ],
133
+ * },
134
+ * ])
135
+ */
136
+ declare function buildTree<ID extends string, PID extends string, T extends {
137
+ [key in ID | PID]: string;
138
+ }>(idProp: ID, parentIdProp: PID, items: T[]): WithChildren<T>[];
100
139
 
101
140
  /**
102
141
  * 复制文本
@@ -706,4 +745,4 @@ declare const tooltipEvent: {
706
745
  handleMouseLeave: typeof handleMouseLeave;
707
746
  };
708
747
 
709
- export { type AnyArray, type AnyFunc, type AnyObject, type ArrayElements, type DateObj, type DateValue, type DebounceFunc, type FileType, HEX_POOL, type ICanvasWM, type ITreeConf, type IdLike, type LooseParamValue, type LooseParams, type ObjectAssignItem, type OnceFunc, type Params, type PartialDeep, type RandomString, type ReadyCallback, type Replacer, STRING_ARABIC_NUMERALS, STRING_LOWERCASE_ALPHA, STRING_POOL, STRING_UPPERCASE_ALPHA, type SetStyle, type SmoothScrollOptions, type Style, type ThrottleFunc, UNIQUE_NUMBER_SAFE_LENGTH, type UniqueString, type Url, addClass, arrayEach, arrayEachAsync, arrayInsertBefore, arrayLike, arrayRemove, asyncMap, calculateDate, calculateDateTime, chooseLocalFile, cloneDeep, cookieDel, cookieGet, cookieSet, copyText, dateParse, dateToEnd, dateToStart, debounce, downloadBlob, downloadData, downloadHref, downloadURL, forEachDeep, formatDate, formatNumber, genCanvasWM, getComputedCssVal, getGlobal, getStrWidthPx, getStyle, hasClass, isArray, isBigInt, isBoolean, isDate, isDomReady, isError, isFunction, isNaN, isNull, isNumber, isObject, isPlainObject, isPrimitive, isRegExp, isString, isSymbol, isUndefined, isValidDate, numberAbbr, numberToHex, objectAssign, objectEach, objectEachAsync, objectFill, objectGet, objectHas, objectMap, objectAssign as objectMerge, objectOmit, objectPick, onDomReady, once, pathJoin, pathNormalize, qsParse, qsStringify, randomNumber, randomString, randomUuid, removeClass, searchTreeById, setGlobal, setStyle, smoothScroll, stringAssign, stringCamelCase, stringEscapeHtml, stringFill, stringFormat, stringKebabCase, throttle, tooltipEvent, typeIs, uniqueNumber, uniqueString, urlDelParams, urlParse, urlSetParams, urlStringify, wait };
748
+ export { type AnyArray, type AnyFunc, type AnyObject, type ArrayElements, type DateObj, type DateValue, type DebounceFunc, type FileType, HEX_POOL, type ICanvasWM, type ITreeConf, type IdLike, type LooseParamValue, type LooseParams, type ObjectAssignItem, type OnceFunc, type Params, type PartialDeep, type RandomString, type ReadyCallback, type Replacer, STRING_ARABIC_NUMERALS, STRING_LOWERCASE_ALPHA, STRING_POOL, STRING_UPPERCASE_ALPHA, type SetStyle, type SmoothScrollOptions, type Style, type ThrottleFunc, UNIQUE_NUMBER_SAFE_LENGTH, type UniqueString, type Url, type WithChildren, addClass, arrayEach, arrayEachAsync, arrayInsertBefore, arrayLike, arrayRemove, asyncMap, buildTree, calculateDate, calculateDateTime, chooseLocalFile, cloneDeep, cookieDel, cookieGet, cookieSet, copyText, dateParse, dateToEnd, dateToStart, debounce, downloadBlob, downloadData, downloadHref, downloadURL, forEachDeep, formatDate, formatNumber, genCanvasWM, getComputedCssVal, getGlobal, getStrWidthPx, getStyle, hasClass, isArray, isBigInt, isBoolean, isDate, isDomReady, isError, isFunction, isNaN, isNull, isNumber, isObject, isPlainObject, isPrimitive, isRegExp, isString, isSymbol, isUndefined, isValidDate, numberAbbr, numberToHex, objectAssign, objectEach, objectEachAsync, objectFill, objectGet, objectHas, objectMap, objectAssign as objectMerge, objectOmit, objectPick, onDomReady, once, pathJoin, pathNormalize, qsParse, qsStringify, randomNumber, randomString, randomUuid, removeClass, searchTreeById, setGlobal, setStyle, smoothScroll, stringAssign, stringCamelCase, stringEscapeHtml, stringFill, stringFormat, stringKebabCase, throttle, tooltipEvent, typeIs, uniqueNumber, uniqueString, urlDelParams, urlParse, urlSetParams, urlStringify, wait };
package/lib/umd/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.0.1
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -450,6 +450,91 @@
450
450
  };
451
451
  return getIds(toFlatArray(tree));
452
452
  }
453
+ /**
454
+ * 使用迭代函数转换数组
455
+ * @param {T} array
456
+ * @param {Function} callback 迭代函数
457
+ * @return {Array}
458
+ */
459
+ function flatMap(array, callback) {
460
+ const result = [];
461
+ array.forEach((value, index) => {
462
+ result.push(...callback(value, index, array));
463
+ });
464
+ return result;
465
+ }
466
+ /**
467
+ * 根据 idProp 与 parentIdProp 从对象数组中构建对应的树
468
+ * 当 A[parentIdProp] === B[idProp] 时,对象A会被移动到对象B的children。
469
+ * 当一个对象的 parentIdProp 不与其他对象的 idProp 字段相等时,该对象被作为树的顶层节点
470
+ * @param {string} idProp 元素ID
471
+ * @param {string} parentIdProp 父元素ID
472
+ * @param {object[]} items 一维数组
473
+ * @returns {WithChildren<T>[]} 树
474
+ * @example
475
+ * const array = [
476
+ * { id: 'node-1', parent: 'root' },
477
+ * { id: 'node-2', parent: 'root' },
478
+ * { id: 'node-3', parent: 'node-2' },
479
+ * { id: 'node-4', parent: 'node-2' },
480
+ * { id: 'node-5', parent: 'node-4' },
481
+ * ]
482
+ * const tree = buildTree('id', 'parent', array)
483
+ * expect(tree).toEqual([
484
+ * { id: 'node-1', parent: 'root' },
485
+ * {
486
+ * id: 'node-2',
487
+ * parent: 'root',
488
+ * children: [
489
+ * { id: 'node-3', parent: 'node-2' },
490
+ * {
491
+ * id: 'node-4',
492
+ * parent: 'node-2',
493
+ * children: [{ id: 'node-5', parent: 'node-4' }],
494
+ * },
495
+ * ],
496
+ * },
497
+ * ])
498
+ */
499
+ function buildTree(idProp, parentIdProp, items) {
500
+ const wrapperMap = new Map();
501
+ const ensure = (id) => {
502
+ if (wrapperMap.has(id)) {
503
+ return wrapperMap.get(id);
504
+ }
505
+ //@ts-ignore
506
+ const wrapper = { id, parent: null, item: null, children: [] };
507
+ wrapperMap.set(id, wrapper);
508
+ return wrapper;
509
+ };
510
+ for (const item of items) {
511
+ const parentWrapper = ensure(item[parentIdProp]);
512
+ const itemWrapper = ensure(item[idProp]);
513
+ //@ts-ignore
514
+ itemWrapper.parent = parentWrapper;
515
+ //@ts-ignore
516
+ parentWrapper.children.push(itemWrapper);
517
+ //@ts-ignore
518
+ itemWrapper.item = item;
519
+ }
520
+ const topLevelWrappers = flatMap(Array.from(wrapperMap.values()).filter(wrapper => wrapper.parent === null), wrapper => wrapper.children);
521
+ return unwrapRecursively(topLevelWrappers);
522
+ function unwrapRecursively(wrapperArray) {
523
+ const result = [];
524
+ for (const wrapper of wrapperArray) {
525
+ if (wrapper.children.length === 0) {
526
+ result.push(wrapper.item);
527
+ }
528
+ else {
529
+ result.push({
530
+ ...wrapper.item,
531
+ children: unwrapRecursively(wrapper.children)
532
+ });
533
+ }
534
+ }
535
+ return result;
536
+ }
537
+ }
453
538
 
454
539
  // @ref https://cubic-bezier.com/
455
540
  const easingDefines = {
@@ -1925,6 +2010,7 @@
1925
2010
  exports.arrayLike = arrayLike;
1926
2011
  exports.arrayRemove = arrayRemove;
1927
2012
  exports.asyncMap = asyncMap;
2013
+ exports.buildTree = buildTree;
1928
2014
  exports.calculateDate = calculateDate;
1929
2015
  exports.calculateDateTime = calculateDateTime;
1930
2016
  exports.chooseLocalFile = chooseLocalFile;
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "sculp-js",
3
- "version": "1.0.1",
4
- "private": false,
3
+ "version": "1.1.0",
4
+ "packageManager": "npm@8.19.2",
5
5
  "description": "js工具库",
6
6
  "scripts": {
7
7
  "prepare": "husky install",
8
- "build": "NODE_OPTIONS=--max-old-space-size=2048 rollup --bundleConfigAsCjs --config rollup.config.js",
8
+ "build": "rollup --bundleConfigAsCjs --config rollup.config.js",
9
9
  "build:terser": "node scripts/build.js",
10
10
  "test:unit": "jest",
11
11
  "test": "jest --coverage",
12
+ "coveralls": "jest --coverage --coverageReporters=text-lcov | coveralls",
12
13
  "lint": "eslint ./src --ext .vue,.js,jsx,.ts,tsx",
13
14
  "lint:fix": "eslint --fix ./src --ext .vue,.js,jsx,.ts,tsx",
14
15
  "prettier": "prettier -c --write \"**/*.{vue,ts,js,jsx,css,less,scss,json}\"",
@@ -35,11 +36,11 @@
35
36
  "lib"
36
37
  ],
37
38
  "keywords": [
38
- "js-utils",
39
- "utils"
39
+ "typescript",
40
+ "js-utils"
40
41
  ],
41
42
  "engines": {
42
- "node": ">=12.0.0"
43
+ "node": ">=16"
43
44
  },
44
45
  "repository": "git@github.com:chandq/sculp-js.git",
45
46
  "dependencies": {