@movk/core 0.0.3 → 0.0.5

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/index.d.mts CHANGED
@@ -1,37 +1,180 @@
1
1
  import { VNode, Ref } from 'vue';
2
2
  import { z } from 'zod/v4';
3
3
 
4
+ /**
5
+ * 统一同步/异步返回类型
6
+ * @typeParam T - 类型
7
+ * @example
8
+ * // type T = string | Promise<string>
9
+ * // type R = ApiAwaitable<T>
10
+ * // 结果:R 为 string | Promise<string>
11
+ */
12
+ type ApiAwaitable<T> = T | Promise<T>;
13
+ /**
14
+ * 提取Promise类型
15
+ * @typeParam T - 类型
16
+ * @example
17
+ * // type T = Promise<string>
18
+ * // type R = ApiUnwrapPromise<T>
19
+ * // 结果:R 为 string
20
+ */
21
+ type ApiUnwrapPromise<T> = T extends Promise<infer U> ? U : T;
22
+ /**
23
+ * 提取函数返回类型
24
+ * @typeParam TFn - 函数类型
25
+ * @example
26
+ * // type Fn = (x: number, y: string) => Promise<string>
27
+ * // type R = ApiAwaitedReturn<Fn>
28
+ * // 结果:R 为 string
29
+ */
30
+ type ApiAwaitedReturn<TFn> = TFn extends (...args: any[]) => ApiAwaitable<infer R> ? R : never;
31
+
32
+ type UnknownObject = Record<string, unknown>;
4
33
  type AnyObject = Record<string, any>;
34
+ /**
35
+ * 依据键名从对象类型 `T` 中剔除键 `K`。
36
+ * @typeParam T - 源对象类型
37
+ * @typeParam K - 要剔除的键(必须来自 `keyof T`)
38
+ * @example
39
+ * // type User = { id: string; name: string; age: number }
40
+ * // type R = OmitByKey<User, 'age'>
41
+ * // 结果:R 为 { id: string; name: string }
42
+ */
5
43
  type OmitByKey<T, K extends keyof T> = {
6
44
  [P in keyof T as P extends K ? never : P]: T[P];
7
45
  };
46
+ /**
47
+ * 依据键名从对象类型 `T` 中挑选键 `K`。
48
+ * @typeParam T - 源对象类型
49
+ * @typeParam K - 要保留的键(必须来自 `keyof T`)
50
+ * @example
51
+ * // type User = { id: string; name: string; age: number }
52
+ * // type R = PickByKey<User, 'id' | 'name'>
53
+ * // 结果:R 为 { id: string; name: string }
54
+ */
8
55
  type PickByKey<T, K extends keyof T> = {
9
56
  [P in keyof T as P extends K ? P : never]: T[P];
10
57
  };
58
+ /**
59
+ * 基于映射表 `Mapping` 对对象类型 `T` 的键进行重命名。
60
+ * 未在映射表中的键保持原名;映射值为 `PropertyKey`(string/number/symbol)。
61
+ * @typeParam T - 源对象类型
62
+ * @typeParam Mapping - 旧键到新键名的映射
63
+ * @example
64
+ * // type Src = { a: number; b: string }
65
+ * // type R = RenameKeys<Src, { a: 'id' }>
66
+ * // 结果:R 为 { id: number; b: string }
67
+ */
11
68
  type RenameKeys<T, Mapping extends {
12
69
  [K in keyof T]?: PropertyKey;
13
70
  }> = {
14
71
  [K in keyof T as K extends keyof Mapping ? Exclude<Mapping[K], undefined> : K]: T[K];
15
72
  };
73
+ /**
74
+ * 将对象类型 `T` 中的键 `K` 标记为必填(移除可选修饰)。
75
+ * @typeParam T - 源对象类型
76
+ * @typeParam K - 设为必填的键
77
+ * @example
78
+ * // type User = { id: string; name?: string }
79
+ * // type R = RequiredByKeys<User, 'name'>
80
+ * // 结果:R['name'] 为必填的 string
81
+ */
16
82
  type RequiredByKeys<T, K extends keyof T> = T & {
17
83
  [P in K]-?: T[P];
18
84
  };
85
+ /**
86
+ * 将对象类型 `T` 中的键 `K` 标记为可选。
87
+ * @typeParam T - 源对象类型
88
+ * @typeParam K - 设为可选的键
89
+ * @example
90
+ * // type User = { id: string; name: string }
91
+ * // type R = PartialByKeys<User, 'name'>
92
+ * // 结果:R['name'] 为可选(可能为 undefined)
93
+ */
19
94
  type PartialByKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
