@jsbot-tellus/core 2.0.3 → 2.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.
- package/README.md +13 -17
- package/dist/app.js +12 -40
- package/dist/app.js.map +1 -1
- package/dist/core/config/schema.d.ts +0 -2
- package/dist/core/config/schema.d.ts.map +1 -1
- package/dist/core/config/schema.js +0 -1
- package/dist/core/config/schema.js.map +1 -1
- package/dist/core/dispatch/command.d.ts +24 -2
- package/dist/core/dispatch/command.d.ts.map +1 -1
- package/dist/core/dispatch/command.js +297 -60
- package/dist/core/dispatch/command.js.map +1 -1
- package/dist/core/dispatch/router.d.ts +17 -3
- package/dist/core/dispatch/router.d.ts.map +1 -1
- package/dist/core/dispatch/router.js +38 -2
- package/dist/core/dispatch/router.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/plugin/command-params.d.ts +15 -0
- package/dist/core/plugin/command-params.d.ts.map +1 -0
- package/dist/core/plugin/command-params.js +427 -0
- package/dist/core/plugin/command-params.js.map +1 -0
- package/dist/core/plugin/context.d.ts.map +1 -1
- package/dist/core/plugin/context.js +27 -0
- package/dist/core/plugin/context.js.map +1 -1
- package/dist/core/plugin/install-dir.d.ts +6 -9
- package/dist/core/plugin/install-dir.d.ts.map +1 -1
- package/dist/core/plugin/install-dir.js +99 -79
- package/dist/core/plugin/install-dir.js.map +1 -1
- package/dist/core/plugin/install-validate.d.ts +2 -1
- package/dist/core/plugin/install-validate.d.ts.map +1 -1
- package/dist/core/plugin/install-validate.js +25 -17
- package/dist/core/plugin/install-validate.js.map +1 -1
- package/dist/core/plugin/installer.d.ts +3 -3
- package/dist/core/plugin/installer.d.ts.map +1 -1
- package/dist/core/plugin/installer.js +143 -140
- package/dist/core/plugin/installer.js.map +1 -1
- package/dist/core/plugin/loader.d.ts +1 -0
- package/dist/core/plugin/loader.d.ts.map +1 -1
- package/dist/core/plugin/loader.js +24 -2
- package/dist/core/plugin/loader.js.map +1 -1
- package/dist/core/plugin/types.d.ts +11 -3
- package/dist/core/plugin/types.d.ts.map +1 -1
- package/dist/core/plugin/types.js.map +1 -1
- package/dist/plugins/admin/index.d.ts.map +1 -1
- package/dist/plugins/admin/index.js +119 -86
- package/dist/plugins/admin/index.js.map +1 -1
- package/dist/plugins/core/index.d.ts.map +1 -1
- package/dist/plugins/core/index.js +4 -1
- package/dist/plugins/core/index.js.map +1 -1
- package/docs/architecture.md +22 -24
- package/docs/configuration.md +19 -23
- package/docs/feature-parity.md +4 -4
- package/docs/migration.md +13 -13
- package/docs/plugin-api.md +156 -26
- package/docs/plugin-development.md +390 -0
- package/docs/release.md +2 -2
- package/examples/plugins/hello/README.md +10 -5
- package/examples/plugins/hello/index.js +3 -6
- package/package.json +2 -1
- package/src/app.ts +16 -55
- package/src/core/config/schema.ts +0 -1
- package/src/core/dispatch/command.ts +474 -70
- package/src/core/dispatch/router.ts +77 -3
- package/src/core/index.ts +2 -0
- package/src/core/plugin/command-params.ts +595 -0
- package/src/core/plugin/context.ts +47 -2
- package/src/core/plugin/install-dir.ts +117 -111
- package/src/core/plugin/install-validate.ts +36 -34
- package/src/core/plugin/installer.ts +228 -184
- package/src/core/plugin/loader.ts +36 -2
- package/src/core/plugin/types.ts +23 -3
- package/src/plugins/admin/index.ts +302 -233
- package/src/plugins/core/index.ts +5 -1
- package/dist/core/plugin/installed.d.ts +0 -9
- package/dist/core/plugin/installed.d.ts.map +0 -1
- package/dist/core/plugin/installed.js +0 -113
- package/dist/core/plugin/installed.js.map +0 -1
- package/src/core/plugin/installed.ts +0 -165
|
@@ -1,10 +1,20 @@
|
|
|
1
|
+
import type { OneBotMessageEvent } from '@snowluma/sdk'
|
|
2
|
+
import {
|
|
3
|
+
compileCommandParams,
|
|
4
|
+
type CompiledCommandParams,
|
|
5
|
+
} from '../plugin/command-params.js'
|
|
1
6
|
import type {
|
|
7
|
+
CommandGroupOptions,
|
|
8
|
+
CommandGroupRegistrar,
|
|
2
9
|
CommandHandler,
|
|
3
10
|
CommandInfo,
|
|
4
11
|
CommandMatch,
|
|
12
|
+
CommandOptions,
|
|
5
13
|
} from '../plugin/types.js'
|
|
6
14
|
import type { Permission } from '../security/permission.js'
|
|
7
15
|
|
|
16
|
+
type AnyCommandHandler = CommandHandler<OneBotMessageEvent, any[]>
|
|
17
|
+
|
|
8
18
|
export interface CommandRegistration {
|
|
9
19
|
pluginId: string
|
|
10
20
|
name: string
|
|
@@ -12,7 +22,21 @@ export interface CommandRegistration {
|
|
|
12
22
|
prefixes: string[]
|
|
13
23
|
permission: Permission
|
|
14
24
|
description?: string | undefined
|
|
15
|
-
|
|
25
|
+
params?: string | undefined
|
|
26
|
+
paramsParser?: CompiledCommandParams | undefined
|
|
27
|
+
usage?: string | undefined
|
|
28
|
+
handler: AnyCommandHandler
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface CommandGroupRegistration {
|
|
32
|
+
pluginId: string
|
|
33
|
+
name: string
|
|
34
|
+
aliases: string[]
|
|
35
|
+
prefixes: string[]
|
|
36
|
+
permission: Permission
|
|
37
|
+
description?: string | undefined
|
|
38
|
+
params?: string | undefined
|
|
39
|
+
handler?: AnyCommandHandler | undefined
|
|
16
40
|
}
|
|
17
41
|
|
|
18
42
|
export interface RegisteredCommand {
|
|
@@ -20,80 +44,167 @@ export interface RegisteredCommand {
|
|
|
20
44
|
match: CommandMatch
|
|
21
45
|
}
|
|
22
46
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
47
|
+
interface GroupChild {
|
|
48
|
+
name: string
|
|
49
|
+
description?: string | undefined
|
|
50
|
+
usage?: string | undefined
|
|
51
|
+
}
|
|
27
52
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
)
|
|
34
|
-
),
|
|
35
|
-
]
|
|
36
|
-
const prefixes = [...new Set(registration.prefixes)]
|
|
53
|
+
interface GroupScope {
|
|
54
|
+
registrar: CommandGroupRegistrar
|
|
55
|
+
disposeAll: () => void
|
|
56
|
+
track: (dispose: () => void, cleanup?: () => void) => () => void
|
|
57
|
+
}
|
|
37
58
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const existing = this.index.get(prefix)?.get(name)
|
|
59
|
+
function normalizeSegment(label: string, value: string): string {
|
|
60
|
+
const trimmed = value.trim()
|
|
41
61
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
}
|
|
62
|
+
if (!trimmed) {
|
|
63
|
+
throw new Error(`${label} must not be empty`)
|
|
64
|
+
}
|
|
47
65
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
66
|
+
if (/\s/.test(trimmed)) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`${label} must be a single segment; use commands.group() for multi-level commands`
|
|
69
|
+
)
|
|
70
|
+
}
|
|
51
71
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
72
|
+
return trimmed
|
|
73
|
+
}
|
|
55
74
|
|
|
56
|
-
|
|
57
|
-
|
|
75
|
+
function uniqueStrings(values: string[]): string[] {
|
|
76
|
+
const seen = new Set<string>()
|
|
77
|
+
const result: string[] = []
|
|
58
78
|
|
|
59
|
-
|
|
79
|
+
for (const value of values) {
|
|
80
|
+
const key = value.toLowerCase()
|
|
60
81
|
|
|
61
|
-
|
|
62
|
-
this.byPlugin.get(registration.pluginId) ??
|
|
63
|
-
new Set<CommandRegistration>()
|
|
64
|
-
pluginSet.add(registration)
|
|
65
|
-
this.byPlugin.set(registration.pluginId, pluginSet)
|
|
82
|
+
if (seen.has(key)) continue
|
|
66
83
|
|
|
67
|
-
|
|
84
|
+
seen.add(key)
|
|
85
|
+
result.push(value)
|
|
86
|
+
}
|
|
68
87
|
|
|
69
|
-
|
|
70
|
-
|
|
88
|
+
return result
|
|
89
|
+
}
|
|
71
90
|
|
|
72
|
-
|
|
91
|
+
function groupBases(name: string, aliases: string[]): string[] {
|
|
92
|
+
return uniqueStrings([
|
|
93
|
+
normalizeSegment('group name', name),
|
|
94
|
+
...aliases.map((alias) => normalizeSegment('group alias', alias)),
|
|
95
|
+
])
|
|
96
|
+
}
|
|
73
97
|
|
|
74
|
-
|
|
75
|
-
|
|
98
|
+
function composedBases(
|
|
99
|
+
parentBases: string[],
|
|
100
|
+
name: string,
|
|
101
|
+
aliases: string[],
|
|
102
|
+
kind: 'command' | 'group'
|
|
103
|
+
): string[] {
|
|
104
|
+
const variants = uniqueStrings([
|
|
105
|
+
normalizeSegment(`${kind} name`, name),
|
|
106
|
+
...aliases.map((alias) => normalizeSegment(`${kind} alias`, alias)),
|
|
107
|
+
])
|
|
108
|
+
const bases: string[] = []
|
|
109
|
+
const seen = new Set<string>()
|
|
110
|
+
|
|
111
|
+
for (const parent of parentBases) {
|
|
112
|
+
for (const variant of variants) {
|
|
113
|
+
const path = `${parent} ${variant}`
|
|
114
|
+
const key = path.toLowerCase()
|
|
115
|
+
|
|
116
|
+
if (seen.has(key)) continue
|
|
117
|
+
|
|
118
|
+
seen.add(key)
|
|
119
|
+
bases.push(path)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
76
122
|
|
|
77
|
-
|
|
123
|
+
return bases
|
|
124
|
+
}
|
|
78
125
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
126
|
+
function createGroupUsageHandler(children: GroupChild[]): AnyCommandHandler {
|
|
127
|
+
return async (_event, context, match) => {
|
|
128
|
+
const root = `${match.prefix}${match.command}`
|
|
129
|
+
const names = children.map((child) => child.name)
|
|
130
|
+
const lines = [
|
|
131
|
+
names.length > 0
|
|
132
|
+
? `用法:${root} <${names.join('|')}>`
|
|
133
|
+
: `用法:${root}`,
|
|
134
|
+
]
|
|
84
135
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
136
|
+
for (const child of children) {
|
|
137
|
+
const usage = child.usage !== undefined ? ` ${child.usage}` : ''
|
|
138
|
+
const command = `${root} ${child.name}${usage}`
|
|
89
139
|
|
|
90
|
-
|
|
91
|
-
|
|
140
|
+
lines.push(
|
|
141
|
+
child.description !== undefined
|
|
142
|
+
? `${command} - ${child.description}`
|
|
143
|
+
: command
|
|
144
|
+
)
|
|
145
|
+
}
|
|
92
146
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
147
|
+
await context.send(lines.join('\n'))
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export class CommandRegistry {
|
|
152
|
+
private readonly index = new Map<string, Map<string, CommandRegistration>>()
|
|
153
|
+
private readonly registrations = new Set<CommandRegistration>()
|
|
154
|
+
private readonly byPlugin = new Map<string, Set<CommandRegistration>>()
|
|
155
|
+
|
|
156
|
+
register(registration: CommandRegistration): () => void {
|
|
157
|
+
const name = normalizeSegment('command name', registration.name)
|
|
158
|
+
const aliases = uniqueStrings(
|
|
159
|
+
registration.aliases.map((alias) =>
|
|
160
|
+
normalizeSegment('command alias', alias)
|
|
161
|
+
)
|
|
162
|
+
).filter((alias) => alias.toLowerCase() !== name.toLowerCase())
|
|
163
|
+
const normalized = this.withParams({
|
|
164
|
+
...registration,
|
|
165
|
+
name,
|
|
166
|
+
aliases,
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
return this.insert(normalized, [name, ...aliases])
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
group(
|
|
173
|
+
registration: CommandGroupRegistration,
|
|
174
|
+
setup: (group: CommandGroupRegistrar) => void
|
|
175
|
+
): () => void {
|
|
176
|
+
const prefixes = uniqueStrings(registration.prefixes)
|
|
177
|
+
const bases = groupBases(registration.name, registration.aliases)
|
|
178
|
+
const children: GroupChild[] = []
|
|
179
|
+
const scope = this.createGroupScope(
|
|
180
|
+
registration.pluginId,
|
|
181
|
+
bases,
|
|
182
|
+
prefixes,
|
|
183
|
+
registration.permission,
|
|
184
|
+
children
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
setup(scope.registrar)
|
|
189
|
+
|
|
190
|
+
const dispose = this.registerGroupRoot(
|
|
191
|
+
registration.pluginId,
|
|
192
|
+
bases,
|
|
193
|
+
prefixes,
|
|
194
|
+
registration.permission,
|
|
195
|
+
registration.description,
|
|
196
|
+
registration.params,
|
|
197
|
+
registration.handler,
|
|
198
|
+
children
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
scope.track(dispose)
|
|
202
|
+
} catch (error) {
|
|
203
|
+
scope.disposeAll()
|
|
204
|
+
throw error
|
|
96
205
|
}
|
|
206
|
+
|
|
207
|
+
return scope.disposeAll
|
|
97
208
|
}
|
|
98
209
|
|
|
99
210
|
removePlugin(pluginId: string): void {
|
|
@@ -102,12 +213,11 @@ export class CommandRegistry {
|
|
|
102
213
|
if (!registrations) return
|
|
103
214
|
|
|
104
215
|
for (const registration of [...registrations]) {
|
|
105
|
-
const prefixes = registration.prefixes
|
|
106
216
|
const names = [registration.name, ...registration.aliases].map(
|
|
107
217
|
(name) => name.toLowerCase()
|
|
108
218
|
)
|
|
109
219
|
|
|
110
|
-
for (const prefix of prefixes) {
|
|
220
|
+
for (const prefix of registration.prefixes) {
|
|
111
221
|
const bucket = this.index.get(prefix)
|
|
112
222
|
|
|
113
223
|
if (!bucket) continue
|
|
@@ -139,6 +249,9 @@ export class CommandRegistry {
|
|
|
139
249
|
...(registration.description !== undefined
|
|
140
250
|
? { description: registration.description }
|
|
141
251
|
: {}),
|
|
252
|
+
...(registration.usage !== undefined
|
|
253
|
+
? { usage: registration.usage }
|
|
254
|
+
: {}),
|
|
142
255
|
pluginId: registration.pluginId,
|
|
143
256
|
}))
|
|
144
257
|
}
|
|
@@ -159,22 +272,313 @@ export class CommandRegistry {
|
|
|
159
272
|
|
|
160
273
|
if (!text) continue
|
|
161
274
|
|
|
162
|
-
const
|
|
163
|
-
|
|
275
|
+
const tokens = [...text.matchAll(/\S+/g)]
|
|
276
|
+
|
|
277
|
+
if (tokens.length === 0) continue
|
|
278
|
+
|
|
279
|
+
for (let count = tokens.length; count >= 1; count -= 1) {
|
|
280
|
+
const matched = tokens.slice(0, count)
|
|
281
|
+
const first = matched[0]
|
|
282
|
+
const last = matched[matched.length - 1]
|
|
283
|
+
|
|
284
|
+
if (!first || !last) continue
|
|
285
|
+
|
|
286
|
+
const key = matched
|
|
287
|
+
.map((token) => token[0])
|
|
288
|
+
.join(' ')
|
|
289
|
+
.toLowerCase()
|
|
290
|
+
const registration = this.index.get(prefix)?.get(key)
|
|
164
291
|
|
|
165
|
-
|
|
292
|
+
if (!registration) continue
|
|
166
293
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
294
|
+
const start = first.index ?? 0
|
|
295
|
+
const end = (last.index ?? 0) + last[0].length
|
|
296
|
+
|
|
297
|
+
return {
|
|
298
|
+
registration,
|
|
299
|
+
match: {
|
|
300
|
+
command: text
|
|
301
|
+
.slice(start, end)
|
|
302
|
+
.replace(/\s+/g, ' ')
|
|
303
|
+
.trim(),
|
|
304
|
+
prefix,
|
|
305
|
+
args: tokens.slice(count).map((token) => token[0]),
|
|
306
|
+
rest: text.slice(end).trim(),
|
|
307
|
+
},
|
|
308
|
+
}
|
|
175
309
|
}
|
|
176
310
|
}
|
|
177
311
|
|
|
178
312
|
return null
|
|
179
313
|
}
|
|
314
|
+
|
|
315
|
+
private withParams(registration: CommandRegistration): CommandRegistration {
|
|
316
|
+
if (registration.params === undefined) return registration
|
|
317
|
+
|
|
318
|
+
const compiled = compileCommandParams(registration.params)
|
|
319
|
+
|
|
320
|
+
return {
|
|
321
|
+
...registration,
|
|
322
|
+
paramsParser: compiled,
|
|
323
|
+
usage: compiled.usage,
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
private insert(
|
|
328
|
+
registration: CommandRegistration,
|
|
329
|
+
paths: string[]
|
|
330
|
+
): () => void {
|
|
331
|
+
const prefixes = uniqueStrings(registration.prefixes)
|
|
332
|
+
const names = uniqueStrings(paths)
|
|
333
|
+
|
|
334
|
+
for (const prefix of prefixes) {
|
|
335
|
+
for (const name of names) {
|
|
336
|
+
const existing = this.index.get(prefix)?.get(name.toLowerCase())
|
|
337
|
+
|
|
338
|
+
if (existing) {
|
|
339
|
+
throw new Error(`command conflict: ${prefix}${name}`)
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
for (const prefix of prefixes) {
|
|
345
|
+
const bucket =
|
|
346
|
+
this.index.get(prefix) ?? new Map<string, CommandRegistration>()
|
|
347
|
+
|
|
348
|
+
for (const name of names) {
|
|
349
|
+
bucket.set(name.toLowerCase(), registration)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
this.index.set(prefix, bucket)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
this.registrations.add(registration)
|
|
356
|
+
|
|
357
|
+
const pluginSet =
|
|
358
|
+
this.byPlugin.get(registration.pluginId) ??
|
|
359
|
+
new Set<CommandRegistration>()
|
|
360
|
+
pluginSet.add(registration)
|
|
361
|
+
this.byPlugin.set(registration.pluginId, pluginSet)
|
|
362
|
+
|
|
363
|
+
let disposed = false
|
|
364
|
+
|
|
365
|
+
return () => {
|
|
366
|
+
if (disposed) return
|
|
367
|
+
|
|
368
|
+
disposed = true
|
|
369
|
+
|
|
370
|
+
for (const prefix of prefixes) {
|
|
371
|
+
const bucket = this.index.get(prefix)
|
|
372
|
+
|
|
373
|
+
if (!bucket) continue
|
|
374
|
+
|
|
375
|
+
for (const name of names) {
|
|
376
|
+
if (bucket.get(name.toLowerCase()) === registration) {
|
|
377
|
+
bucket.delete(name.toLowerCase())
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (bucket.size === 0) {
|
|
382
|
+
this.index.delete(prefix)
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
this.registrations.delete(registration)
|
|
387
|
+
pluginSet.delete(registration)
|
|
388
|
+
|
|
389
|
+
if (pluginSet.size === 0) {
|
|
390
|
+
this.byPlugin.delete(registration.pluginId)
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
private createGroupScope(
|
|
396
|
+
pluginId: string,
|
|
397
|
+
bases: string[],
|
|
398
|
+
prefixes: string[],
|
|
399
|
+
permission: Permission,
|
|
400
|
+
children: GroupChild[]
|
|
401
|
+
): GroupScope {
|
|
402
|
+
const disposers: Array<() => void> = []
|
|
403
|
+
let disposed = false
|
|
404
|
+
|
|
405
|
+
const track = (
|
|
406
|
+
dispose: () => void,
|
|
407
|
+
cleanup?: () => void
|
|
408
|
+
): (() => void) => {
|
|
409
|
+
let done = false
|
|
410
|
+
|
|
411
|
+
const tracked = (): void => {
|
|
412
|
+
if (done) return
|
|
413
|
+
|
|
414
|
+
done = true
|
|
415
|
+
cleanup?.()
|
|
416
|
+
dispose()
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
disposers.push(tracked)
|
|
420
|
+
|
|
421
|
+
return tracked
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const disposeAll = (): void => {
|
|
425
|
+
if (disposed) return
|
|
426
|
+
|
|
427
|
+
disposed = true
|
|
428
|
+
|
|
429
|
+
for (const dispose of disposers.splice(0).reverse()) {
|
|
430
|
+
dispose()
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const registrar: CommandGroupRegistrar = {
|
|
435
|
+
register: <TArgs extends unknown[] = []>(
|
|
436
|
+
options: CommandOptions,
|
|
437
|
+
handler: CommandHandler<OneBotMessageEvent, TArgs>
|
|
438
|
+
) => {
|
|
439
|
+
const childBases = composedBases(
|
|
440
|
+
bases,
|
|
441
|
+
options.name,
|
|
442
|
+
options.aliases ?? [],
|
|
443
|
+
'command'
|
|
444
|
+
)
|
|
445
|
+
const name = childBases[0]
|
|
446
|
+
|
|
447
|
+
if (!name) {
|
|
448
|
+
throw new Error('command name must not be empty')
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
const registration = this.withParams({
|
|
452
|
+
pluginId,
|
|
453
|
+
name,
|
|
454
|
+
aliases: childBases.slice(1),
|
|
455
|
+
prefixes: options.prefixes ?? prefixes,
|
|
456
|
+
permission: options.permission ?? permission,
|
|
457
|
+
...(options.description !== undefined
|
|
458
|
+
? { description: options.description }
|
|
459
|
+
: {}),
|
|
460
|
+
...(options.params !== undefined
|
|
461
|
+
? { params: options.params }
|
|
462
|
+
: {}),
|
|
463
|
+
handler,
|
|
464
|
+
})
|
|
465
|
+
const dispose = this.insert(registration, childBases)
|
|
466
|
+
const record: GroupChild = {
|
|
467
|
+
name: options.name.trim(),
|
|
468
|
+
...(options.description !== undefined
|
|
469
|
+
? { description: options.description }
|
|
470
|
+
: {}),
|
|
471
|
+
...(registration.usage !== undefined
|
|
472
|
+
? { usage: registration.usage }
|
|
473
|
+
: {}),
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
children.push(record)
|
|
477
|
+
|
|
478
|
+
return track(dispose, () => {
|
|
479
|
+
const index = children.indexOf(record)
|
|
480
|
+
|
|
481
|
+
if (index >= 0) {
|
|
482
|
+
children.splice(index, 1)
|
|
483
|
+
}
|
|
484
|
+
})
|
|
485
|
+
},
|
|
486
|
+
|
|
487
|
+
group: <TArgs extends unknown[] = []>(
|
|
488
|
+
options: CommandGroupOptions<TArgs>,
|
|
489
|
+
nestedSetup: (group: CommandGroupRegistrar) => void
|
|
490
|
+
) => {
|
|
491
|
+
const nestedBases = composedBases(
|
|
492
|
+
bases,
|
|
493
|
+
options.name,
|
|
494
|
+
options.aliases ?? [],
|
|
495
|
+
'group'
|
|
496
|
+
)
|
|
497
|
+
const nestedPrefixes = options.prefixes ?? prefixes
|
|
498
|
+
const nestedPermission = options.permission ?? permission
|
|
499
|
+
const nestedChildren: GroupChild[] = []
|
|
500
|
+
const nestedScope = this.createGroupScope(
|
|
501
|
+
pluginId,
|
|
502
|
+
nestedBases,
|
|
503
|
+
nestedPrefixes,
|
|
504
|
+
nestedPermission,
|
|
505
|
+
nestedChildren
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
try {
|
|
509
|
+
nestedSetup(nestedScope.registrar)
|
|
510
|
+
|
|
511
|
+
const dispose = this.registerGroupRoot(
|
|
512
|
+
pluginId,
|
|
513
|
+
nestedBases,
|
|
514
|
+
nestedPrefixes,
|
|
515
|
+
nestedPermission,
|
|
516
|
+
options.description,
|
|
517
|
+
options.params,
|
|
518
|
+
options.handler,
|
|
519
|
+
nestedChildren
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
nestedScope.track(dispose)
|
|
523
|
+
} catch (error) {
|
|
524
|
+
nestedScope.disposeAll()
|
|
525
|
+
throw error
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const record: GroupChild = {
|
|
529
|
+
name: options.name.trim(),
|
|
530
|
+
...(options.description !== undefined
|
|
531
|
+
? { description: options.description }
|
|
532
|
+
: {}),
|
|
533
|
+
...(options.params !== undefined
|
|
534
|
+
? {
|
|
535
|
+
usage: compileCommandParams(options.params).usage,
|
|
536
|
+
}
|
|
537
|
+
: {}),
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
children.push(record)
|
|
541
|
+
|
|
542
|
+
return track(nestedScope.disposeAll, () => {
|
|
543
|
+
const index = children.indexOf(record)
|
|
544
|
+
|
|
545
|
+
if (index >= 0) {
|
|
546
|
+
children.splice(index, 1)
|
|
547
|
+
}
|
|
548
|
+
})
|
|
549
|
+
},
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
return { registrar, disposeAll, track }
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
private registerGroupRoot(
|
|
556
|
+
pluginId: string,
|
|
557
|
+
bases: string[],
|
|
558
|
+
prefixes: string[],
|
|
559
|
+
permission: Permission,
|
|
560
|
+
description: string | undefined,
|
|
561
|
+
params: string | undefined,
|
|
562
|
+
handler: AnyCommandHandler | undefined,
|
|
563
|
+
children: GroupChild[]
|
|
564
|
+
): () => void {
|
|
565
|
+
const name = bases[0]
|
|
566
|
+
|
|
567
|
+
if (!name) {
|
|
568
|
+
throw new Error('group name must not be empty')
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const registration = this.withParams({
|
|
572
|
+
pluginId,
|
|
573
|
+
name,
|
|
574
|
+
aliases: bases.slice(1),
|
|
575
|
+
prefixes,
|
|
576
|
+
permission,
|
|
577
|
+
...(description !== undefined ? { description } : {}),
|
|
578
|
+
...(params !== undefined ? { params } : {}),
|
|
579
|
+
handler: handler ?? createGroupUsageHandler(children),
|
|
580
|
+
})
|
|
581
|
+
|
|
582
|
+
return this.insert(registration, bases)
|
|
583
|
+
}
|
|
180
584
|
}
|