a2bei4-utils 1.0.9 → 1.0.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.
Files changed (44) hide show
  1. package/dist/a2bei4.utils.cjs.js +193 -2
  2. package/dist/a2bei4.utils.cjs.js.map +1 -1
  3. package/dist/a2bei4.utils.cjs.min.js +1 -1
  4. package/dist/a2bei4.utils.cjs.min.js.map +1 -1
  5. package/dist/a2bei4.utils.esm.js +191 -2
  6. package/dist/a2bei4.utils.esm.js.map +1 -1
  7. package/dist/a2bei4.utils.esm.min.js +1 -1
  8. package/dist/a2bei4.utils.esm.min.js.map +1 -1
  9. package/dist/a2bei4.utils.umd.js +193 -2
  10. package/dist/a2bei4.utils.umd.js.map +1 -1
  11. package/dist/a2bei4.utils.umd.min.js +1 -1
  12. package/dist/a2bei4.utils.umd.min.js.map +1 -1
  13. package/dist/arr.cjs.map +1 -1
  14. package/dist/arr.js.map +1 -1
  15. package/dist/audio.cjs.map +1 -1
  16. package/dist/audio.js.map +1 -1
  17. package/dist/browser.cjs.map +1 -1
  18. package/dist/browser.js.map +1 -1
  19. package/dist/common.cjs.map +1 -1
  20. package/dist/common.js.map +1 -1
  21. package/dist/date.cjs.map +1 -1
  22. package/dist/date.js.map +1 -1
  23. package/dist/download.cjs.map +1 -1
  24. package/dist/download.js.map +1 -1
  25. package/dist/evt.cjs.map +1 -1
  26. package/dist/evt.js.map +1 -1
  27. package/dist/id.cjs.map +1 -1
  28. package/dist/id.js.map +1 -1
  29. package/dist/menu.cjs.map +1 -1
  30. package/dist/menu.js.map +1 -1
  31. package/dist/timer.cjs +14 -0
  32. package/dist/timer.cjs.map +1 -1
  33. package/dist/timer.js +14 -0
  34. package/dist/timer.js.map +1 -1
  35. package/dist/tree.cjs +177 -0
  36. package/dist/tree.cjs.map +1 -1
  37. package/dist/tree.js +176 -1
  38. package/dist/tree.js.map +1 -1
  39. package/dist/webSocket.cjs.map +1 -1
  40. package/dist/webSocket.js.map +1 -1
  41. package/package.json +5 -5
  42. package/types/index.d.ts +186 -2
  43. package/types/timer.d.ts +4 -0
  44. package/types/tree.d.ts +182 -1