95
+ /**
96
+ * 将对象类型 `T` 中的键 `K` 标记为只读(浅只读)。
97
+ * @typeParam T - 源对象类型
98
+ * @typeParam K - 设为只读的键
99
+ * @example
100
+ * // type User = { id: string; name: string }
101
+ * // type R = ReadonlyByKeys<User, 'id'>
102
+ * // 结果:R['id'] 不可被重新赋值
103
+ */
20
104
  type ReadonlyByKeys<T, K extends keyof T> = T & {
21
105
  readonly [P in K]: T[P];
22
106
  };
107
+ /**
108
+ * 取消对象类型 `T` 中键 `K` 的只读限制,使其可写(浅层)。
109
+ * @typeParam T - 源对象类型
110
+ * @typeParam K - 取消只读的键
111
+ * @example
112
+ * // type User = { readonly id: string; name: string }
113
+ * // type R = MutableByKeys<User, 'id'>
114
+ * // 结果:R['id'] 变为可写
115
+ */
23
116
  type MutableByKeys<T, K extends keyof T> = {
24
117
  -readonly [P in K]: T[P];
25
118
  } & Omit<T, K>;
119
+ /**
120
+ * 将联合类型 `U` 转换为交叉类型,用于合并联合成员的属性。
121
+ * @typeParam U - 联合类型
122
+ * @example
123
+ * // type U = { a: number } | { b: string }
124
+ * // type R = UnionToIntersection<U>
125
+ * // 结果:R 为 { a: number } & { b: string }
126
+ */
26
127
  type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? {
27
128
  [K in keyof I]: I[K];
28
129
  } : never;
130
+ /**
131
+ * 若对象 `T` 在键 `K` 处的类型为元组,则提取其首个元素类型,否则为 `never`。
132
+ * @typeParam T - 具有元组属性的对象类型
133
+ * @typeParam K - 属性键
134
+ * @example
135
+ * // type Cfg = { params: [id: string, flag?: boolean] }
136
+ * // type R = FirstParam<Cfg, 'params'>
137
+ * // 结果:R 为 string
138
+ */
29
139
  type FirstParam<T, K extends keyof T> = T[K] extends [infer P, ...any[]] ? P : never;
140
+ /**
141
+ * 从函数类型中提取首个参数类型;若 `T` 非函数类型,则为 `undefined`。
142
+ * @typeParam T - 函数类型
143
+ * @example
144
+ * // type Fn = (x: number, y: string) => void
145
+ * // type R = FirstParameter<Fn>
146
+ * // 结果:R 为 number;若 T 非函数,则为 undefined
147
+ */
30
148
  type FirstParameter<T> = T extends (arg: infer P, ...args: any[]) => any ? P : undefined;
149
+ /**
150
+ * 递归将对象类型 `T` 的所有属性变为可选(深可选)。
151
+ * @typeParam T - 源对象类型
152
+ * @example
153
+ * // type Src = { a: { b: number } }
154
+ * // type R = DeepPartial<Src>
155
+ * // 结果:R 为 { a?: { b?: number | undefined } | undefined }
156
+ */
31
157
  type DeepPartial<T> = {
32
158
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P] | undefined;
33
159
  };
160
+ /**
161
+ * 当 `MaybeObject` 为对象时,返回键 `Key` 对应的属性类型;否则为 `never`。
162
+ * @typeParam MaybeObject - 可能为对象的类型
163
+ * @typeParam Key - 目标键名(string)
164
+ * @example
165
+ * // type Obj = { id: number }
166
+ * // type R1 = GetObjectField<Obj, 'id'> // 结果:number
167
+ * // type R2 = GetObjectField<string, 'id'> // 结果:never
168
+ */
34
169
  type GetObjectField<MaybeObject, Key extends string> = MaybeObject extends Record<string, any> ? MaybeObject[Key] : never;
170
+ /**
171
+ * Vue 渲染相关文本/节点类型:可为字符串、`VNode` 或返回 `VNode` 的函数。
172
+ * @example
173
+ * // 在渲染 API 中允许三种形态:
174
+ * // - '标题'
175
+ * // - h('div', '标题') 产生的 VNode
176
+ * // - () => h('div', '标题') 的惰性渲染函数
177
+ */
35
178
  type StringOrVNode = string | VNode | (() => VNode);
36
179
 
