tcdona_unilib 1.0.11 → 1.0.14
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/.prettierrc.json +6 -0
- package/animejs.ts +13 -1
- package/ast-grep.ts +42 -0
- package/big.ts +2 -2
- package/clipboardy.ts +1 -1
- package/dayjs.ts +2 -2
- package/dotenvx.ts +15 -2
- package/eff/aff.ts +161 -0
- package/eff/aff.util.ts +218 -0
- package/eff/eff.delay.ts +21 -0
- package/eff/eff.ts +225 -0
- package/eff/effcan.ts +286 -0
- package/eff/throwable.ts +11 -0
- package/effector.ts +33 -2
- package/es-toolkit.ts +1 -7
- package/exome.ts +10 -2
- package/hono.ts +18 -2
- package/hotkeys-js.ts +3 -2
- package/idmeta.json +42 -0
- package/inquirer.ts +1 -1
- package/koka/async.ts +2 -7
- package/koka/ctx.ts +2 -9
- package/koka/err.ts +2 -9
- package/koka/gen.ts +2 -9
- package/koka/index.ts +1 -1
- package/koka/opt.ts +2 -7
- package/koka/result.ts +6 -9
- package/koka/task.ts +2 -8
- package/koka-domain.ts +13 -16
- package/koka.ts +29 -34
- package/magic-regexp.ts +28 -2
- package/marked.ts +28 -2
- package/nanoid.ts +7 -1
- package/nanostores.ts +31 -2
- package/neverthrow.ts +2 -2
- package/package.json +24 -33
- package/pathe.ts +16 -1
- package/pinyin-pro.ts +16 -2
- package/prettier.ts +20 -2
- package/staticMeta/enum.api.ts +111 -82
- package/staticMeta/err.ts +64 -0
- package/staticMeta/file.yml.ts +22 -13
- package/staticMeta/md.html2md.ts +38 -0
- package/staticMeta/md.md2html.ts +203 -0
- package/staticMeta/path.init.ts +12 -12
- package/staticMeta/string.nanoid.ts +7 -7
- package/staticMeta/url.ts +57 -54
- package/tinypool.ts +29 -2
- package/turndown.ts +1 -1
- package/vite.ts +2 -2
- package/viteplugin/md.plugin.dist.d.ts +18 -0
- package/viteplugin/md.plugin.dist.js +1133 -0
- package/viteplugin/md.plugin.ts +22 -0
- package/viteplugin/vite-env.d.ts +6 -0
- package/viteplugin/vite.config.ts +62 -0
- package/vue.ts +2 -12
- package/zod.ts +19 -2
- package/zx.ts +25 -1
- package/@ast-grep.ts +0 -18
- package/comctx.ts +0 -2
- package/hono/cors.ts +0 -1
- package/hono/logger.ts +0 -1
- package/hono/timeout.ts +0 -1
- package/staticMeta/ast.scan.ts +0 -131
- package/staticMeta/ast.ts +0 -259
- package/staticMeta/eff.delay.ts +0 -17
- package/staticMeta/eff.ts +0 -203
- package/staticMeta/iduniq.ts +0 -320
- package/staticMeta/idupdate.ts +0 -374
- package/staticMeta/pkg.json.ts +0 -138
- package/staticMeta/project.ts +0 -98
- package/staticMeta/sync.ts +0 -296
package/.prettierrc.json
ADDED
package/animejs.ts
CHANGED
|
@@ -1 +1,13 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {
|
|
2
|
+
animate,
|
|
3
|
+
createTimeline,
|
|
4
|
+
createTimer,
|
|
5
|
+
createScope,
|
|
6
|
+
createSpring,
|
|
7
|
+
createDraggable,
|
|
8
|
+
stagger,
|
|
9
|
+
eases,
|
|
10
|
+
utils,
|
|
11
|
+
svg,
|
|
12
|
+
engine,
|
|
13
|
+
} from 'animejs'
|
package/ast-grep.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// -----Type Only Export!-----//
|
|
2
|
+
export type {
|
|
3
|
+
FileOption,
|
|
4
|
+
FindConfig,
|
|
5
|
+
NapiConfig,
|
|
6
|
+
DynamicLangRegistrations,
|
|
7
|
+
Edit,
|
|
8
|
+
Pos,
|
|
9
|
+
Range,
|
|
10
|
+
Rule,
|
|
11
|
+
Lang,
|
|
12
|
+
SgNode,
|
|
13
|
+
} from '@ast-grep/napi'
|
|
14
|
+
|
|
15
|
+
// -----Runtime Value Export!-----//
|
|
16
|
+
// 导入所有需要的模块
|
|
17
|
+
import {
|
|
18
|
+
findInFiles,
|
|
19
|
+
kind,
|
|
20
|
+
parse,
|
|
21
|
+
parseAsync,
|
|
22
|
+
parseFiles,
|
|
23
|
+
pattern,
|
|
24
|
+
registerDynamicLanguage,
|
|
25
|
+
Lang,
|
|
26
|
+
SgNode,
|
|
27
|
+
SgRoot,
|
|
28
|
+
} from '@ast-grep/napi'
|
|
29
|
+
|
|
30
|
+
// 导出为对象,避免命名冲突
|
|
31
|
+
export const astgrep = {
|
|
32
|
+
findInFiles,
|
|
33
|
+
kind,
|
|
34
|
+
parse,
|
|
35
|
+
parseAsync,
|
|
36
|
+
parseFiles,
|
|
37
|
+
pattern,
|
|
38
|
+
registerDynamicLanguage,
|
|
39
|
+
Lang,
|
|
40
|
+
SgNode,
|
|
41
|
+
SgRoot,
|
|
42
|
+
}
|
package/big.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default as Big } from 'big.js'
|
|
2
|
-
export type { Big as BigType, BigSource } from 'big.js'
|
|
1
|
+
export { default as Big } from 'big.js'
|
|
2
|
+
export type { Big as BigType, BigSource } from 'big.js'
|
package/clipboardy.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default as clipboard } from 'clipboardy'
|
|
1
|
+
export { default as clipboard } from 'clipboardy'
|
package/dayjs.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default as dayjs } from 'dayjs'
|
|
2
|
-
export type { Dayjs, ConfigType, OptionType } from 'dayjs'
|
|
1
|
+
export { default as dayjs } from 'dayjs'
|
|
2
|
+
export type { Dayjs, ConfigType, OptionType } from 'dayjs'
|
package/dotenvx.ts
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
// 导入所有需要的模块
|
|
2
|
+
import { config, parse, set, get, ls, genexample } from '@dotenvx/dotenvx'
|
|
3
|
+
|
|
4
|
+
// 导出为对象,避免命名冲突
|
|
5
|
+
export const dotenvx = {
|
|
6
|
+
config,
|
|
7
|
+
parse,
|
|
8
|
+
set,
|
|
9
|
+
get,
|
|
10
|
+
ls,
|
|
11
|
+
genexample,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// 导出类型
|
|
2
15
|
export type {
|
|
3
16
|
DotenvConfigOptions,
|
|
4
17
|
DotenvConfigOutput,
|
|
@@ -10,4 +23,4 @@ export type {
|
|
|
10
23
|
SetOutput,
|
|
11
24
|
GetOptions,
|
|
12
25
|
GenExampleOutput,
|
|
13
|
-
} from
|
|
26
|
+
} from '@dotenvx/dotenvx'
|
package/eff/aff.ts
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { Result } from 'neverthrow'
|
|
2
|
+
import { err, ok, ResultAsync } from 'neverthrow'
|
|
3
|
+
import {
|
|
4
|
+
Actrl,
|
|
5
|
+
ABORT_REASON,
|
|
6
|
+
shortId,
|
|
7
|
+
type AffFn,
|
|
8
|
+
type NonEmptyArray,
|
|
9
|
+
type ExtractOk,
|
|
10
|
+
type ExtractErr,
|
|
11
|
+
} from './aff.util'
|
|
12
|
+
|
|
13
|
+
export class Aff {
|
|
14
|
+
/**
|
|
15
|
+
* 创建子任务(继承父 signal,支持取消传播)
|
|
16
|
+
*/
|
|
17
|
+
static make<T, E>(
|
|
18
|
+
actrlSpanId: string,
|
|
19
|
+
executor: AffFn<T, E>,
|
|
20
|
+
parentActrl: Actrl,
|
|
21
|
+
): ResultAsync<T, E> {
|
|
22
|
+
const actrl = new Actrl(actrlSpanId)
|
|
23
|
+
const unlink = parentActrl.link(actrl)
|
|
24
|
+
|
|
25
|
+
const executorResult = executor(actrl)
|
|
26
|
+
// 统一处理 PromiseLike 和 ResultAsync,转换为 Promise<Result<T, E>>
|
|
27
|
+
// ResultAsync 实现了 PromiseLike,Promise.resolve 可以处理它
|
|
28
|
+
const promise: Promise<Result<T, E>> = Promise.resolve(
|
|
29
|
+
executorResult as PromiseLike<Result<T, E>>,
|
|
30
|
+
)
|
|
31
|
+
.catch((e) => err(e as E))
|
|
32
|
+
.then((result) => {
|
|
33
|
+
actrl.resultStatus = result.isOk() ? 'ok' : 'err'
|
|
34
|
+
unlink()
|
|
35
|
+
actrl.cancel(ABORT_REASON.COMPLETED)
|
|
36
|
+
return result
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
return new ResultAsync(promise)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 创建根级任务(无父 signal)
|
|
44
|
+
*/
|
|
45
|
+
static root<T, E>(executor: AffFn<T, E>): ResultAsync<T, E> {
|
|
46
|
+
return Aff.make('root', executor, new Actrl('$', true))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static all<T extends NonEmptyArray<AffFn<unknown, unknown>>>(
|
|
50
|
+
executors: T,
|
|
51
|
+
parentActrl: Actrl,
|
|
52
|
+
): ResultAsync<
|
|
53
|
+
{ -readonly [P in keyof T]: ExtractOk<T[P]> },
|
|
54
|
+
ExtractErr<T[number]>
|
|
55
|
+
> {
|
|
56
|
+
const actrl = new Actrl('all#' + shortId())
|
|
57
|
+
const unlink = parentActrl.link(actrl)
|
|
58
|
+
|
|
59
|
+
// Result -> Promise 语义转换:err 变成 reject,这样 Promise.all 遇到 err 会立即返回
|
|
60
|
+
const toPromise = (ra: ResultAsync<unknown, unknown>) =>
|
|
61
|
+
ra.then((r) => (r.isOk() ? r.value : Promise.reject(r.error)))
|
|
62
|
+
|
|
63
|
+
const promise = Promise.all(
|
|
64
|
+
executors.map((fn, i) => toPromise(Aff.make(`all-${i}`, fn, actrl))),
|
|
65
|
+
)
|
|
66
|
+
.then((values) => {
|
|
67
|
+
unlink()
|
|
68
|
+
actrl.cancel(ABORT_REASON.COMPLETED)
|
|
69
|
+
return ok(values) as Result<
|
|
70
|
+
{ -readonly [P in keyof T]: ExtractOk<T[P]> },
|
|
71
|
+
ExtractErr<T[number]>
|
|
72
|
+
>
|
|
73
|
+
})
|
|
74
|
+
.catch((e) => {
|
|
75
|
+
unlink()
|
|
76
|
+
actrl.cancel(ABORT_REASON.SETTLED)
|
|
77
|
+
return err(e) as Result<
|
|
78
|
+
{ -readonly [P in keyof T]: ExtractOk<T[P]> },
|
|
79
|
+
ExtractErr<T[number]>
|
|
80
|
+
>
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
return new ResultAsync(promise)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static any<T extends NonEmptyArray<AffFn<unknown, unknown>>>(
|
|
87
|
+
executors: T,
|
|
88
|
+
parentActrl: Actrl,
|
|
89
|
+
): ResultAsync<ExtractOk<T[number]>, ExtractErr<T[number]>[]> {
|
|
90
|
+
const actrl = new Actrl('any#' + shortId())
|
|
91
|
+
const unlink = parentActrl.link(actrl)
|
|
92
|
+
|
|
93
|
+
// Result -> Promise 语义转换
|
|
94
|
+
const toPromise = (ra: ResultAsync<unknown, unknown>) =>
|
|
95
|
+
ra.then((r) => (r.isOk() ? r.value : Promise.reject(r.error)))
|
|
96
|
+
|
|
97
|
+
const promise = Promise.any(
|
|
98
|
+
executors.map((fn, i) => toPromise(Aff.make(`any-${i}`, fn, actrl))),
|
|
99
|
+
)
|
|
100
|
+
.then((value) => {
|
|
101
|
+
unlink()
|
|
102
|
+
actrl.cancel(ABORT_REASON.SETTLED)
|
|
103
|
+
return ok(value) as Result<
|
|
104
|
+
ExtractOk<T[number]>,
|
|
105
|
+
ExtractErr<T[number]>[]
|
|
106
|
+
>
|
|
107
|
+
})
|
|
108
|
+
.catch((e: AggregateError) => {
|
|
109
|
+
unlink()
|
|
110
|
+
actrl.cancel(ABORT_REASON.COMPLETED)
|
|
111
|
+
return err(e.errors) as Result<
|
|
112
|
+
ExtractOk<T[number]>,
|
|
113
|
+
ExtractErr<T[number]>[]
|
|
114
|
+
>
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
return new ResultAsync(promise)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
static race<T extends NonEmptyArray<AffFn<unknown, unknown>>>(
|
|
121
|
+
executors: T,
|
|
122
|
+
parentActrl: Actrl,
|
|
123
|
+
): ResultAsync<ExtractOk<T[number]>, ExtractErr<T[number]>> {
|
|
124
|
+
const actrl = new Actrl('race#' + shortId())
|
|
125
|
+
const unlink = parentActrl.link(actrl)
|
|
126
|
+
|
|
127
|
+
const promise = Promise.race(
|
|
128
|
+
executors.map((fn, i) => Aff.make(`race-${i}`, fn, actrl)),
|
|
129
|
+
).then((firstResult) => {
|
|
130
|
+
unlink()
|
|
131
|
+
actrl.cancel(ABORT_REASON.SETTLED)
|
|
132
|
+
return firstResult as Result<ExtractOk<T[number]>, ExtractErr<T[number]>>
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
return new ResultAsync(promise)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
static allSettled<T extends NonEmptyArray<AffFn<unknown, unknown>>>(
|
|
139
|
+
executors: T,
|
|
140
|
+
parentActrl: Actrl,
|
|
141
|
+
): ResultAsync<
|
|
142
|
+
{ -readonly [P in keyof T]: Result<ExtractOk<T[P]>, ExtractErr<T[P]>> },
|
|
143
|
+
never
|
|
144
|
+
> {
|
|
145
|
+
const actrl = new Actrl('settled#' + shortId())
|
|
146
|
+
const unlink = parentActrl.link(actrl)
|
|
147
|
+
|
|
148
|
+
const promise = Promise.all(
|
|
149
|
+
executors.map((fn, i) => Aff.make(`allSettled-${i}`, fn, actrl)),
|
|
150
|
+
).then((results) => {
|
|
151
|
+
unlink()
|
|
152
|
+
actrl.cancel(ABORT_REASON.COMPLETED)
|
|
153
|
+
return ok(results) as Result<
|
|
154
|
+
{ -readonly [P in keyof T]: Result<ExtractOk<T[P]>, ExtractErr<T[P]>> },
|
|
155
|
+
never
|
|
156
|
+
>
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
return new ResultAsync(promise)
|
|
160
|
+
}
|
|
161
|
+
}
|
package/eff/aff.util.ts
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { Result } from 'neverthrow'
|
|
2
|
+
import { err, ok, ResultAsync } from 'neverthrow'
|
|
3
|
+
import { tcNanoid } from '../staticMeta/string.nanoid'
|
|
4
|
+
|
|
5
|
+
export type ActrlSpan = {
|
|
6
|
+
id: string
|
|
7
|
+
parent: string
|
|
8
|
+
status: 'init'
|
|
9
|
+
startTime: number
|
|
10
|
+
duration: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class Actrl {
|
|
14
|
+
readonly ac: AbortController
|
|
15
|
+
public traceid: string = ''
|
|
16
|
+
public span: ActrlSpan = {
|
|
17
|
+
id: '',
|
|
18
|
+
parent: '',
|
|
19
|
+
status: 'init',
|
|
20
|
+
startTime: 0,
|
|
21
|
+
duration: 0,
|
|
22
|
+
}
|
|
23
|
+
private isRoot = false
|
|
24
|
+
public depth = 0 // 基于父子关系的真实深度
|
|
25
|
+
public resultStatus: 'ok' | 'err' | null = null // 任务返回状态
|
|
26
|
+
public logs: string[] = [] // 日志数组,用于收集日志信息
|
|
27
|
+
private rootLogs: string[] | null = null // 指向根 Actrl 的 logs,用于统一收集所有日志
|
|
28
|
+
|
|
29
|
+
constructor(spanid: string, isRoot = false) {
|
|
30
|
+
this.ac = new AbortController()
|
|
31
|
+
this.span.id = spanid
|
|
32
|
+
this.isRoot = isRoot
|
|
33
|
+
this.depth = isRoot ? 0 : 0
|
|
34
|
+
if (isRoot) {
|
|
35
|
+
this.rootLogs = this.logs // 根 Actrl 的 rootLogs 指向自己的 logs
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get aborted() {
|
|
40
|
+
return this.ac.signal.aborted
|
|
41
|
+
}
|
|
42
|
+
get reason(): unknown {
|
|
43
|
+
return this.ac.signal.reason
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
cancel(reason?: unknown) {
|
|
47
|
+
this.ac.abort(reason)
|
|
48
|
+
}
|
|
49
|
+
link(childActrl: Actrl) {
|
|
50
|
+
// 让子 Actrl 共享根 Actrl 的 logs
|
|
51
|
+
childActrl.rootLogs = this.rootLogs || this.logs
|
|
52
|
+
// 获取目标日志数组(根 Actrl 的 logs)
|
|
53
|
+
const getTargetLogs = () => this.rootLogs || this.logs
|
|
54
|
+
|
|
55
|
+
if (this.isRoot) {
|
|
56
|
+
this.traceid = tcNanoid()
|
|
57
|
+
childActrl.traceid = this.traceid
|
|
58
|
+
childActrl.depth = 1
|
|
59
|
+
|
|
60
|
+
const indent = formatIndent(childActrl.depth)
|
|
61
|
+
const displayId = childActrl.span.id
|
|
62
|
+
getTargetLogs().push(formatLogStart(indent, displayId))
|
|
63
|
+
|
|
64
|
+
if (this.ac.signal.aborted) {
|
|
65
|
+
childActrl.cancel(this.ac.signal.reason)
|
|
66
|
+
getTargetLogs().push(
|
|
67
|
+
formatLogCancel(indent, childActrl.span.id, 'parent aborted'),
|
|
68
|
+
)
|
|
69
|
+
return noop
|
|
70
|
+
}
|
|
71
|
+
const handler = () => {
|
|
72
|
+
childActrl.cancel(this.ac.signal.reason)
|
|
73
|
+
// 记录取消日志(当父任务因为 SETTLED 被取消时)
|
|
74
|
+
if (this.ac.signal.reason === ABORT_REASON.SETTLED) {
|
|
75
|
+
getTargetLogs().push(formatLogCancel(indent, childActrl.span.id))
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
this.ac.signal.addEventListener('abort', handler, { once: true })
|
|
79
|
+
return () => {
|
|
80
|
+
// 判断是否被外部取消(reason 是 'settled' 表示被其他任务抢先完成)
|
|
81
|
+
const isCancelled =
|
|
82
|
+
childActrl.aborted && childActrl.reason === ABORT_REASON.SETTLED
|
|
83
|
+
let status = ''
|
|
84
|
+
if (isCancelled) {
|
|
85
|
+
status = ' [cancelled]'
|
|
86
|
+
} else if (childActrl.resultStatus) {
|
|
87
|
+
status = ' [' + childActrl.resultStatus + ']'
|
|
88
|
+
}
|
|
89
|
+
getTargetLogs().push(formatLogEnd(indent, childActrl.span.id, status))
|
|
90
|
+
this.ac.signal.removeEventListener('abort', handler)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
childActrl.traceid = this.traceid
|
|
94
|
+
childActrl.span.parent = this.span.id
|
|
95
|
+
childActrl.depth = this.depth + 1
|
|
96
|
+
|
|
97
|
+
const indent = formatIndent(childActrl.depth)
|
|
98
|
+
const displayId = formatDisplayId(this.span.id, childActrl.span.id)
|
|
99
|
+
childActrl.span.id = displayId
|
|
100
|
+
getTargetLogs().push(formatLogStart(indent, displayId))
|
|
101
|
+
|
|
102
|
+
if (this.ac.signal.aborted) {
|
|
103
|
+
childActrl.cancel(this.ac.signal.reason)
|
|
104
|
+
getTargetLogs().push(
|
|
105
|
+
formatLogCancel(indent, childActrl.span.id, 'parent aborted'),
|
|
106
|
+
)
|
|
107
|
+
return noop
|
|
108
|
+
}
|
|
109
|
+
const handler = () => {
|
|
110
|
+
childActrl.cancel(this.ac.signal.reason)
|
|
111
|
+
// 记录取消日志(当父任务因为 SETTLED 被取消时)
|
|
112
|
+
if (this.ac.signal.reason === ABORT_REASON.SETTLED) {
|
|
113
|
+
getTargetLogs().push(formatLogCancel(indent, childActrl.span.id))
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
this.ac.signal.addEventListener('abort', handler, { once: true })
|
|
117
|
+
return () => {
|
|
118
|
+
// 判断是否被外部取消(reason 是 'settled' 表示被其他任务抢先完成)
|
|
119
|
+
const isCancelled =
|
|
120
|
+
childActrl.aborted && childActrl.reason === ABORT_REASON.SETTLED
|
|
121
|
+
let status = ''
|
|
122
|
+
if (isCancelled) {
|
|
123
|
+
status = ' [cancelled]'
|
|
124
|
+
} else if (childActrl.resultStatus) {
|
|
125
|
+
status = ' [' + childActrl.resultStatus + ']'
|
|
126
|
+
}
|
|
127
|
+
getTargetLogs().push(formatLogEnd(indent, childActrl.span.id, status))
|
|
128
|
+
this.ac.signal.removeEventListener('abort', handler)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
on(
|
|
132
|
+
type: string,
|
|
133
|
+
listener: EventListenerOrEventListenerObject,
|
|
134
|
+
options?: boolean | AddEventListenerOptions,
|
|
135
|
+
) {
|
|
136
|
+
this.ac.signal.addEventListener(type, listener, options)
|
|
137
|
+
}
|
|
138
|
+
off(
|
|
139
|
+
type: string,
|
|
140
|
+
listener: EventListenerOrEventListenerObject,
|
|
141
|
+
options?: boolean | EventListenerOptions,
|
|
142
|
+
) {
|
|
143
|
+
this.ac.signal.removeEventListener(type, listener, options)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export type AffFn<T, E> = (
|
|
148
|
+
actrl: Actrl,
|
|
149
|
+
) => PromiseLike<Result<T, E>> | ResultAsync<T, E>
|
|
150
|
+
export type NonEmptyArray<T> = readonly [T, ...T[]]
|
|
151
|
+
export type ExtractOk<T> = T extends AffFn<infer U, unknown> ? U : never
|
|
152
|
+
export type ExtractErr<T> = T extends AffFn<unknown, infer E> ? E : never
|
|
153
|
+
|
|
154
|
+
export const ABORT_REASON = { SETTLED: 'settled', COMPLETED: 'completed' } as const
|
|
155
|
+
export const noop = () => {}
|
|
156
|
+
|
|
157
|
+
// ============================================================
|
|
158
|
+
// 日志格式化函数
|
|
159
|
+
// ============================================================
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* 生成缩进字符串
|
|
163
|
+
*/
|
|
164
|
+
export const formatIndent = (depth: number): string => {
|
|
165
|
+
return ' '.repeat(depth)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* 格式化显示 ID(取父级最后一段 + 当前 id)
|
|
170
|
+
*/
|
|
171
|
+
export const formatDisplayId = (parentId: string, childId: string): string => {
|
|
172
|
+
const parentShort = parentId.split('/').pop() || parentId
|
|
173
|
+
return parentShort + '/' + childId
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* 格式化开始日志
|
|
178
|
+
*/
|
|
179
|
+
export const formatLogStart = (indent: string, id: string): string => {
|
|
180
|
+
return indent + '→ ' + id
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* 格式化结束日志
|
|
185
|
+
*/
|
|
186
|
+
export const formatLogEnd = (indent: string, id: string, status?: string): string => {
|
|
187
|
+
return indent + '← ' + id + (status || '')
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 格式化取消日志
|
|
192
|
+
*/
|
|
193
|
+
export const formatLogCancel = (
|
|
194
|
+
indent: string,
|
|
195
|
+
id: string,
|
|
196
|
+
reason?: string,
|
|
197
|
+
): string => {
|
|
198
|
+
if (reason === 'parent aborted') {
|
|
199
|
+
return indent + '✗ ' + id + ' [cancelled: parent aborted]'
|
|
200
|
+
}
|
|
201
|
+
return indent + '✗ ' + id + ' [cancelled]'
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* 打印日志
|
|
206
|
+
*/
|
|
207
|
+
export const printLogs = (logs: string[], title?: string): void => {
|
|
208
|
+
if (logs.length > 0) {
|
|
209
|
+
if (title) {
|
|
210
|
+
console.log(`=== ${title} ===`)
|
|
211
|
+
}
|
|
212
|
+
console.log(logs.join('\n'))
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// 简短 id 生成器
|
|
217
|
+
let _idCounter = 0
|
|
218
|
+
export const shortId = () => (++_idCounter).toString(36)
|
package/eff/eff.delay.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ok } from 'neverthrow'
|
|
2
|
+
import { Eff } from './eff'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 异步延迟函数:返回延迟是否完成(true)或被取消(false)
|
|
6
|
+
*/
|
|
7
|
+
export const delayEff = (time: number, parentSignal: AbortSignal) => {
|
|
8
|
+
return Eff.create<boolean, never>(({ signal }) => {
|
|
9
|
+
return new Promise((resolve) => {
|
|
10
|
+
const timer = setTimeout(() => resolve(ok(true)), time)
|
|
11
|
+
signal.addEventListener(
|
|
12
|
+
'abort',
|
|
13
|
+
() => {
|
|
14
|
+
clearTimeout(timer)
|
|
15
|
+
resolve(ok(false))
|
|
16
|
+
},
|
|
17
|
+
{ once: true },
|
|
18
|
+
)
|
|
19
|
+
})
|
|
20
|
+
}, parentSignal)
|
|
21
|
+
}
|