@@ -568,7 +568,7 @@ registerProcessor('audio-stream-resampler-processor', AudioStreamResamplerProces
568
568
  * @param {*} obj - 待检测的值
569
569
  * @returns {obj is string}
570
570
  */
571
- function isNonEmptyString(obj) {
571
+ function isNonEmptyString$1(obj) {
572
572
  return getDataType(obj) === "string" && obj.length > 0;
573
573
  }
574
574
 
@@ -1827,6 +1827,10 @@ registerProcessor('audio-stream-resampler-processor', AudioStreamResamplerProces
1827
1827
  this._fn = fn;
1828
1828
  this._ms = ms;
1829
1829
  this._timerId = null;
1830
+ /**
1831
+ * @type {symbol | null}
1832
+ */
1833
+ this._loopId = null;
1830
1834
  }
1831
1835
 
1832
1836
  /**
@@ -1835,8 +1839,17 @@ registerProcessor('audio-stream-resampler-processor', AudioStreamResamplerProces
1835
1839
  */
1836
1840
  start() {
1837
1841
  this.stop();
1842
+
1843
+ const curLoopId = Symbol();
1844
+ this._loopId = curLoopId;
1845
+
1838
1846
  const loop = () => {
1847
+ if (this._loopId !== curLoopId) return;
1848
+
1839
1849
  this._fn(); // 执行业务
1850
+
1851
+ if (this._loopId !== curLoopId) return;
1852
+
1840
1853
  this._timerId = setTimeout(loop, this._ms);
1841
1854
  };
1842
1855
  loop(); // 立即执行第一次
@@ -1846,6 +1859,7 @@ registerProcessor('audio-stream-resampler-processor', AudioStreamResamplerProces
1846
1859
  * 停止定时器。
1847
1860
  */
1848
1861
  stop() {
1862
+ this._loopId = null;
1849
1863
  if (this._timerId !== null) {
1850
1864
  clearTimeout(this._timerId);
1851
1865
  this._timerId = null;
@@ -2098,6 +2112,181 @@ registerProcessor('audio-stream-resampler-processor', AudioStreamResamplerProces
2098
2112
  }
2099
2113
 
2100
2114
  return path.reverse();
2115
+ }
2116
+
2117
+ /**
2118
+ * 处理函数的返回值类型,用于控制节点是否添加。
2119
+ * @typedef {Object} TransformTreeDataWithExtra_HandlerResult
2120
+ * @property {boolean} [isAdd] - 是否将该节点添加到树中。如果为 false,则过滤掉该节点。
2121
+ */
2122
+
2123
+ /**
2124
+ * 最终输出的树形结构的字段配置。
2125
+ * @typedef {Object} TransformTreeDataWithExtra_TreeDataOption
2126
+ * @property {string} [idKey="key"] - 最终树节点的唯一标识字段名。
2127
+ * @property {string} [titleKey="title"] - 最终树节点的标题显示字段名。
2128
+ * @property {string} [childrenKey="children"] - 最终树节点的子节点列表字段名。
2129
+ */
2130
+
2131
+ /**
2132
+ * 主数据(父节点)的相关配置选项。
2133
+ * @typedef {Object} TransformTreeDataWithExtra_NodeOption
2134
+ * @property {string} [idPrefix] - 节点 ID 的前缀。
2135
+ * @property {string} [idKey="id"] - 原始数据中作为唯一标识的字段名。
2136
+ * @property {string} [titleKey="name"] - 原始数据中作为标题的字段名。
2137
+ * @property {string} [childrenKey="children"] - 原始数据中子节点列表的字段名。
2138
+ * @property {Record<string, any>} [assignData] - 需要额外合并到每个树节点上的静态属性。
2139
+ * @property {string} [rawDataKey] - 如果提供,会将原始节点数据对象挂载到树节点的此字段下。
2140
+ * @property {Object<string, any>} [nodeDataId2Obj] - (副作用) 引用传递的对象,用于建立 id -> 原始数据的映射。
2141
+ * @property {function(object, object): TransformTreeDataWithExtra_HandlerResult | void} [nodeDataHandler] - 对每个主节点进行处理的回调函数。
2142
+ */
2143
+
2144
+ /**
2145
+ * 额外数据(子节点)的相关配置选项。
2146
+ * @typedef {Object} TransformTreeDataWithExtra_ExtraOption
2147
+ * @property {string} [idPrefix] - 额外节点 ID 的前缀。
2148
+ * @property {string} [idKey="id"] - 额外数据中作为唯一标识的字段名。
2149
+ * @property {string} [titleKey="name"] - 额外数据中作为标题的字段名。
2150
+ * @property {string} [childrenKey="extraChildren"] - 在主节点上查找额外数据列表的字段名。
2151
+ * @property {Record<string, any>} [assignData] - 需要额外合并到每个额外树节点上的静态属性。
2152
+ * @property {string} [rawDataKey] - 如果提供,会将原始额外数据对象挂载到树节点的此字段下。
2153
+ * @property {Object<string, any>} [extraDataId2Obj] - (副作用) 引用传递的对象,用于建立 id -> 额外数据的映射。
2154
+ * @property {function(object, object, object): TransformTreeDataWithExtra_HandlerResult | void} [extraDataHandler] - 对每个额外节点进行处理的回调函数。
2155
+ */
2156
+
2157
+ /**
2158
+ * 将平铺或嵌套的原始数据转换为标准树形结构。
2159
+ * 支持将外部“额外数据”节点作为子节点插入到主节点层级中。
2160
+ * 支持自定义字段映射、ID 前缀、数据挂载以及通过回调函数过滤节点。
2161
+ *
2162
+ * @template T
2163
+ * @param {Array<T>} data - 原始数据数组。
2164
+ * @param {TransformTreeDataWithExtra_ExtraOption} [extraOption] - 额外数据(子节点)的相关配置选项。
2165
+ * @param {TransformTreeDataWithExtra_NodeOption} [nodeOption] - 主数据(父节点)的相关配置选项。
2166
+ * @param {TransformTreeDataWithExtra_TreeDataOption} [treeDataOption] - 最终输出的树形结构的字段配置选项。
2167
+ * @returns {Array<object>} 转换后的树形数据数组。
2168
+ */
2169
+ function transformTreeDataWithExtra(data, extraOption = {}, nodeOption = {}, treeDataOption = {}) {
2170
+ const { idPrefix: nodeIdPrefix, idKey: nodeIdKey = "id", titleKey: nodeTitleKey = "name", childrenKey: nodeChildrenKey = "children", assignData: nodeAssignData = {}, rawDataKey: nodeRawDataKey, nodeDataId2Obj, nodeDataHandler } = nodeOption;
2171
+ const { idPrefix: extraIdPrefix, idKey: extraIdKey = "id", titleKey: extraTitleKey = "name", childrenKey: extraChildrenKey = "extraChildren", assignData: extraAssignData = {}, rawDataKey: extraRawDataKey, extraDataId2Obj, extraDataHandler } = extraOption;
2172
+
2173
+ const { idKey: treeIdKey = "key", titleKey: treeTitleKey = "title", childrenKey: treeChildrenKey = "children" } = treeDataOption;
2174
+
2175
+ const transformNode = (node) => {
2176
+ const treeNode = {
2177
+ [treeIdKey]: isNonEmptyString(nodeIdPrefix) ? nodeIdPrefix + node[nodeIdKey] : node[nodeIdKey],
2178
+ [treeTitleKey]: node[nodeTitleKey],
2179
+ [treeChildrenKey]: [],
2180
+ ...nodeAssignData
2181
+ };
2182
+ if (isNonEmptyString(nodeRawDataKey)) {
2183
+ treeNode[nodeRawDataKey] = node;
2184
+ }
2185
+
2186
+ if (Array.isArray(node[nodeChildrenKey]) && node[nodeChildrenKey].length > 0) {
2187
+ treeNode[treeChildrenKey] = node[nodeChildrenKey].map((child) => transformNode(child)).filter((child) => child !== null);
2188
+ }
2189
+
2190
+ if (Array.isArray(node[extraChildrenKey]) && node[extraChildrenKey].length > 0) {
2191
+ const isValidExtraDataId2Obj = typeof extraDataId2Obj === "object" && extraDataId2Obj !== null;
2192
+ const extraNodes = [];
2193
+ for (const extraItem of node[extraChildrenKey]) {
2194
+ if (isValidExtraDataId2Obj) {
2195
+ extraDataId2Obj[extraItem[extraIdKey]] = extraItem;
2196
+ }
2197
+ const extraNode = {
2198
+ [treeIdKey]: isNonEmptyString(extraIdPrefix) ? extraIdPrefix + extraItem[extraIdKey] : extraItem[extraIdKey],
2199
+ [treeTitleKey]: extraItem[extraTitleKey],
2200
+ [treeChildrenKey]: [],
2201
+ ...extraAssignData
2202
+ };
2203
+ if (isNonEmptyString(extraRawDataKey)) {
2204
+ extraNode[extraRawDataKey] = extraItem;
2205
+ }
2206
+ if (typeof extraDataHandler === "function") {
2207
+ const result = extraDataHandler(extraNode, extraItem, node);
2208
+ if (result?.isAdd === false) continue;
2209
+ }
2210
+ extraNodes.push(extraNode);
2211
+ }
2212
+ treeNode[treeChildrenKey] = [...treeNode[treeChildrenKey], ...extraNodes];
2213
+ }
2214
+
2215
+ if (typeof nodeDataId2Obj === "object" && nodeDataId2Obj !== null) {
2216
+ nodeDataId2Obj[node[nodeIdKey]] = node;
2217
+ }
2218
+
2219
+ if (typeof nodeDataHandler === "function") {
2220
+ const result = nodeDataHandler(treeNode, node);
2221
+ if (result?.isAdd === false) {
2222
+ return null;
2223
+ }
2224
+ }
2225
+
2226
+ return treeNode;
2227
+ };
2228
+
2229
+ return data.map((item) => transformNode(item)).filter((item) => item !== null);
2230
+ }
2231
+
2232
+ /**
2233
+ * 自定义过滤函数的类型定义。
2234
+ * @callback FilterTreeData_FilterFn
2235
+ * @param {object} node - 当前遍历到的树节点对象。
2236
+ * @param {string | number} filterValue - 当前用于过滤的值。
2237
+ * @param {Array<object>} [children] - 当前节点的子节点数组(原始数据)。
2238
+ * @returns {boolean} 返回 true 表示保留该节点,false 表示过滤掉。
2239
+ */
2240
+
2241
+ /**
2242
+ * 递归过滤树形数据。
2243
+ *
2244
+ * 该函数会保留符合条件的节点。特别地,**即使当前节点本身不匹配条件,只要其子孙节点中有匹配项,该节点也会被保留**,
2245
+ * 从而保证过滤后的树结构能展示出匹配节点的完整路径。
2246
+ *
2247
+ * @template T
2248
+ * @param {Array<T>} treeData - 源树形数据数组。
2249
+ * @param {string | number} filterValue - 用于过滤的关键字。
2250
+ * @param {string} [filterKey="name"] - 节点对象中用于匹配的字段名。默认为 "name"。如果提供了 filterFn 则此项无效。
2251
+ * @param {string} [childrenKey="children"] - 节点对象中存储子数组的字段名。默认为 "children"。
2252
+ * @param {FilterTreeData_FilterFn} [filterFn] - 自定义过滤函数。如果提供,将忽略 filterKey,使用此函数的返回值判断是否匹配。
2253
+ * @returns {Array<T>} 过滤后的新树形数据数组。注意:返回的是节点对象的浅拷贝。
2254
+ */
2255
+ function filterTreeData(treeData, filterValue, filterKey = "name", childrenKey = "children", filterFn) {
2256
+ if (!Array.isArray(treeData) || treeData.length === 0) {
2257
+ return [];
2258
+ }
2259
+
2260
+ if (filterValue == null || filterValue === "") {
2261
+ return treeData.map((node) => ({ ...node }));
2262
+ }
2263
+
2264
+ const result = [];
2265
+
2266
+ for (const node of treeData) {
2267
+ const newNode = { ...node };
2268
+ const children = node[childrenKey];
2269
+
2270
+ // 后代节点
2271
+ let isDescendantMatch = false;
2272
+ if (Array.isArray(children)) {
2273
+ const newChildren = filterTreeData(children, filterValue, filterKey, childrenKey, filterFn);
2274
+ newNode[childrenKey] = newChildren;
2275
+ isDescendantMatch = newChildren.length > 0;
2276
+ }
2277
+
2278
+ if (isDescendantMatch) {
2279
+ result.push(newNode);
2280
+ } else {
2281
+ // 当前节点
2282
+ const isMatch = typeof filterFn === "function" ? filterFn(node, filterValue, children) : node[filterKey]?.toString().includes(filterValue);
2283
+
2284
+ if (isMatch) {
2285
+ result.push(newNode);
2286
+ }
2287
+ }
2288
+ }
2289
+ return result;
2101
2290
  }
2102
2291
 
2103
2292
  /**
@@ -2522,6 +2711,7 @@ registerProcessor('audio-stream-resampler-processor', AudioStreamResamplerProces
2522
2711
  exports.downloadJSON = downloadJSON;
2523
2712
  exports.extractFullyCheckedKeys = extractFullyCheckedKeys;
2524
2713
  exports.fetchOrDownloadByUrl = fetchOrDownloadByUrl;
2714
+ exports.filterTreeData = filterTreeData;
2525
2715
  exports.findObjAttrValueById = findObjAttrValueById;
2526
2716
  exports.findTreeNodeById = findTreeNodeById;
2527
2717
  exports.findTreeNodePath = findTreeNodePath;
@@ -2539,7 +2729,7 @@ registerProcessor('audio-stream-resampler-processor', AudioStreamResamplerProces
2539
2729
  exports.isBlob = isBlob;
2540
2730
  exports.isDate = isDate;
2541
2731
  exports.isFunction = isFunction;
2542
- exports.isNonEmptyString = isNonEmptyString;
2732
+ exports.isNonEmptyString = isNonEmptyString$1;
2543
2733
  exports.isPlainObject = isPlainObject;
2544
2734
  exports.isPromise = isPromise;
2545
2735
  exports.millisecond2Duration = millisecond2Duration;
@@ -2560,6 +2750,7 @@ registerProcessor('audio-stream-resampler-processor', AudioStreamResamplerProces
2560
2750
  exports.shuffle = shuffle;
2561
2751
  exports.throttle = throttle;
2562
2752
  exports.toDate = toDate;
2753
+ exports.transformTreeDataWithExtra = transformTreeDataWithExtra;
2563
2754
 
2564
2755
  }));
2565
2756
  //# sourceMappingURL=a2bei4.utils.umd.js.map