37
180
  declare const StorageTypeSchema: z.ZodEnum<{
@@ -58,35 +201,6 @@ interface AppStorageReturn<T> {
58
201
  removeItem: () => void;
59
202
  }
60
203
 
61
- declare const _TreeNodeBaseSchema: z.ZodRecord<z.ZodString, z.ZodAny>;
62
- type TreeNodeBase = z.infer<typeof _TreeNodeBaseSchema>;
63
- type TreeNode<T extends TreeNodeBase = TreeNodeBase> = T & {
64
- [K in TreeConfig['children']]: TreeNode<T>[];
65
- };
66
- declare const TreeConfigSchema: z.ZodObject<{
67
- id: z.ZodDefault<z.ZodString>;
68
- pid: z.ZodDefault<z.ZodString>;
69
- children: z.ZodDefault<z.ZodString>;
70
- }, z.core.$strip>;
71
- type TreeConfig = z.infer<typeof TreeConfigSchema>;
72
- type TreeConfigInput = z.input<typeof TreeConfigSchema>;
73
- declare const TreeStatsSchema: z.ZodObject<{
74
- total: z.ZodNumber;
75
- leaves: z.ZodNumber;
76
- depth: z.ZodNumber;
77
- branches: z.ZodNumber;
78
- }, z.core.$strip>;
79
- type TreeStats = z.infer<typeof TreeStatsSchema>;
80
- interface TreeNodeResult<T extends TreeNodeBase = TreeNodeBase> {
81
- readonly node: TreeNode<T>;
82
- readonly path: readonly TreeNode<T>[];
83
- readonly depth: number;
84
- readonly index: number;
85
- }
86
- type TreePredicate<T extends TreeNodeBase = TreeNodeBase> = (node: TreeNode<T>, depth: number, path: readonly TreeNode<T>[]) => boolean;
87
- type TreeTransformer<T extends TreeNodeBase = TreeNodeBase, R extends TreeNodeBase = TreeNodeBase> = (node: TreeNode<T>, depth: number, path: readonly TreeNode<T>[]) => R;
88
- type TreeVisitor<T extends TreeNodeBase = TreeNodeBase> = (node: TreeNode<T>, depth: number, path: readonly TreeNode<T>[]) => void | boolean;
89
-
90
204
  /**
91
205
  * 应用存储管理的组合式函数,支持localStorage和sessionStorage
92
206
  *
@@ -170,36 +284,32 @@ declare function useAppStorage<T = unknown>(config: StorageConfigInput<T>): AppS
170
284
  */
171
285
  declare function useCopyCode(text: string): Promise<boolean>;
172
286
 
173
- /**
174
- * 树形数据结构操作类,提供树形数据的各种操作方法
175
- *
176
- * @category Data Structures
177
- * @example
178
- * ```ts
179
- * // 从扁平数组创建树形结构
180
- * const flatList = [
181
- * { id: '1', name: '根节点', pid: null },
182
- * { id: '2', name: '子节点1', pid: '1' },
183
- * { id: '3', name: '子节点2', pid: '1' },
184
- * { id: '4', name: '孙节点', pid: '2' }
185
- * ]
186
- *
187
- * const tree = Tree.fromList(flatList)
188
- * console.log(tree) // 树形结构
189
- *
190
- * // 查找节点
191
- * const found = Tree.find(tree, (node) => node.name === '子节点1')
192
- *
193
- * // 过滤节点
194
- * const filtered = Tree.filter(tree, (node) => node.name.includes('子'))
195
- *
196
- * // 转换树形结构
197
- * const transformed = Tree.transform(tree, (node) => ({
198
- * ...node,
199
- * displayName: `[${node.name}]`
200
- * }))
201
- * ```
202
- */
287
+ type TreeNode<T = any> = T & {
288
+ children?: TreeNode<T>[];
289
+ [key: string]: any;
290
+ };
291
+ declare const TreeConfigSchema: z.ZodObject<{
292
+ id: z.ZodDefault<z.ZodString>;
293
+ pid: z.ZodDefault<z.ZodString>;
294
+ children: z.ZodDefault<z.ZodString>;
295
+ }, z.core.$strip>;
296
+ type TreeConfigInput = z.input<typeof TreeConfigSchema>;
297
+ declare const _TreeStatsSchema: z.ZodObject<{
298
+ total: z.ZodNumber;
299
+ leaves: z.ZodNumber;
300
+ depth: z.ZodNumber;
301
+ branches: z.ZodNumber;
302
+ }, z.core.$strip>;
303
+ type TreeStats = z.infer<typeof _TreeStatsSchema>;
304
+ interface TreeNodeResult<T = any> {
305
+ readonly node: TreeNode<T>;
306
+ readonly path: readonly TreeNode<T>[];
307
+ readonly depth: number;
308
+ readonly index: number;
309
+ }
310
+ type TreePredicate<T = any> = (node: TreeNode<T>, depth: number, path: readonly TreeNode<T>[]) => boolean;
311
+ type TreeTransformer<T = any, R = any> = (node: TreeNode<T>, depth: number, path: readonly TreeNode<T>[]) => R;
312
+ type TreeVisitor<T = any> = (node: TreeNode<T>, depth: number, path: readonly TreeNode<T>[]) => void | boolean;
203
313
  declare class Tree {
204
314
  private static dfsGenerator;
205
315
  private static bfsGenerator;
@@ -229,7 +339,7 @@ declare class Tree {
229
339
  * console.log(tree) // 转换为树形结构
230
340
  * ```
231
341
  */
232
- static fromList<T extends TreeNodeBase>(list: T[], config?: TreeConfigInput): TreeNode<T>[];
342
+ static fromList<T = any>(list: T[], config?: TreeConfigInput): TreeNode<T>[];
233
343
  /**
234
344
  * 将树形结构转换为扁平数组
235
345
  *
@@ -254,124 +364,328 @@ declare class Tree {
254
364
  * console.log(flatList) // [{ id: '1', name: '根节点' }, { id: '2', name: '子节点1' }, ...]
255
365
  * ```
256
366
  */
257
- static toList<T extends TreeNodeBase>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): T[];
258
- static estimateSize<T extends TreeNodeBase>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): number;
259
- static find<T extends TreeNodeBase>(tree: TreeNode<T> | TreeNode<T>[], predicate: TreePredicate<T>, config?: TreeConfigInput): TreeNodeResult<T> | undefined;
260
- static findAll<T extends TreeNodeBase>(tree: TreeNode<T> | TreeNode<T>[], predicate: TreePredicate<T>, config?: TreeConfigInput): TreeNodeResult<T>[];
261
- static findById<T extends TreeNodeBase>(tree: TreeNode<T> | TreeNode<T>[], id: string, config?: TreeConfigInput): TreeNodeResult<T> | undefined;
262
- static getStats<T extends TreeNodeBase>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): TreeStats;
263
- static filter<T extends TreeNodeBase>(tree: TreeNode<T> | TreeNode<T>[], predicate: TreePredicate<T>, config?: TreeConfigInput): TreeNode<T>[];
264
- static transform<T extends TreeNodeBase, R extends TreeNodeBase>(tree: TreeNode<T> | TreeNode<T>[], transformer: TreeTransformer<T, R>, config?: TreeConfigInput): TreeNode<R>[];
265
- static forEach<T extends TreeNodeBase>(tree: TreeNode<T> | TreeNode<T>[], visitor: TreeVisitor<T>, config?: TreeConfigInput): void;
266
- static insertBefore<T extends TreeNodeBase>(tree: TreeNode<T>[], targetId: string, newNode: T, config?: TreeConfigInput): boolean;
267
- static insertAfter<T extends TreeNodeBase>(tree: TreeNode<T>[], targetId: string, newNode: T, config?: TreeConfigInput): boolean;
268
- static remove<T extends TreeNodeBase>(tree: TreeNode<T>[], targetId: string, config?: TreeConfigInput): TreeNode<T> | undefined;
269
- static validate<T extends TreeNodeBase>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): {
367
+ static toList<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): T[];
368
+ /**
369
+ * 估算树形结构的节点数量
370
+ *
371
+ * @category Data Structures
372
+ * @param tree 树形结构(单个节点或节点数组)
373
+ * @param config 树形配置选项
374
+ * @returns 节点总数量
375
+ * @example
376
+ * ```ts
377
+ * const tree = [
378
+ * {
379
+ * id: '1',
380
+ * name: '根节点',
381
+ * children: [
382
+ * { id: '2', name: '子节点1', children: [] },
383
+ * { id: '3', name: '子节点2', children: [] }
384
+ * ]
385
+ * }
386
+ * ]
387
+ *
388
+ * const size = Tree.estimateSize(tree)
389
+ * console.log(size) // 3
390
+ * ```
391
+ */
392
+ static estimateSize<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): number;
393
+ /**
394
+ * 查找树中第一个满足条件的节点
395
+ *
396
+ * @category Data Structures
397
+ * @param tree 树形结构(单个节点或节点数组)
398
+ * @param predicate 查找条件函数
399
+ * @param config 树形配置选项
400
+ * @returns 匹配的节点结果,包含节点、路径、深度和索引信息;未找到时返回undefined
401
+ * @example
402
+ * ```ts
403
+ * const tree = [
404
+ * {
405
+ * id: '1',
406
+ * name: '部门1',
407
+ * children: [
408
+ * { id: '2', name: '部门1-1', children: [] }
409
+ * ]
410
+ * }
411
+ * ]
412
+ *
413
+ * const result = Tree.find(tree, (node) => node.name === '部门1-1')
414
+ * console.log(result?.node.id) // '2'
415
+ * console.log(result?.depth) // 1
416
+ * ```
417
+ */
418
+ static find<T = any>(tree: TreeNode<T> | TreeNode<T>[], predicate: TreePredicate<T>, config?: TreeConfigInput): TreeNodeResult<T> | undefined;
419
+ /**
420
+ * 查找树中所有满足条件的节点
421
+ *
422
+ * @category Data Structures
423
+ * @param tree 树形结构(单个节点或节点数组)
424
+ * @param predicate 查找条件函数
425
+ * @param config 树形配置选项
426
+ * @returns 所有匹配的节点结果数组,每个结果包含节点、路径、深度和索引信息
427
+ * @example
428
+ * ```ts
429
+ * const tree = [
430
+ * {
431
+ * id: '1',
432
+ * type: 'folder',
433
+ * name: '根目录',
434
+ * children: [
435
+ * { id: '2', type: 'file', name: '文件1', children: [] },
436
+ * { id: '3', type: 'file', name: '文件2', children: [] }
437
+ * ]
438
+ * }
439
+ * ]
440
+ *
441
+ * const files = Tree.findAll(tree, (node) => node.type === 'file')
442
+ * console.log(files.length) // 2
443
+ * ```
444
+ */
445
+ static findAll<T = any>(tree: TreeNode<T> | TreeNode<T>[], predicate: TreePredicate<T>, config?: TreeConfigInput): TreeNodeResult<T>[];
446
+ /**
447
+ * 根据ID查找树中的节点
448
+ *
449
+ * @category Data Structures
450
+ * @param tree 树形结构(单个节点或节点数组)
451
+ * @param id 要查找的节点ID
452
+ * @param config 树形配置选项
453
+ * @returns 匹配的节点结果,包含节点、路径、深度和索引信息;未找到时返回undefined
454
+ * @example
455
+ * ```ts
456
+ * const tree = [
457
+ * {
458
+ * id: '1',
459
+ * name: '根节点',
460
+ * children: [
461
+ * { id: '2', name: '子节点', children: [] }
462
+ * ]
463
+ * }
464
+ * ]
465
+ *
466
+ * const result = Tree.findById(tree, '2')
467
+ * console.log(result?.node.name) // '子节点'
468
+ * ```
469
+ */
470
+ static findById<T = any>(tree: TreeNode<T> | TreeNode<T>[], id: string, config?: TreeConfigInput): TreeNodeResult<T> | undefined;
471
+ /**
472
+ * 获取树形结构的统计信息
473
+ *
474
+ * @category Data Structures
475
+ * @param tree 树形结构(单个节点或节点数组)
476
+ * @param config 树形配置选项
477
+ * @returns 树的统计信息,包含总节点数、叶子节点数、最大深度和分支节点数
478
+ * @example
479
+ * ```ts
480
+ * const tree = [
481
+ * {
482
+ * id: '1',
483
+ * name: '根节点',
484
+ * children: [
485
+ * { id: '2', name: '子节点1', children: [] },
486
+ * { id: '3', name: '子节点2', children: [
487
+ * { id: '4', name: '孙节点', children: [] }
488
+ * ] }
489
+ * ]
490
+ * }
491
+ * ]
492
+ *
493
+ * const stats = Tree.getStats(tree)
494
+ * console.log(stats) // { total: 4, leaves: 2, depth: 3, branches: 2 }
495
+ * ```
496
+ */
497
+ static getStats<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): TreeStats;
498
+ /**
499
+ * 过滤树形结构,保留满足条件的节点及其祖先和后代
500
+ *
501
+ * @category Data Structures
502
+ * @param tree 树形结构(单个节点或节点数组)
503
+ * @param predicate 过滤条件函数
504
+ * @param config 树形配置选项
505
+ * @returns 过滤后的树形结构数组
506
+ * @example
507
+ * ```ts
508
+ * const tree = [
509
+ * {
510
+ * id: '1',
511
+ * type: 'folder',
512
+ * name: '根目录',
513
+ * children: [
514
+ * { id: '2', type: 'file', name: '文档.txt', children: [] },
515
+ * { id: '3', type: 'folder', name: '子目录', children: [
516
+ * { id: '4', type: 'file', name: '图片.jpg', children: [] }
517
+ * ] }
518
+ * ]
519
+ * }
520
+ * ]
521
+ *
522
+ * const filtered = Tree.filter(tree, (node) => node.type === 'file')
523
+ * // 返回包含所有文件节点及其父级路径的树结构
524
+ * ```
525
+ */
526
+ static filter<T = any>(tree: TreeNode<T> | TreeNode<T>[], predicate: TreePredicate<T>, config?: TreeConfigInput): TreeNode<T>[];
527
+ /**
528
+ * 转换树形结构,将每个节点转换为新的结构
529
+ *
530
+ * @category Data Structures
531
+ * @param tree 树形结构(单个节点或节点数组)
532
+ * @param transformer 节点转换函数
533
+ * @param config 树形配置选项
534
+ * @returns 转换后的树形结构数组
535
+ * @example
536
+ * ```ts
537
+ * const tree = [
538
+ * {
539
+ * id: '1',
540
+ * name: '部门1',
541
+ * children: [
542
+ * { id: '2', name: '部门1-1', children: [] }
543
+ * ]
544
+ * }
545
+ * ]
546
+ *
547
+ * const transformed = Tree.transform(tree, (node, depth) => ({
548
+ * key: node.id,
549
+ * title: node.name,
550
+ * level: depth
551
+ * }))
552
+ * // 转换为新的数据结构
553
+ * ```
554
+ */
555
+ static transform<T = any, R = any>(tree: TreeNode<T> | TreeNode<T>[], transformer: TreeTransformer<T, R>, config?: TreeConfigInput): TreeNode<R>[];
556
+ /**
557
+ * 遍历树形结构的每个节点
558
+ *
559
+ * @category Data Structures
560
+ * @param tree 树形结构(单个节点或节点数组)
561
+ * @param visitor 访问者函数,返回false可以跳过子节点的遍历
562
+ * @param config 树形配置选项
563
+ * @example
564
+ * ```ts
565
+ * const tree = [
566
+ * {
567
+ * id: '1',
568
+ * name: '根节点',
569
+ * children: [
570
+ * { id: '2', name: '子节点', children: [] }
571
+ * ]
572
+ * }
573
+ * ]
574
+ *
575
+ * Tree.forEach(tree, (node, depth) => {
576
+ * console.log(`${' '.repeat(depth * 2)}${node.name}`)
577
+ * // 输出缩进的树结构
578
+ * })
579
+ * ```
580
+ */
581
+ static forEach<T = any>(tree: TreeNode<T> | TreeNode<T>[], visitor: TreeVisitor<T>, config?: TreeConfigInput): void;
582
+ /**
583
+ * 在指定节点前插入新节点
584
+ *
585
+ * @category Data Structures
586
+ * @param tree 树形结构数组
587
+ * @param targetId 目标节点的ID
588
+ * @param newNode 要插入的新节点数据
589
+ * @param config 树形配置选项
590
+ * @returns 是否成功插入
591
+ * @example
592
+ * ```ts
593
+ * const tree = [
594
+ * {
595
+ * id: '1',
596
+ * name: '节点1',
597
+ * children: [
598
+ * { id: '2', name: '节点2', children: [] }
599
+ * ]
600
+ * }
601
+ * ]
602
+ *
603
+ * const success = Tree.insertBefore(tree, '2', { id: '1.5', name: '新节点' })
604
+ * console.log(success) // true
605
+ * ```
606
+ */
607
+ static insertBefore<T = any>(tree: TreeNode<T>[], targetId: string, newNode: T, config?: TreeConfigInput): boolean;
608
+ /**
609
+ * 在指定节点后插入新节点
610
+ *
611
+ * @category Data Structures
612
+ * @param tree 树形结构数组
613
+ * @param targetId 目标节点的ID
614
+ * @param newNode 要插入的新节点数据
615
+ * @param config 树形配置选项
616
+ * @returns 是否成功插入
617
+ * @example
618
+ * ```ts
619
+ * const tree = [
620
+ * {
621
+ * id: '1',
622
+ * name: '节点1',
623
+ * children: [
624
+ * { id: '2', name: '节点2', children: [] }
625
+ * ]
626
+ * }
627
+ * ]
628
+ *
629
+ * const success = Tree.insertAfter(tree, '2', { id: '3', name: '新节点' })
630
+ * console.log(success) // true
631
+ * ```
632
+ */
633
+ static insertAfter<T = any>(tree: TreeNode<T>[], targetId: string, newNode: T, config?: TreeConfigInput): boolean;
634
+ /**
635
+ * 从树中删除指定节点
636
+ *
637
+ * @category Data Structures
638
+ * @param tree 树形结构数组
639
+ * @param targetId 要删除的节点ID
640
+ * @param config 树形配置选项
641
+ * @returns 被删除的节点,未找到时返回undefined
642
+ * @example
643
+ * ```ts
644
+ * const tree = [
645
+ * {
646
+ * id: '1',
647
+ * name: '根节点',
648
+ * children: [
649
+ * { id: '2', name: '子节点', children: [] }
650
+ * ]
651
+ * }
652
+ * ]
653
+ *
654
+ * const removed = Tree.remove(tree, '2')
655
+ * console.log(removed?.name) // '子节点'
656
+ * ```
657
+ */
658
+ static remove<T = any>(tree: TreeNode<T>[], targetId: string, config?: TreeConfigInput): TreeNode<T> | undefined;
659
+ /**
660
+ * 验证树形结构的有效性
661
+ *
662
+ * @category Data Structures
663
+ * @param tree 树形结构(单个节点或节点数组)
664
+ * @param config 树形配置选项
665
+ * @returns 验证结果,包含是否有效和错误信息数组
666
+ * @example
667
+ * ```ts
668
+ * const tree = [
669
+ * {
670
+ * id: '1',
671
+ * name: '根节点',
672
+ * children: [
673
+ * { id: '2', name: '子节点', children: [] }
674
+ * ]
675
+ * }
676
+ * ]
677
+ *
678
+ * const result = Tree.validate(tree)
679
+ * console.log(result.isValid) // true
680
+ * console.log(result.errors) // []
681
+ * ```
682
+ */
683
+ static validate<T = any>(tree: TreeNode<T> | TreeNode<T>[], config?: TreeConfigInput): {
270
684
  isValid: boolean;
271
685
  errors: string[];
272
686
  };
