sculp-js 1.0.1 → 1.2.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 (50) hide show
  1. package/README.md +105 -9
  2. package/lib/cjs/array.js +1 -92
  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 +6 -3
  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/tree.js +212 -0
  21. package/lib/cjs/type.js +1 -1
  22. package/lib/cjs/unique.js +1 -1
  23. package/lib/cjs/url.js +1 -1
  24. package/lib/cjs/watermark.js +1 -1
  25. package/lib/es/array.js +2 -91
  26. package/lib/es/async.js +1 -1
  27. package/lib/es/clipboard.js +1 -1
  28. package/lib/es/cookie.js +1 -1
  29. package/lib/es/date.js +1 -1
  30. package/lib/es/dom.js +1 -1
  31. package/lib/es/download.js +1 -1
  32. package/lib/es/easing.js +1 -1
  33. package/lib/es/file.js +1 -1
  34. package/lib/es/func.js +1 -1
  35. package/lib/es/index.js +3 -2
  36. package/lib/es/number.js +1 -1
  37. package/lib/es/object.js +1 -1
  38. package/lib/es/path.js +1 -1
  39. package/lib/es/qs.js +1 -1
  40. package/lib/es/random.js +1 -1
  41. package/lib/es/string.js +1 -1
  42. package/lib/es/tooltip.js +1 -1
  43. package/lib/es/tree.js +207 -0
  44. package/lib/es/type.js +1 -1
  45. package/lib/es/unique.js +1 -1
  46. package/lib/es/url.js +1 -1
  47. package/lib/es/watermark.js +1 -1
  48. package/lib/index.d.ts +77 -25
  49. package/lib/umd/index.js +203 -90
  50. package/package.json +10 -6
package/lib/umd/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.0.0
2
+ * sculp-js v1.1.0
3
3
  * (c) 2023-2023 chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -361,95 +361,6 @@
361
361
  indexes.forEach((val, idx) => array.splice(val - idx, 1));
362
362
  return array;
363
363
  }
364
- /**
365
- * 自定义深度优先遍历函数(支持continue和break操作)
366
- * @param {ArrayLike<V>} tree 树形数据
367
- * @param {Function} iterator 迭代函数, 返回值为true时continue, 返回值为false时break
368
- * @param {string} children 定制子元素的key
369
- * @param {boolean} isReverse 是否反向遍历
370
- * @returns {*}
371
- */
372
- function forEachDeep(tree, iterator, children = 'children', isReverse = false) {
373
- let level = 0, isBreak = false;
374
- const walk = (arr, parent) => {
375
- if (isReverse) {
376
- for (let i = arr.length - 1; i >= 0; i--) {
377
- if (isBreak) {
378
- break;
379
- }
380
- const re = iterator(arr[i], i, tree, parent, level);
381
- if (re === false) {
382
- isBreak = true;
383
- break;
384
- }
385
- else if (re === true) {
386
- continue;
387
- }
388
- // @ts-ignore
389
- if (Array.isArray(arr[i][children])) {
390
- ++level;
391
- // @ts-ignore
392
- walk(arr[i][children], arr[i]);
393
- }
394
- }
395
- }
396
- else {
397
- for (let i = 0; i < arr.length; i++) {
398
- if (isBreak) {
399
- break;
400
- }
401
- const re = iterator(arr[i], i, tree, parent, level);
402
- if (re === false) {
403
- isBreak = true;
404
- break;
405
- }
406
- else if (re === true) {
407
- continue;
408
- }
409
- // @ts-ignore
410
- if (Array.isArray(arr[i][children])) {
411
- ++level;
412
- // @ts-ignore
413
- walk(arr[i][children], arr[i]);
414
- }
415
- }
416
- }
417
- };
418
- walk(tree, null);
419
- }
420
- /**
421
- * 在树中找到 id 为某个值的节点,并返回上游的所有父级节点
422
- *
423
- * @param {ArrayLike<T>} tree - 树形数据
424
- * @param {IdLike} nodeId - 元素ID
425
- * @param {ITreeConf} config - 迭代配置项
426
- * @returns {[IdLike[], ITreeItem<V>[]]} - 由parentId...childId, parentObject-childObject组成的二维数组
427
- */
428
- function searchTreeById(tree, nodeId, config) {
429
- const { children = 'children', id = 'id' } = config || {};
430
- const toFlatArray = (tree, parentId, parent) => {
431
- return tree.reduce((t, _) => {
432
- const child = _[children];
433
- return [
434
- ...t,
435
- parentId ? { ..._, parentId, parent } : _,
436
- ...(child && child.length ? toFlatArray(child, _[id], _) : [])
437
- ];
438
- }, []);
439
- };
440
- const getIds = (flatArray) => {
441
- let child = flatArray.find(_ => _[id] === nodeId);
442
- const { parent, parentId, ...other } = child;
443
- let ids = [nodeId], nodes = [other];
444
- while (child && child.parentId) {
445
- ids = [child.parentId, ...ids];
446
- nodes = [child.parent, ...nodes];
447
- child = flatArray.find(_ => _[id] === child.parentId); // eslint-disable-line
448
- }
449
- return [ids, nodes];
450
- };
451
- return getIds(toFlatArray(tree));
452
- }
453
364
 
