@pikku/core 0.9.12-next.0 → 0.10.1
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/CHANGELOG.md +14 -0
- package/dist/errors/errors.d.ts +2 -0
- package/dist/errors/errors.js +6 -0
- package/dist/function/function-runner.d.ts +5 -4
- package/dist/function/function-runner.js +10 -4
- package/dist/function/functions.types.d.ts +67 -1
- package/dist/function/functions.types.js +43 -1
- package/dist/index.d.ts +1 -7
- package/dist/index.js +1 -7
- package/dist/middleware/auth-apikey.d.ts +19 -11
- package/dist/middleware/auth-apikey.js +33 -33
- package/dist/middleware/auth-bearer.d.ts +34 -7
- package/dist/middleware/auth-bearer.js +53 -36
- package/dist/middleware/auth-cookie.d.ts +30 -12
- package/dist/middleware/auth-cookie.js +51 -43
- package/dist/middleware/timeout.d.ts +6 -2
- package/dist/middleware/timeout.js +7 -9
- package/dist/middleware-runner.d.ts +0 -18
- package/dist/middleware-runner.js +0 -21
- package/dist/permissions.d.ts +82 -20
- package/dist/permissions.js +175 -62
- package/dist/pikku-state.d.ts +22 -2
- package/dist/pikku-state.js +7 -1
- package/dist/types/core.types.d.ts +58 -1
- package/dist/types/core.types.js +23 -1
- package/dist/utils.d.ts +1 -1
- package/dist/wirings/channel/channel-handler.js +6 -5
- package/dist/wirings/channel/channel-runner.d.ts +3 -1
- package/dist/wirings/channel/channel-runner.js +4 -21
- package/dist/wirings/channel/channel.types.d.ts +12 -13
- package/dist/wirings/cli/channel/cli-channel-runner.js +5 -2
- package/dist/wirings/cli/cli-runner.d.ts +10 -0
- package/dist/wirings/cli/cli-runner.js +44 -20
- package/dist/wirings/cli/cli.types.d.ts +54 -27
- package/dist/wirings/cli/command-parser.js +34 -4
- package/dist/wirings/cli/index.d.ts +1 -1
- package/dist/wirings/cli/index.js +1 -1
- package/dist/wirings/http/http-runner.d.ts +31 -1
- package/dist/wirings/http/http-runner.js +36 -1
- package/dist/wirings/http/http.types.d.ts +2 -1
- package/dist/wirings/http/index.d.ts +1 -1
- package/dist/wirings/http/index.js +1 -1
- package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
- package/dist/wirings/mcp/mcp-runner.js +2 -0
- package/dist/wirings/mcp/mcp.types.d.ts +35 -14
- package/dist/wirings/queue/queue-runner.js +1 -0
- package/dist/wirings/scheduler/scheduler-runner.js +1 -0
- package/dist/wirings/scheduler/scheduler.types.d.ts +2 -2
- package/package.json +6 -5
- package/src/errors/errors.ts +6 -0
- package/src/factory-functions.test.ts +60 -1
- package/src/function/function-runner.test.ts +8 -3
- package/src/function/function-runner.ts +18 -5
- package/src/function/functions.types.ts +85 -2
- package/src/index.ts +1 -21
- package/src/middleware/auth-apikey.ts +42 -57
- package/src/middleware/auth-bearer.ts +66 -49
- package/src/middleware/auth-cookie.ts +63 -82
- package/src/middleware/timeout.ts +10 -14
- package/src/middleware-runner.ts +0 -25
- package/src/permissions.test.ts +26 -27
- package/src/permissions.ts +215 -104
- package/src/pikku-state.ts +35 -3
- package/src/types/core.types.ts +70 -3
- package/src/utils.ts +1 -1
- package/src/wirings/channel/channel-handler.ts +11 -10
- package/src/wirings/channel/channel-runner.ts +18 -27
- package/src/wirings/channel/channel.types.ts +24 -15
- package/src/wirings/cli/channel/cli-channel-runner.ts +8 -3
- package/src/wirings/cli/cli-runner.test.ts +80 -59
- package/src/wirings/cli/cli-runner.ts +57 -21
- package/src/wirings/cli/cli.types.ts +74 -44
- package/src/wirings/cli/command-parser.test.ts +91 -86
- package/src/wirings/cli/command-parser.ts +38 -4
- package/src/wirings/cli/index.ts +1 -0
- package/src/wirings/http/http-runner.ts +41 -1
- package/src/wirings/http/http.types.ts +3 -1
- package/src/wirings/http/index.ts +7 -1
- package/src/wirings/mcp/mcp-endpoint-registry.ts +1 -1
- package/src/wirings/mcp/mcp-runner.ts +2 -0
- package/src/wirings/mcp/mcp.types.ts +48 -12
- package/src/wirings/queue/queue-runner.ts +1 -0
- package/src/wirings/scheduler/scheduler-runner.ts +1 -0
- package/src/wirings/scheduler/scheduler.types.ts +2 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
CLIProgramState,
|
|
16
16
|
CorePikkuCLIRender,
|
|
17
17
|
CoreCLICommandConfig,
|
|
18
|
+
CLIMeta,
|
|
18
19
|
} from './cli.types.js'
|
|
19
20
|
import type {
|
|
20
21
|
CoreSingletonServices,
|
|
@@ -30,6 +31,20 @@ import { PikkuUserSessionService } from '../../services/user-session-service.js'
|
|
|
30
31
|
import { LocalVariablesService } from '../../services/local-variables.js'
|
|
31
32
|
import { generateCommandHelp, parseCLIArguments } from './command-parser.js'
|
|
32
33
|
|
|
34
|
+
/**
|
|
35
|
+
* CLI command execution error - thrown when CLI execution fails
|
|
36
|
+
* Should be caught by the wrapper to call process.exit()
|
|
37
|
+
*/
|
|
38
|
+
export class CLIError extends Error {
|
|
39
|
+
constructor(
|
|
40
|
+
message: string,
|
|
41
|
+
public exitCode: number = 1
|
|
42
|
+
) {
|
|
43
|
+
super(message)
|
|
44
|
+
this.name = 'CLIError'
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
33
48
|
/**
|
|
34
49
|
* Default JSON renderer for CLI output
|
|
35
50
|
*/
|
|
@@ -51,7 +66,7 @@ export const wireCLI = <
|
|
|
51
66
|
// Get the existing metadata that was generated during inspection
|
|
52
67
|
const cliMeta = pikkuState('cli', 'meta') || {}
|
|
53
68
|
|
|
54
|
-
if (!cliMeta[cli.program]) {
|
|
69
|
+
if (!cliMeta.programs?.[cli.program]) {
|
|
55
70
|
throw new Error(
|
|
56
71
|
`CLI metadata not found for program '${cli.program}'. Did you run 'pikku all'?`
|
|
57
72
|
)
|
|
@@ -122,7 +137,7 @@ function registerCLICommands(
|
|
|
122
137
|
program: string
|
|
123
138
|
) {
|
|
124
139
|
// Get the CLI metadata to find actual function names
|
|
125
|
-
const cliMeta = pikkuState('cli', 'meta')[program]
|
|
140
|
+
const cliMeta = pikkuState('cli', 'meta').programs[program]
|
|
126
141
|
|
|
127
142
|
for (const [name, command] of Object.entries(commands)) {
|
|
128
143
|
const fullPath = [...path, name]
|
|
@@ -242,7 +257,7 @@ export async function runCLICommand({
|
|
|
242
257
|
}): Promise<any> {
|
|
243
258
|
// Get the command metadata to find the function name
|
|
244
259
|
const cliMeta = pikkuState('cli', 'meta')
|
|
245
|
-
const programMeta = cliMeta[program]
|
|
260
|
+
const programMeta = cliMeta.programs?.[program]
|
|
246
261
|
if (!programMeta) {
|
|
247
262
|
throw new NotFoundError(`Program not found: ${program}`)
|
|
248
263
|
}
|
|
@@ -346,14 +361,6 @@ export async function runCLICommand({
|
|
|
346
361
|
)
|
|
347
362
|
}
|
|
348
363
|
|
|
349
|
-
// Build inherited middleware from tags
|
|
350
|
-
const inheritedMiddleware: any[] = []
|
|
351
|
-
if (programData?.tags) {
|
|
352
|
-
for (const tag of programData.tags) {
|
|
353
|
-
inheritedMiddleware.push({ type: 'tag', tag })
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
364
|
try {
|
|
358
365
|
const result = await runPikkuFunc(
|
|
359
366
|
PikkuWiringTypes.cli,
|
|
@@ -365,8 +372,11 @@ export async function runCLICommand({
|
|
|
365
372
|
data: pluckedData,
|
|
366
373
|
auth: false,
|
|
367
374
|
userSession,
|
|
368
|
-
inheritedMiddleware,
|
|
375
|
+
inheritedMiddleware: currentCommand.middleware,
|
|
369
376
|
wireMiddleware: allWireMiddleware,
|
|
377
|
+
inheritedPermissions: currentCommand.permissions,
|
|
378
|
+
wirePermissions: undefined,
|
|
379
|
+
tags: programData?.tags,
|
|
370
380
|
interaction,
|
|
371
381
|
}
|
|
372
382
|
)
|
|
@@ -410,10 +420,12 @@ export const pikkuCLIRender = <
|
|
|
410
420
|
/**
|
|
411
421
|
* Execute a CLI program with the given arguments
|
|
412
422
|
* This is the main entry point for CLI programs
|
|
423
|
+
*
|
|
424
|
+
* @throws {CLIError} When CLI execution fails - should be caught by wrapper to call process.exit()
|
|
413
425
|
*/
|
|
414
426
|
export async function executeCLI({
|
|
415
427
|
programName,
|
|
416
|
-
args
|
|
428
|
+
args,
|
|
417
429
|
createConfig,
|
|
418
430
|
createSingletonServices,
|
|
419
431
|
createSessionServices,
|
|
@@ -424,21 +436,39 @@ export async function executeCLI({
|
|
|
424
436
|
createSingletonServices: CreateSingletonServices<any, any>
|
|
425
437
|
createSessionServices?: CreateSessionServices<any, any>
|
|
426
438
|
}): Promise<void> {
|
|
439
|
+
if (!args) {
|
|
440
|
+
throw new Error(
|
|
441
|
+
'CLI arguments are required, this is to satisfy release diffs'
|
|
442
|
+
)
|
|
443
|
+
}
|
|
444
|
+
|
|
427
445
|
try {
|
|
428
446
|
// Get CLI metadata from state
|
|
429
|
-
const allCLIMeta = pikkuState('cli', 'meta')
|
|
430
|
-
|
|
447
|
+
const allCLIMeta = pikkuState('cli', 'meta') as unknown as
|
|
448
|
+
| CLIMeta
|
|
449
|
+
| undefined
|
|
450
|
+
if (!allCLIMeta) {
|
|
451
|
+
throw new Error(
|
|
452
|
+
'[PKU342] CLI metadata not found. No CLI wirings were registered. See https://pikku.dev/errors/pku342 for more information.'
|
|
453
|
+
)
|
|
454
|
+
}
|
|
455
|
+
const programMeta = allCLIMeta.programs[programName]
|
|
431
456
|
|
|
432
457
|
if (!programMeta) {
|
|
433
|
-
|
|
434
|
-
process.exit(1)
|
|
458
|
+
throw new CLIError(`CLI program "${programName}" not found`, 1)
|
|
435
459
|
}
|
|
436
460
|
|
|
437
461
|
// Parse arguments for this specific program
|
|
438
462
|
const parsed = parseCLIArguments(args, programName, allCLIMeta)
|
|
439
463
|
|
|
440
464
|
// Handle help (check after parsing to support subcommand help)
|
|
441
|
-
if
|
|
465
|
+
// Show help if --help/-h is present, or if no args AND no default command
|
|
466
|
+
const shouldShowHelp =
|
|
467
|
+
args.includes('--help') ||
|
|
468
|
+
args.includes('-h') ||
|
|
469
|
+
(args.length === 0 && parsed.commandPath.length === 0)
|
|
470
|
+
|
|
471
|
+
if (shouldShowHelp) {
|
|
442
472
|
const helpText = generateCommandHelp(
|
|
443
473
|
programName,
|
|
444
474
|
allCLIMeta,
|
|
@@ -464,12 +494,12 @@ export async function executeCLI({
|
|
|
464
494
|
parsed.commandPath
|
|
465
495
|
)
|
|
466
496
|
console.log(helpText)
|
|
467
|
-
|
|
497
|
+
throw new CLIError('Unknown command', 1)
|
|
468
498
|
} else {
|
|
469
499
|
// Show errors for other types of errors
|
|
470
500
|
console.error('Errors:')
|
|
471
501
|
parsed.errors.forEach((error) => console.error(` ${error}`))
|
|
472
|
-
|
|
502
|
+
throw new CLIError(parsed.errors.join('\n'), 1)
|
|
473
503
|
}
|
|
474
504
|
}
|
|
475
505
|
|
|
@@ -491,6 +521,12 @@ export async function executeCLI({
|
|
|
491
521
|
createSessionServices,
|
|
492
522
|
})
|
|
493
523
|
} catch (error: any) {
|
|
524
|
+
// Re-throw CLIError as-is
|
|
525
|
+
if (error instanceof CLIError) {
|
|
526
|
+
throw error
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// Wrap other errors in CLIError
|
|
494
530
|
console.error('Error:', error)
|
|
495
531
|
|
|
496
532
|
// Show stack trace in verbose mode
|
|
@@ -498,6 +534,6 @@ export async function executeCLI({
|
|
|
498
534
|
console.error('Stack trace:', error.stack)
|
|
499
535
|
}
|
|
500
536
|
|
|
501
|
-
|
|
537
|
+
throw new CLIError(error.message || String(error), 1)
|
|
502
538
|
}
|
|
503
539
|
}
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
PikkuDocs,
|
|
6
6
|
CoreServices,
|
|
7
7
|
MiddlewareMetadata,
|
|
8
|
+
PermissionMetadata,
|
|
8
9
|
} from '../../types/core.types.js'
|
|
9
10
|
import {
|
|
10
11
|
CorePikkuFunctionConfig,
|
|
@@ -78,6 +79,8 @@ export interface CLICommandMeta {
|
|
|
78
79
|
tags?: string[]
|
|
79
80
|
subcommands?: Record<string, CLICommandMeta>
|
|
80
81
|
middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
|
|
82
|
+
permissions?: PermissionMetadata[] // Pre-resolved permission chain (tag + explicit)
|
|
83
|
+
isDefault?: boolean
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
/**
|
|
@@ -90,10 +93,28 @@ export type CLIProgramMeta = {
|
|
|
90
93
|
defaultRenderName?: string
|
|
91
94
|
}
|
|
92
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Renderer metadata for CLI commands
|
|
98
|
+
*/
|
|
99
|
+
export interface RendererMeta {
|
|
100
|
+
name: string
|
|
101
|
+
exportedName?: string
|
|
102
|
+
services: {
|
|
103
|
+
optimized: boolean
|
|
104
|
+
services: string[]
|
|
105
|
+
}
|
|
106
|
+
filePath: string
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export type RenderersMeta = Record<string, RendererMeta>
|
|
110
|
+
|
|
93
111
|
/**
|
|
94
112
|
* All CLI programs metadata
|
|
95
113
|
*/
|
|
96
|
-
export
|
|
114
|
+
export interface CLIMeta {
|
|
115
|
+
programs: Record<string, CLIProgramMeta>
|
|
116
|
+
renderers: RenderersMeta
|
|
117
|
+
}
|
|
97
118
|
|
|
98
119
|
/**
|
|
99
120
|
* CLI-specific renderer that outputs to console
|
|
@@ -108,7 +129,7 @@ export type CorePikkuCLIRender<
|
|
|
108
129
|
* Extract input parameters from a Pikku function config type
|
|
109
130
|
*/
|
|
110
131
|
export type ExtractFunctionInput<Func> =
|
|
111
|
-
Func extends CorePikkuFunctionConfig<infer FuncType>
|
|
132
|
+
Func extends CorePikkuFunctionConfig<infer FuncType, any, any>
|
|
112
133
|
? FuncType extends
|
|
113
134
|
| CorePikkuFunction<infer Input, any, any, any, any>
|
|
114
135
|
| CorePikkuFunctionSessionless<infer Input, any, any, any, any>
|
|
@@ -135,30 +156,47 @@ type SplitBySpace<S extends string> = S extends `${infer First} ${infer Rest}`
|
|
|
135
156
|
: [S]
|
|
136
157
|
|
|
137
158
|
/**
|
|
138
|
-
*
|
|
159
|
+
* Recursively build a tuple by stripping brackets from each element
|
|
160
|
+
*/
|
|
161
|
+
type BuildParamsTuple<Parts extends readonly string[]> =
|
|
162
|
+
Parts extends readonly [
|
|
163
|
+
infer First extends string,
|
|
164
|
+
...infer Rest extends string[],
|
|
165
|
+
]
|
|
166
|
+
? [StripBrackets<First>, ...BuildParamsTuple<Rest>]
|
|
167
|
+
: []
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Extract parameter names from CLI parameter string into a tuple
|
|
139
171
|
* Example: "<env> [region]" => ["env", "region"]
|
|
140
172
|
*/
|
|
141
|
-
type ExtractParameterNames<S extends string> =
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
173
|
+
type ExtractParameterNames<S extends string> = BuildParamsTuple<SplitBySpace<S>>
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Check if all elements of a tuple are valid keys of Input
|
|
177
|
+
*/
|
|
178
|
+
type AllParamsValid<
|
|
179
|
+
Params extends readonly any[],
|
|
180
|
+
Input,
|
|
181
|
+
> = Params extends readonly [infer First, ...infer Rest]
|
|
182
|
+
? First extends keyof Input
|
|
183
|
+
? AllParamsValid<Rest, Input>
|
|
184
|
+
: false
|
|
185
|
+
: true
|
|
146
186
|
|
|
147
187
|
/**
|
|
148
188
|
* Validate that all parameter names are valid keys of the function input
|
|
149
189
|
*/
|
|
150
190
|
export type ValidateParameters<Params extends string, Input> =
|
|
151
|
-
ExtractParameterNames<Params> extends
|
|
152
|
-
?
|
|
153
|
-
? Params
|
|
154
|
-
: never
|
|
191
|
+
AllParamsValid<ExtractParameterNames<Params>, Input> extends true
|
|
192
|
+
? Params
|
|
155
193
|
: never
|
|
156
194
|
|
|
157
195
|
/**
|
|
158
196
|
* Extract output type from a Pikku function config type
|
|
159
197
|
*/
|
|
160
198
|
export type ExtractFunctionOutput<Func> =
|
|
161
|
-
Func extends CorePikkuFunctionConfig<infer FuncType>
|
|
199
|
+
Func extends CorePikkuFunctionConfig<infer FuncType, any, any>
|
|
162
200
|
? FuncType extends
|
|
163
201
|
| CorePikkuFunction<any, infer Output, any, any, any>
|
|
164
202
|
| CorePikkuFunctionSessionless<any, infer Output, any, any, any>
|
|
@@ -170,43 +208,34 @@ export type ExtractFunctionOutput<Func> =
|
|
|
170
208
|
* CLI command configuration that infers options from function input type.
|
|
171
209
|
* This is a helper type for creating type-safe CLI commands.
|
|
172
210
|
*/
|
|
173
|
-
export
|
|
174
|
-
|
|
211
|
+
export type CoreCLICommandConfig<
|
|
212
|
+
FuncConfig,
|
|
175
213
|
PikkuMiddleware extends CorePikkuMiddleware<any> = CorePikkuMiddleware<any>,
|
|
176
214
|
PikkuCLIRender extends CorePikkuCLIRender<any, any, any> = CorePikkuCLIRender<
|
|
177
215
|
any,
|
|
178
216
|
any
|
|
179
217
|
>,
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
218
|
+
Params extends string = string,
|
|
219
|
+
> = {
|
|
220
|
+
parameters?: ValidateParameters<Params, ExtractFunctionInput<FuncConfig>>
|
|
221
|
+
func?: FuncConfig
|
|
183
222
|
description?: string
|
|
184
223
|
render?: PikkuCLIRender
|
|
185
|
-
options?:
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
>
|
|
194
|
-
> &
|
|
195
|
-
Record<
|
|
196
|
-
string,
|
|
197
|
-
{
|
|
198
|
-
description?: string
|
|
199
|
-
short?: string
|
|
200
|
-
default?: any
|
|
201
|
-
}
|
|
202
|
-
>
|
|
224
|
+
options?: {
|
|
225
|
+
[K in keyof ExtractFunctionInput<FuncConfig>]?: {
|
|
226
|
+
description?: string
|
|
227
|
+
short?: string
|
|
228
|
+
default?: ExtractFunctionInput<FuncConfig>[K]
|
|
229
|
+
}
|
|
230
|
+
}
|
|
203
231
|
middleware?: PikkuMiddleware[]
|
|
204
232
|
subcommands?: Record<
|
|
205
233
|
string,
|
|
206
|
-
CoreCLICommandConfig<any, PikkuMiddleware, PikkuCLIRender>
|
|
234
|
+
CoreCLICommandConfig<any, PikkuMiddleware, PikkuCLIRender, any>
|
|
207
235
|
>
|
|
208
236
|
auth?: boolean
|
|
209
237
|
permissions?: any[]
|
|
238
|
+
isDefault?: boolean
|
|
210
239
|
}
|
|
211
240
|
|
|
212
241
|
/**
|
|
@@ -215,7 +244,7 @@ export interface CoreCLICommandConfig<
|
|
|
215
244
|
export interface CoreCLICommand<
|
|
216
245
|
In,
|
|
217
246
|
Out,
|
|
218
|
-
|
|
247
|
+
PikkuFunctionConfig extends CorePikkuFunctionConfig<
|
|
219
248
|
| CorePikkuFunction<In, Out, any, any, any>
|
|
220
249
|
| CorePikkuFunctionSessionless<In, Out, any, any, any>
|
|
221
250
|
>,
|
|
@@ -228,7 +257,7 @@ export interface CoreCLICommand<
|
|
|
228
257
|
> = Record<string, CoreCLICommandConfig<any, any, any>>,
|
|
229
258
|
> {
|
|
230
259
|
parameters?: string
|
|
231
|
-
func:
|
|
260
|
+
func: PikkuFunctionConfig
|
|
232
261
|
render?: CorePikkuCLIRender<Out>
|
|
233
262
|
description?: string
|
|
234
263
|
options?: CLIOptions<Options>
|
|
@@ -237,6 +266,7 @@ export interface CoreCLICommand<
|
|
|
237
266
|
auth?: boolean
|
|
238
267
|
docs?: PikkuDocs
|
|
239
268
|
subcommands?: Subcommands
|
|
269
|
+
isDefault?: boolean
|
|
240
270
|
}
|
|
241
271
|
|
|
242
272
|
/**
|
|
@@ -245,11 +275,11 @@ export interface CoreCLICommand<
|
|
|
245
275
|
export type CLICommandShorthand<
|
|
246
276
|
In,
|
|
247
277
|
Out,
|
|
248
|
-
|
|
278
|
+
PikkuFunctionConfig extends CorePikkuFunctionConfig<
|
|
249
279
|
| CorePikkuFunction<In, Out, any, any, any>
|
|
250
280
|
| CorePikkuFunctionSessionless<In, Out, any, any, any>
|
|
251
281
|
>,
|
|
252
|
-
> =
|
|
282
|
+
> = PikkuFunctionConfig
|
|
253
283
|
|
|
254
284
|
/**
|
|
255
285
|
* Command definition (either full or shorthand)
|
|
@@ -257,7 +287,7 @@ export type CLICommandShorthand<
|
|
|
257
287
|
export type CLICommandDefinition<
|
|
258
288
|
In,
|
|
259
289
|
Out,
|
|
260
|
-
|
|
290
|
+
PikkuFunctionConfig extends CorePikkuFunctionConfig<
|
|
261
291
|
| CorePikkuFunction<In, Out, any, any, any>
|
|
262
292
|
| CorePikkuFunctionSessionless<In, Out, any, any, any>
|
|
263
293
|
>,
|
|
@@ -272,13 +302,13 @@ export type CLICommandDefinition<
|
|
|
272
302
|
| CoreCLICommand<
|
|
273
303
|
In,
|
|
274
304
|
Out,
|
|
275
|
-
|
|
305
|
+
PikkuFunctionConfig,
|
|
276
306
|
PikkuPermission,
|
|
277
307
|
PikkuMiddleware,
|
|
278
308
|
Options,
|
|
279
309
|
Subcommands
|
|
280
310
|
>
|
|
281
|
-
| CLICommandShorthand<In, Out,
|
|
311
|
+
| CLICommandShorthand<In, Out, PikkuFunctionConfig>
|
|
282
312
|
|
|
283
313
|
/**
|
|
284
314
|
* CLI wiring configuration
|
|
@@ -4,78 +4,80 @@ import { parseCLIArguments, generateCommandHelp } from './command-parser.js'
|
|
|
4
4
|
import { CLIMeta } from './cli.types.js'
|
|
5
5
|
|
|
6
6
|
const testMeta: CLIMeta = {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
programs: {
|
|
8
|
+
'test-cli': {
|
|
9
|
+
program: 'test-cli',
|
|
10
|
+
options: {
|
|
11
|
+
verbose: {
|
|
12
|
+
description: 'Enable verbose output',
|
|
13
|
+
short: 'v',
|
|
14
|
+
default: false,
|
|
15
|
+
},
|
|
14
16
|
},
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
commands: {
|
|
18
|
+
greet: {
|
|
19
|
+
parameters: '<name>',
|
|
20
|
+
pikkuFuncName: 'greetFunc',
|
|
21
|
+
positionals: [{ name: 'name', required: true }],
|
|
22
|
+
options: {
|
|
23
|
+
loud: {
|
|
24
|
+
description: 'Use loud greeting',
|
|
25
|
+
short: 'l',
|
|
26
|
+
default: false,
|
|
27
|
+
},
|
|
26
28
|
},
|
|
27
29
|
},
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
choices: ['admin', 'user', 'guest'],
|
|
30
|
+
user: {
|
|
31
|
+
pikkuFuncName: '',
|
|
32
|
+
positionals: [],
|
|
33
|
+
options: {},
|
|
34
|
+
subcommands: {
|
|
35
|
+
create: {
|
|
36
|
+
parameters: '<name> <email>',
|
|
37
|
+
pikkuFuncName: 'createUserFunc',
|
|
38
|
+
positionals: [
|
|
39
|
+
{ name: 'name', required: true },
|
|
40
|
+
{ name: 'email', required: true },
|
|
41
|
+
],
|
|
42
|
+
options: {
|
|
43
|
+
role: {
|
|
44
|
+
description: 'User role',
|
|
45
|
+
short: 'r',
|
|
46
|
+
default: 'user',
|
|
47
|
+
choices: ['admin', 'user', 'guest'],
|
|
48
|
+
},
|
|
48
49
|
},
|
|
49
50
|
},
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
delete: {
|
|
52
|
+
parameters: '<id>',
|
|
53
|
+
pikkuFuncName: 'deleteUserFunc',
|
|
54
|
+
positionals: [{ name: 'id', required: true }],
|
|
55
|
+
options: {
|
|
56
|
+
force: {
|
|
57
|
+
description: 'Force delete',
|
|
58
|
+
short: 'f',
|
|
59
|
+
default: false,
|
|
60
|
+
},
|
|
60
61
|
},
|
|
61
62
|
},
|
|
62
63
|
},
|
|
63
64
|
},
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
65
|
+
files: {
|
|
66
|
+
parameters: '<paths...>',
|
|
67
|
+
pikkuFuncName: 'filesFunc',
|
|
68
|
+
positionals: [{ name: 'paths', required: true, variadic: true }],
|
|
69
|
+
options: {},
|
|
70
|
+
},
|
|
71
|
+
optional: {
|
|
72
|
+
parameters: '[name]',
|
|
73
|
+
pikkuFuncName: 'optionalFunc',
|
|
74
|
+
positionals: [{ name: 'name', required: false }],
|
|
75
|
+
options: {},
|
|
76
|
+
},
|
|
76
77
|
},
|
|
77
78
|
},
|
|
78
79
|
},
|
|
80
|
+
renderers: {},
|
|
79
81
|
}
|
|
80
82
|
|
|
81
83
|
describe('Command Parser', () => {
|
|
@@ -291,23 +293,25 @@ describe('Command Parser', () => {
|
|
|
291
293
|
|
|
292
294
|
test('should parse number values correctly', () => {
|
|
293
295
|
const metaWithNumber: CLIMeta = {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
296
|
+
programs: {
|
|
297
|
+
'num-cli': {
|
|
298
|
+
program: 'num-cli',
|
|
299
|
+
options: {},
|
|
300
|
+
commands: {
|
|
301
|
+
test: {
|
|
302
|
+
pikkuFuncName: 'testFunc',
|
|
303
|
+
positionals: [],
|
|
304
|
+
options: {
|
|
305
|
+
port: {
|
|
306
|
+
description: 'Port number',
|
|
307
|
+
default: 3000,
|
|
308
|
+
},
|
|
306
309
|
},
|
|
307
310
|
},
|
|
308
311
|
},
|
|
309
312
|
},
|
|
310
313
|
},
|
|
314
|
+
renderers: {},
|
|
311
315
|
}
|
|
312
316
|
|
|
313
317
|
const result = parseCLIArguments(
|
|
@@ -349,8 +353,7 @@ describe('Command Parser', () => {
|
|
|
349
353
|
assert.ok(help.includes('--verbose'))
|
|
350
354
|
})
|
|
351
355
|
|
|
352
|
-
|
|
353
|
-
test.skip('should generate help for specific command', () => {
|
|
356
|
+
test('should generate help for specific command', () => {
|
|
354
357
|
const help = generateCommandHelp('test-cli', testMeta, ['greet'])
|
|
355
358
|
|
|
356
359
|
assert.ok(help.includes('Usage: test-cli greet'))
|
|
@@ -359,8 +362,7 @@ describe('Command Parser', () => {
|
|
|
359
362
|
assert.ok(help.includes('Use loud greeting'))
|
|
360
363
|
})
|
|
361
364
|
|
|
362
|
-
|
|
363
|
-
test.skip('should generate help for subcommand', () => {
|
|
365
|
+
test('should generate help for subcommand', () => {
|
|
364
366
|
const help = generateCommandHelp('test-cli', testMeta, ['user', 'create'])
|
|
365
367
|
|
|
366
368
|
assert.ok(help.includes('Usage: test-cli user create'))
|
|
@@ -371,19 +373,22 @@ describe('Command Parser', () => {
|
|
|
371
373
|
|
|
372
374
|
test('should show command description if available', () => {
|
|
373
375
|
const metaWithDesc: CLIMeta = {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
376
|
+
programs: {
|
|
377
|
+
'test-cli': {
|
|
378
|
+
program: 'test-cli',
|
|
379
|
+
options: {},
|
|
380
|
+
commands: {
|
|
381
|
+
greet: {
|
|
382
|
+
parameters: '<name>',
|
|
383
|
+
pikkuFuncName: 'greetFunc',
|
|
384
|
+
description: 'Greet a user',
|
|
385
|
+
positionals: [{ name: 'name', required: true }],
|
|
386
|
+
options: {},
|
|
387
|
+
},
|
|
384
388
|
},
|
|
385
389
|
},
|
|
386
390
|
},
|
|
391
|
+
renderers: {},
|
|
387
392
|
}
|
|
388
393
|
|
|
389
394
|
const help = generateCommandHelp('test-cli', metaWithDesc, ['greet'])
|