273
687
  }
274
688
 
275
- /**
276
- * UnoCSS Flex布局预设,提供便捷的flex布局工具类
277
- *
278
- * @category Framework
279
- * @returns UnoCSS预设配置对象
280
- * @example
281
- * ```ts
282
- * // 在unocss.config.ts中使用
283
- * import { presetFlex } from '@movk/core'
284
- *
285
- * export default defineConfig({
286
- * presets: [
287
- * presetFlex(),
288
- * // 其他预设...
289
- * ]
290
- * })
291
- *
292
- * // 在HTML中使用生成的类名
293
- * <div class="flex-row-center-center">居中的flex容器</div>
294
- * <div class="flex-col-between-start">纵向分散对齐</div>
295
- * <div class="flex-center">完全居中</div>
296
- * <div class="flex-x-center">水平居中</div>
297
- * <div class="flex-y-center">垂直居中</div>
298
- * ```
299
- */
300
- declare function presetFlex(): {
301
- name: string;
302
- rules: ((RegExp | (([, d, j, a]: string[], { rawSelector }: {
303
- rawSelector: string;
304
- }) => Record<string, string>) | {
305
- autocomplete: string;
306
- })[] | (string | {
307
- display: string;
308
- 'justify-content': string;
309
- 'align-items': string;
310
- })[])[];
311
- shortcuts: {
312
- 'flex-x-center': string;
313
- 'flex-y-center': string;
314
- 'inline-flex-x-center': string;
315
- 'inline-flex-y-center': string;
316
- }[];
317
- };
318
-
319
- interface RuleContext {
320
- rawSelector: string;
321
- }
322
- /**
323
- * UnoCSS 猫头鹰选择器预设,提供基于相邻兄弟选择器的间距和分隔符工具类
324
- *
325
- * @category Framework
326
- * @returns UnoCSS预设配置对象
327
- * @example
328
- * ```ts
329
- * // 在unocss.config.ts中使用
330
- * import { presetOwl } from '@movk/core'
331
- *
332
- * export default defineConfig({
333
- * presets: [
334
- * presetOwl(),
335
- * // 其他预设...
336
- * ]
337
- * })
338
- *
339
- * // 在HTML中使用生成的类名
340
- * <div class="owl-y-4">
341
- * <div>项目1</div>
342
- * <div>项目2</div> <!-- 上边距 1rem -->
343
- * <div>项目3</div> <!-- 上边距 1rem -->
344
- * </div>
345
- *
346
- * <div class="owl-x-2">
347
- * <span>按钮1</span>
348
- * <span>按钮2</span> <!-- 左边距 0.5rem -->
349
- * <span>按钮3</span> <!-- 左边距 0.5rem -->
350
- * </div>
351
- *
352
- * <div class="owl-divide-gray-200">
353
- * <div>列表项1</div>
354
- * <div>列表项2</div> <!-- 上边框分隔线 -->
355
- * <div>列表项3</div> <!-- 上边框分隔线 -->
356
- * </div>
357
- * ```
358
- */
359
- declare function presetOwl(): {
360
- name: string;
361
- rules: (RegExp | (([, value]: string[], { rawSelector }: RuleContext) => string | undefined) | {
362
- autocomplete: string;
363
- })[][];
364
- shortcuts: {
365
- 'owl-stack': string;
366
- 'owl-stack-tight': string;
367
- 'owl-stack-loose': string;
368
- 'owl-list': string;
369
- 'owl-list-tight': string;
370
- 'owl-nav': string;
371
- 'owl-card-stack': string;
372
- }[];
373
- };
374
-
375
689
  /**
376
690
  * 数组去重,返回去除重复元素后的新数组
377
691
  *
@@ -789,10 +1103,6 @@ declare function omitUndefined<T extends AnyObject>(obj: T): Partial<T>;
789
1103
  */