454
365
  // @ref https://cubic-bezier.com/
455
366
  const easingDefines = {
@@ -1912,6 +1823,206 @@
1912
1823
  }
1913
1824
  const tooltipEvent = { handleMouseEnter, handleMouseLeave };
1914
1825
 
1826
+ const defaultFieldOptions = { keyField: 'key', childField: 'children', pidField: 'pid' };
1827
+ /**
1828
+ * 自定义深度优先遍历函数(支持continue和break操作), 可用于insert tree item 和 remove tree item
1829
+ * @param {ArrayLike<V>} tree 树形数据
1830
+ * @param {Function} iterator 迭代函数, 返回值为true时continue, 返回值为false时break
1831
+ * @param {string} children 定制子元素的key
1832
+ * @param {boolean} isReverse 是否反向遍历
1833
+ * @returns {*}
1834
+ */
1835
+ function forEachDeep(tree, iterator, children = 'children', isReverse = false) {
1836
+ let level = 0, isBreak = false;
1837
+ const walk = (arr, parent) => {
1838
+ if (isReverse) {
1839
+ for (let i = arr.length - 1; i >= 0; i--) {
1840
+ if (isBreak) {
1841
+ break;
1842
+ }
1843
+ const re = iterator(arr[i], i, arr, tree, parent, level);
1844
+ if (re === false) {
1845
+ isBreak = true;
1846
+ break;
1847
+ }
1848
+ else if (re === true) {
1849
+ continue;
1850
+ }
1851
+ // @ts-ignore
1852
+ if (arr[i] && Array.isArray(arr[i][children])) {
1853
+ ++level;
1854
+ // @ts-ignore
1855
+ walk(arr[i][children], arr[i]);
1856
+ }
1857
+ }
1858
+ }
1859
+ else {
1860
+ for (let i = 0; i < arr.length; i++) {
1861
+ if (isBreak) {
1862
+ break;
1863
+ }
1864
+ const re = iterator(arr[i], i, arr, tree, parent, level);
1865
+ if (re === false) {
1866
+ isBreak = true;
1867
+ break;
1868
+ }
1869
+ else if (re === true) {
1870
+ continue;
1871
+ }
1872
+ // @ts-ignore
1873
+ if (arr[i] && Array.isArray(arr[i][children])) {
1874
+ ++level;
1875
+ // @ts-ignore
1876
+ walk(arr[i][children], arr[i]);
1877
+ }
1878
+ }
1879
+ }
1880
+ };
1881
+ walk(tree, null);
1882
+ }
1883
+ /**
1884
+ * 在树中找到 id 为某个值的节点,并返回上游的所有父级节点
1885
+ *
1886
+ * @param {ArrayLike<T>} tree - 树形数据
1887
+ * @param {IdLike} nodeId - 元素ID
1888
+ * @param {ITreeConf} config - 迭代配置项
1889
+ * @returns {[IdLike[], ITreeItem<V>[]]} - 由parentId...childId, parentObject-childObject组成的二维数组
1890
+ */
1891
+ function searchTreeById(tree, nodeId, config) {
1892
+ const { children = 'children', id = 'id' } = config || {};
1893
+ const toFlatArray = (tree, parentId, parent) => {
1894
+ return tree.reduce((t, _) => {
1895
+ const child = _[children];
1896
+ return [
1897
+ ...t,
1898
+ parentId ? { ..._, parentId, parent } : _,
1899
+ ...(child && child.length ? toFlatArray(child, _[id], _) : [])
1900
+ ];
1901
+ }, []);
1902
+ };
1903
+ const getIds = (flatArray) => {
1904
+ let child = flatArray.find(_ => _[id] === nodeId);
1905
+ const { parent, parentId, ...other } = child;
1906
+ let ids = [nodeId], nodes = [other];
1907
+ while (child && child.parentId) {
1908
+ ids = [child.parentId, ...ids];
1909
+ nodes = [child.parent, ...nodes];
1910
+ child = flatArray.find(_ => _[id] === child.parentId); // eslint-disable-line
1911
+ }
1912
+ return [ids, nodes];
1913
+ };
1914
+ return getIds(toFlatArray(tree));
1915
+ }
1916
+ /**
1917
+ * 使用迭代函数转换数组
1918
+ * @param {T} array
1919
+ * @param {Function} callback 迭代函数
1920
+ * @returns {Array}
1921
+ */
1922
+ function flatMap(array, callback) {
1923
+ const result = [];
1924
+ array.forEach((value, index) => {
1925
+ result.push(...callback(value, index, array));
1926
+ });
1927
+ return result;
1928
+ }
1929
+ /**
1930
+ * 根据 idProp 与 parentIdProp 从对象数组中构建对应的树
1931
+ * 当 A[parentIdProp] === B[idProp] 时,对象A会被移动到对象B的children。
1932
+ * 当一个对象的 parentIdProp 不与其他对象的 idProp 字段相等时,该对象被作为树的顶层节点
1933
+ * @param {string} idProp 元素ID
1934
+ * @param {string} parentIdProp 父元素ID
1935
+ * @param {object[]} items 一维数组
1936
+ * @returns {WithChildren<T>[]} 树
1937
+ * @example
1938
+ * const array = [
1939
+ * { id: 'node-1', parent: 'root' },
1940
+ * { id: 'node-2', parent: 'root' },
1941
+ * { id: 'node-3', parent: 'node-2' },
1942
+ * { id: 'node-4', parent: 'node-2' },
1943
+ * { id: 'node-5', parent: 'node-4' },
1944
+ * ]
1945
+ * const tree = buildTree('id', 'parent', array)
1946
+ * expect(tree).toEqual([
1947
+ * { id: 'node-1', parent: 'root' },
1948
+ * {
1949
+ * id: 'node-2',
1950
+ * parent: 'root',
1951
+ * children: [
1952
+ * { id: 'node-3', parent: 'node-2' },
1953
+ * {
1954
+ * id: 'node-4',
1955
+ * parent: 'node-2',
1956
+ * children: [{ id: 'node-5', parent: 'node-4' }],
1957
+ * },
1958
+ * ],
1959
+ * },
1960
+ * ])
1961
+ */
1962
+ function buildTree(idProp, parentIdProp, items) {
1963
+ const wrapperMap = new Map();
1964
+ const ensure = (id) => {
1965
+ if (wrapperMap.has(id)) {
1966
+ return wrapperMap.get(id);
1967
+ }
1968
+ //@ts-ignore
1969
+ const wrapper = { id, parent: null, item: null, children: [] };
1970
+ wrapperMap.set(id, wrapper);
1971
+ return wrapper;
1972
+ };
1973
+ for (const item of items) {
1974
+ const parentWrapper = ensure(item[parentIdProp]);
1975
+ const itemWrapper = ensure(item[idProp]);
1976
+ //@ts-ignore
1977
+ itemWrapper.parent = parentWrapper;
1978
+ //@ts-ignore
1979
+ parentWrapper.children.push(itemWrapper);
1980
+ //@ts-ignore
1981
+ itemWrapper.item = item;
1982
+ }
1983
+ const topLevelWrappers = flatMap(Array.from(wrapperMap.values()).filter(wrapper => wrapper.parent === null), wrapper => wrapper.children);
1984
+ return unwrapRecursively(topLevelWrappers);
1985
+ function unwrapRecursively(wrapperArray) {
1986
+ const result = [];
1987
+ for (const wrapper of wrapperArray) {
1988
+ if (wrapper.children.length === 0) {
1989
+ result.push(wrapper.item);
1990
+ }
1991
+ else {
1992
+ result.push({
1993
+ ...wrapper.item,
1994
+ children: unwrapRecursively(wrapper.children)
1995
+ });
1996
+ }
1997
+ }
1998
+ return result;
1999
+ }
2000
+ }
2001
+ /**
2002
+ * 扁平化数组转换成树(效率高于buildTree)
2003
+ * @param {any[]} list
2004
+ * @param {IFieldOptions} options
2005
+ * @returns {any[]}
2006
+ */
2007
+ function formatTree(list, options = defaultFieldOptions) {
2008
+ const { keyField, childField, pidField } = options;
2009
+ const treeArr = [];
2010
+ const sourceMap = {};
2011
+ list.forEach(item => {
2012
+ sourceMap[item[keyField]] = item;
2013
+ });
2014
+ list.forEach(item => {
2015
+ const parent = sourceMap[item[pidField]];
2016
+ if (parent) {
2017
+ (parent[childField] || (parent[childField] = [])).push(item);
2018
+ }
2019
+ else {
2020
+ treeArr.push(item);
2021
+ }
2022
+ });
2023
+ return treeArr;
2024
+ }
2025
+
1915
2026
  exports.HEX_POOL = HEX_POOL;