790
1104
  declare function pick<T extends AnyObject, K extends keyof T>(obj: T, keys: K[]): PickByKey<T, K>;
791
1105
 
792
- interface SeparateResult<T extends AnyObject, K extends keyof T> {
793
- picked: PickByKey<T, K>;
794
- omitted: OmitByKey<T, K>;
795
- }
796
1106
  /**
797
1107
  * 将对象按指定键分离为两个对象
798
1108
  *
@@ -818,7 +1128,35 @@ interface SeparateResult<T extends AnyObject, K extends keyof T> {
818
1128
  * const { picked: publicData, omitted: privateData } = separate(user, ['id', 'name', 'email'])
819
1129
  * ```
820
1130
  */
821
- declare function separate<T extends AnyObject, K extends keyof T>(obj: T, keys: K[]): SeparateResult<T, K>;
1131
+ declare function separate<T extends AnyObject, K extends keyof T>(obj: T, keys: K[]): {
1132
+ picked: PickByKey<T, K>;
1133
+ omitted: OmitByKey<T, K>;
1134
+ };
1135
+ /**
1136
+ * 将对象按多分组键集合进行分离(浅层),返回各分组与 others
1137
+ *
1138
+ * - 键冲突策略:先到先得。若同一键出现在多个分组中,则归入第一个匹配到的分组
1139
+ * - 仅处理对象自有的浅层键,不解析深层路径
1140
+ * - 分组中包含不存在于对象的键将被忽略
1141
+ *
1142
+ * @category Object
1143
+ * @param obj 源对象
1144
+ * @param groups 分组映射,如 { a: ['x', 'y'], b: ['z'] }
1145
+ * @returns 一个对象,包含每个分组的子对象以及 others(其余未被分组捕获的键)
1146
+ * @example
1147
+ * ```ts
1148
+ * const options = { id: 1, name: 'John', email: 'a@b.com', role: 'admin' }
1149
+ * const { a, b, others } = separateMany(options, { a: ['id'], b: ['name'] as const })
1150
+ * // a: { id: 1 }
1151
+ * // b: { name: 'John' }
1152
+ * // others: { email: 'a@b.com', role: 'admin' }
1153
+ * ```
1154
+ */
1155
+ declare function separateMany<T extends AnyObject, M extends Record<string, readonly (keyof T)[]>>(obj: T, groups: M): {
1156
+ [P in keyof M]: PickByKey<T, M[P][number]>;
1157
+ } & {
1158
+ others: OmitByKey<T, M[keyof M][number]>;
1159
+ };
822
1160
 