1916
2027
  exports.STRING_ARABIC_NUMERALS = STRING_ARABIC_NUMERALS;
1917
2028
  exports.STRING_LOWERCASE_ALPHA = STRING_LOWERCASE_ALPHA;
@@ -1925,6 +2036,7 @@
1925
2036
  exports.arrayLike = arrayLike;
1926
2037
  exports.arrayRemove = arrayRemove;
1927
2038
  exports.asyncMap = asyncMap;
2039
+ exports.buildTree = buildTree;
1928
2040
  exports.calculateDate = calculateDate;
1929
2041
  exports.calculateDateTime = calculateDateTime;
1930
2042
  exports.chooseLocalFile = chooseLocalFile;
@@ -1944,6 +2056,7 @@
1944
2056
  exports.forEachDeep = forEachDeep;
1945
2057
  exports.formatDate = formatDate;
1946
2058
  exports.formatNumber = formatNumber;
2059
+ exports.formatTree = formatTree;
1947
2060
  exports.genCanvasWM = genCanvasWM;
1948
2061
  exports.getComputedCssVal = getComputedCssVal;
1949
2062
  exports.getGlobal = getGlobal;
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.2.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}\"",
@@ -21,6 +22,7 @@
21
22
  "main": "lib/cjs/index.js",
22
23
  "module": "lib/es/index.js",
23
24
  "browser": "lib/umd/index.js",
25
+ "unpkg": "lib/umd/index.js",
24
26
  "types": "lib/index.d.ts",
25
27
  "typings": "lib/index.d.ts",
26
28
  "exports": {
@@ -35,13 +37,15 @@
35
37
  "lib"
36
38
  ],
37
39
  "keywords": [
38
- "js-utils",
39
- "utils"
40
+ "typescript",
41
+ "js-utils"
40
42
  ],
41
43
  "engines": {
42
- "node": ">=12.0.0"
44
+ "node": ">=16"
43
45
  },
44
46
  "repository": "git@github.com:chandq/sculp-js.git",
47
+ "license": "MIT",
48
+ "homepage": "https://github.com/chandq/sculp-js#readme",
45
49
  "dependencies": {
46
50
  "bezier-easing": "^2.1.0",
47
51
  "core-js": "^3.33.0"