823
1161
  /**
824
1162
  * 将字符串首字母大写
@@ -1001,5 +1339,5 @@ declare function isFunction(value: any): value is (...args: any[]) => any;
1001
1339
  */
1002
1340
  declare function isEmpty(value: any): boolean;
1003
1341
 
1004
- export { StorageTypeSchema, Tree, TreeConfigSchema, TreeStatsSchema, camelToKebab, capitalize, chunk, convertSvgToPng, convertToKebabCase, createStorageConfigSchema, debounce, deepClone, extractFilename, flatten, formatFileSize, getRandomUUID, isArray, isEmpty, isFunction, isNumber, isObject, isString, kebabToCamel, omit, omitUndefined, pick, presetFlex, presetOwl, replaceCurrentColor, separate, simpleHash, sleep, sleepWithCancel, throttle, triggerDownload, unique, useAppStorage, useCopyCode };
1005
- export type { AnyObject, AppStorageReturn, DeepPartial, FirstParam, FirstParameter, GetObjectField, MutableByKeys, OmitByKey, PartialByKeys, PickByKey, ReadonlyByKeys, RenameKeys, RequiredByKeys, StorageConfig, StorageConfigInput, StorageType, StringOrVNode, TreeConfig, TreeConfigInput, TreeNode, TreeNodeBase, TreeNodeResult, TreePredicate, TreeStats, TreeTransformer, TreeVisitor, UnionToIntersection };
1342
+ export { StorageTypeSchema, Tree, camelToKebab, capitalize, chunk, convertSvgToPng, convertToKebabCase, createStorageConfigSchema, debounce, deepClone, extractFilename, flatten, formatFileSize, getRandomUUID, isArray, isEmpty, isFunction, isNumber, isObject, isString, kebabToCamel, omit, omitUndefined, pick, replaceCurrentColor, separate, separateMany, simpleHash, sleep, sleepWithCancel, throttle, triggerDownload, unique, useAppStorage, useCopyCode };
1343
+ export type { AnyObject, ApiAwaitable, ApiAwaitedReturn, ApiUnwrapPromise, AppStorageReturn, DeepPartial, FirstParam, FirstParameter, GetObjectField, MutableByKeys, OmitByKey, PartialByKeys, PickByKey, ReadonlyByKeys, RenameKeys, RequiredByKeys, StorageConfig, StorageConfigInput, StorageType, StringOrVNode, UnionToIntersection, UnknownObject };