effect-start 0.14.0 → 0.16.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/package.json +8 -9
- package/src/Commander.test.ts +507 -245
- package/src/ContentNegotiation.test.ts +603 -0
- package/src/ContentNegotiation.ts +542 -0
- package/src/Entity.test.ts +592 -0
- package/src/Entity.ts +362 -0
- package/src/FileRouter.ts +16 -12
- package/src/{FileRouterCodegen.test.ts → FileRouterCodegen.todo.ts} +384 -219
- package/src/FileRouterCodegen.ts +6 -6
- package/src/FileRouterPattern.test.ts +93 -62
- package/src/FileRouter_files.test.ts +5 -5
- package/src/FileRouter_path.test.ts +121 -69
- package/src/FileRouter_tree.test.ts +62 -56
- package/src/FileSystemExtra.test.ts +46 -30
- package/src/Http.test.ts +319 -0
- package/src/Http.ts +167 -0
- package/src/HttpAppExtra.test.ts +39 -20
- package/src/HttpAppExtra.ts +0 -1
- package/src/HttpUtils.test.ts +35 -18
- package/src/HttpUtils.ts +2 -0
- package/src/PathPattern.test.ts +648 -0
- package/src/PathPattern.ts +485 -0
- package/src/Route.ts +266 -1069
- package/src/RouteBody.test.ts +234 -0
- package/src/RouteBody.ts +193 -0
- package/src/RouteHook.test.ts +40 -0
- package/src/RouteHook.ts +106 -0
- package/src/RouteHttp.test.ts +2906 -0
- package/src/RouteHttp.ts +427 -0
- package/src/RouteHttpTracer.ts +92 -0
- package/src/RouteMount.test.ts +481 -0
- package/src/RouteMount.ts +470 -0
- package/src/RouteSchema.test.ts +427 -0
- package/src/RouteSchema.ts +423 -0
- package/src/RouteTree.test.ts +494 -0
- package/src/RouteTree.ts +219 -0
- package/src/RouteTrie.test.ts +322 -0
- package/src/RouteTrie.ts +224 -0
- package/src/RouterPattern.test.ts +569 -548
- package/src/RouterPattern.ts +7 -7
- package/src/Start.ts +3 -3
- package/src/StreamExtra.ts +21 -1
- package/src/TuplePathPattern.ts +64 -0
- package/src/Values.test.ts +263 -0
- package/src/Values.ts +76 -0
- package/src/bun/BunBundle.test.ts +36 -42
- package/src/bun/BunBundle.ts +2 -2
- package/src/bun/BunBundle_imports.test.ts +4 -6
- package/src/bun/BunHttpServer.test.ts +183 -6
- package/src/bun/BunHttpServer.ts +72 -32
- package/src/bun/BunHttpServer_web.ts +18 -6
- package/src/bun/BunImportTrackerPlugin.test.ts +3 -3
- package/src/bun/BunRoute.test.ts +124 -442
- package/src/bun/BunRoute.ts +146 -286
- package/src/{BundleHttp.test.ts → bundler/BundleHttp.test.ts} +34 -60
- package/src/{BundleHttp.ts → bundler/BundleHttp.ts} +1 -2
- package/src/client/index.ts +1 -1
- package/src/{Effect_HttpRouter.test.ts → effect/HttpRouter.test.ts} +69 -90
- package/src/experimental/EncryptedCookies.test.ts +125 -64
- package/src/experimental/SseHttpResponse.ts +0 -1
- package/src/hyper/Hyper.ts +89 -0
- package/src/{HyperHtml.test.ts → hyper/HyperHtml.test.ts} +13 -13
- package/src/{HyperHtml.ts → hyper/HyperHtml.ts} +2 -2
- package/src/{jsx.d.ts → hyper/jsx.d.ts} +1 -1
- package/src/index.ts +3 -4
- package/src/middlewares/BasicAuthMiddleware.test.ts +29 -19
- package/src/{NodeFileSystem.ts → node/FileSystem.ts} +6 -2
- package/src/testing/TestHttpClient.test.ts +26 -26
- package/src/testing/TestLogger.test.ts +27 -14
- package/src/testing/TestLogger.ts +15 -9
- package/src/x/datastar/Datastar.test.ts +47 -48
- package/src/x/datastar/Datastar.ts +1 -1
- package/src/x/tailwind/TailwindPlugin.test.ts +56 -58
- package/src/x/tailwind/plugin.ts +1 -1
- package/src/FileHttpRouter.test.ts +0 -239
- package/src/FileHttpRouter.ts +0 -194
- package/src/Hyper.ts +0 -194
- package/src/Route.test.ts +0 -1370
- package/src/RouteRender.ts +0 -40
- package/src/Router.test.ts +0 -375
- package/src/Router.ts +0 -255
- package/src/bun/BunRoute_bundles.test.ts +0 -219
- /package/src/{Bundle.ts → bundler/Bundle.ts} +0 -0
- /package/src/{BundleFiles.ts → bundler/BundleFiles.ts} +0 -0
- /package/src/{HyperNode.ts → hyper/HyperNode.ts} +0 -0
- /package/src/{jsx-runtime.ts → hyper/jsx-runtime.ts} +0 -0
- /package/src/{NodeUtils.ts → node/Utils.ts} +0 -0
package/src/Commander.test.ts
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as test from "bun:test"
|
|
2
2
|
import * as Effect from "effect/Effect"
|
|
3
3
|
import * as Schema from "effect/Schema"
|
|
4
4
|
import * as assert from "node:assert"
|
|
5
5
|
import * as Commander from "./Commander.ts"
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
test.describe(`${Commander.make.name}`, () => {
|
|
8
|
+
test.it("should create a basic command", () => {
|
|
9
9
|
const cmd = Commander.make({
|
|
10
10
|
name: "test-app",
|
|
11
11
|
description: "A test application",
|
|
12
12
|
})
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
test
|
|
14
|
+
.expect(cmd.name)
|
|
15
|
+
.toBe("test-app")
|
|
16
|
+
test
|
|
17
|
+
.expect(cmd.description)
|
|
18
|
+
.toBe("A test application")
|
|
15
19
|
})
|
|
16
20
|
})
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
test.describe(`${Commander.option.name} - nested builder API`, () => {
|
|
23
|
+
test.it("should add an option with schema", () => {
|
|
20
24
|
const cmd = Commander
|
|
21
25
|
.make({ name: "app" })
|
|
22
26
|
.option(
|
|
@@ -25,12 +29,18 @@ t.describe(`${Commander.option.name} - nested builder API`, () => {
|
|
|
25
29
|
.schema(Schema.String),
|
|
26
30
|
)
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
test
|
|
33
|
+
.expect(cmd.options.output)
|
|
34
|
+
.toBeDefined()
|
|
35
|
+
test
|
|
36
|
+
.expect(cmd.options.output.long)
|
|
37
|
+
.toBe("--output")
|
|
38
|
+
test
|
|
39
|
+
.expect(cmd.options.output.short)
|
|
40
|
+
.toBe("o")
|
|
31
41
|
})
|
|
32
42
|
|
|
33
|
-
|
|
43
|
+
test.it("should add option with description", () => {
|
|
34
44
|
const cmd = Commander
|
|
35
45
|
.make({ name: "app" })
|
|
36
46
|
.option(
|
|
@@ -40,10 +50,12 @@ t.describe(`${Commander.option.name} - nested builder API`, () => {
|
|
|
40
50
|
.schema(Schema.String),
|
|
41
51
|
)
|
|
42
52
|
|
|
43
|
-
|
|
53
|
+
test
|
|
54
|
+
.expect(cmd.options.output.description)
|
|
55
|
+
.toBe("Output file")
|
|
44
56
|
})
|
|
45
57
|
|
|
46
|
-
|
|
58
|
+
test.it("should add option with default value", () => {
|
|
47
59
|
const cmd = Commander
|
|
48
60
|
.make({ name: "app" })
|
|
49
61
|
.option(
|
|
@@ -53,10 +65,12 @@ t.describe(`${Commander.option.name} - nested builder API`, () => {
|
|
|
53
65
|
.schema(Commander.NumberFromString),
|
|
54
66
|
)
|
|
55
67
|
|
|
56
|
-
|
|
68
|
+
test
|
|
69
|
+
.expect(cmd.options.count.defaultValue)
|
|
70
|
+
.toBe(10)
|
|
57
71
|
})
|
|
58
72
|
|
|
59
|
-
|
|
73
|
+
test.it("should chain multiple options", () => {
|
|
60
74
|
const cmd = Commander
|
|
61
75
|
.make({ name: "app" })
|
|
62
76
|
.option(
|
|
@@ -70,15 +84,23 @@ t.describe(`${Commander.option.name} - nested builder API`, () => {
|
|
|
70
84
|
.schema(Schema.String),
|
|
71
85
|
)
|
|
72
86
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
87
|
+
test
|
|
88
|
+
.expect(cmd.options.input)
|
|
89
|
+
.toBeDefined()
|
|
90
|
+
test
|
|
91
|
+
.expect(cmd.options.output)
|
|
92
|
+
.toBeDefined()
|
|
93
|
+
test
|
|
94
|
+
.expect(cmd.options.input.long)
|
|
95
|
+
.toBe("--input")
|
|
96
|
+
test
|
|
97
|
+
.expect(cmd.options.output.long)
|
|
98
|
+
.toBe("--output")
|
|
77
99
|
})
|
|
78
100
|
})
|
|
79
101
|
|
|
80
|
-
|
|
81
|
-
|
|
102
|
+
test.describe(`${Commander.parse.name} - kebab-to-camel conversion`, () => {
|
|
103
|
+
test.it("should convert kebab-case to camelCase", async () => {
|
|
82
104
|
const cmd = Commander
|
|
83
105
|
.make({ name: "app" })
|
|
84
106
|
.option(
|
|
@@ -91,10 +113,12 @@ t.describe(`${Commander.parse.name} - kebab-to-camel conversion`, () => {
|
|
|
91
113
|
Commander.parse(cmd, ["--input-file", "test.txt"]),
|
|
92
114
|
)
|
|
93
115
|
|
|
94
|
-
|
|
116
|
+
test
|
|
117
|
+
.expect(result.inputFile)
|
|
118
|
+
.toBe("test.txt")
|
|
95
119
|
})
|
|
96
120
|
|
|
97
|
-
|
|
121
|
+
test.it("should handle single word options", async () => {
|
|
98
122
|
const cmd = Commander
|
|
99
123
|
.make({ name: "app" })
|
|
100
124
|
.option(
|
|
@@ -107,10 +131,12 @@ t.describe(`${Commander.parse.name} - kebab-to-camel conversion`, () => {
|
|
|
107
131
|
Commander.parse(cmd, ["--port", "3000"]),
|
|
108
132
|
)
|
|
109
133
|
|
|
110
|
-
|
|
134
|
+
test
|
|
135
|
+
.expect(result.port)
|
|
136
|
+
.toBe(3000)
|
|
111
137
|
})
|
|
112
138
|
|
|
113
|
-
|
|
139
|
+
test.it("should parse short options", async () => {
|
|
114
140
|
const cmd = Commander
|
|
115
141
|
.make({ name: "app" })
|
|
116
142
|
.option(
|
|
@@ -123,10 +149,12 @@ t.describe(`${Commander.parse.name} - kebab-to-camel conversion`, () => {
|
|
|
123
149
|
Commander.parse(cmd, ["-p", "8080"]),
|
|
124
150
|
)
|
|
125
151
|
|
|
126
|
-
|
|
152
|
+
test
|
|
153
|
+
.expect(result.port)
|
|
154
|
+
.toBe(8080)
|
|
127
155
|
})
|
|
128
156
|
|
|
129
|
-
|
|
157
|
+
test.it("should parse multiple options", async () => {
|
|
130
158
|
const cmd = Commander
|
|
131
159
|
.make({ name: "app" })
|
|
132
160
|
.option(
|
|
@@ -144,11 +172,15 @@ t.describe(`${Commander.parse.name} - kebab-to-camel conversion`, () => {
|
|
|
144
172
|
Commander.parse(cmd, ["--host", "localhost", "--port", "3000"]),
|
|
145
173
|
)
|
|
146
174
|
|
|
147
|
-
|
|
148
|
-
|
|
175
|
+
test
|
|
176
|
+
.expect(result.host)
|
|
177
|
+
.toBe("localhost")
|
|
178
|
+
test
|
|
179
|
+
.expect(result.port)
|
|
180
|
+
.toBe(3000)
|
|
149
181
|
})
|
|
150
182
|
|
|
151
|
-
|
|
183
|
+
test.it("should handle options with equals syntax", async () => {
|
|
152
184
|
const cmd = Commander
|
|
153
185
|
.make({ name: "app" })
|
|
154
186
|
.option(
|
|
@@ -161,10 +193,12 @@ t.describe(`${Commander.parse.name} - kebab-to-camel conversion`, () => {
|
|
|
161
193
|
Commander.parse(cmd, ["--port=3000"]),
|
|
162
194
|
)
|
|
163
195
|
|
|
164
|
-
|
|
196
|
+
test
|
|
197
|
+
.expect(result.port)
|
|
198
|
+
.toBe(3000)
|
|
165
199
|
})
|
|
166
200
|
|
|
167
|
-
|
|
201
|
+
test.it("should use default value when option not provided", async () => {
|
|
168
202
|
const cmd = Commander
|
|
169
203
|
.make({ name: "app" })
|
|
170
204
|
.option(
|
|
@@ -178,10 +212,12 @@ t.describe(`${Commander.parse.name} - kebab-to-camel conversion`, () => {
|
|
|
178
212
|
Commander.parse(cmd, []),
|
|
179
213
|
)
|
|
180
214
|
|
|
181
|
-
|
|
215
|
+
test
|
|
216
|
+
.expect(result.port)
|
|
217
|
+
.toBe(3000)
|
|
182
218
|
})
|
|
183
219
|
|
|
184
|
-
|
|
220
|
+
test.it("should override default when option specified", async () => {
|
|
185
221
|
const cmd = Commander
|
|
186
222
|
.make({ name: "app" })
|
|
187
223
|
.option(
|
|
@@ -195,36 +231,50 @@ t.describe(`${Commander.parse.name} - kebab-to-camel conversion`, () => {
|
|
|
195
231
|
Commander.parse(cmd, ["--port", "8080"]),
|
|
196
232
|
)
|
|
197
233
|
|
|
198
|
-
|
|
234
|
+
test
|
|
235
|
+
.expect(result.port)
|
|
236
|
+
.toBe(8080)
|
|
199
237
|
})
|
|
200
238
|
})
|
|
201
239
|
|
|
202
|
-
|
|
203
|
-
|
|
240
|
+
test.describe(`${Commander.optionHelp.name}`, () => {
|
|
241
|
+
test.it("should add help option", () => {
|
|
204
242
|
const cmd = Commander
|
|
205
243
|
.make({ name: "app" })
|
|
206
244
|
.optionHelp()
|
|
207
245
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
246
|
+
test
|
|
247
|
+
.expect(cmd.options.help)
|
|
248
|
+
.toBeDefined()
|
|
249
|
+
test
|
|
250
|
+
.expect(cmd.options.help.long)
|
|
251
|
+
.toBe("--help")
|
|
252
|
+
test
|
|
253
|
+
.expect(cmd.options.help.short)
|
|
254
|
+
.toBe("h")
|
|
211
255
|
})
|
|
212
256
|
})
|
|
213
257
|
|
|
214
|
-
|
|
215
|
-
|
|
258
|
+
test.describe(`${Commander.optionVersion.name}`, () => {
|
|
259
|
+
test.it("should add version option", () => {
|
|
216
260
|
const cmd = Commander
|
|
217
261
|
.make({ name: "app", version: "1.0.0" })
|
|
218
262
|
.optionVersion()
|
|
219
263
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
264
|
+
test
|
|
265
|
+
.expect(cmd.options.version)
|
|
266
|
+
.toBeDefined()
|
|
267
|
+
test
|
|
268
|
+
.expect(cmd.options.version.long)
|
|
269
|
+
.toBe("--version")
|
|
270
|
+
test
|
|
271
|
+
.expect(cmd.options.version.short)
|
|
272
|
+
.toBe("V")
|
|
223
273
|
})
|
|
224
274
|
})
|
|
225
275
|
|
|
226
|
-
|
|
227
|
-
|
|
276
|
+
test.describe(`${Commander.handle.name}`, () => {
|
|
277
|
+
test.it("should mark command as handled", () => {
|
|
228
278
|
const handled = Commander
|
|
229
279
|
.make({ name: "app" })
|
|
230
280
|
.option(
|
|
@@ -242,13 +292,17 @@ t.describe(`${Commander.handle.name}`, () => {
|
|
|
242
292
|
.schema(Schema.String),
|
|
243
293
|
)
|
|
244
294
|
|
|
245
|
-
|
|
246
|
-
|
|
295
|
+
test
|
|
296
|
+
.expect(handled.handler)
|
|
297
|
+
.toBeDefined()
|
|
298
|
+
test
|
|
299
|
+
.expect(unhandled.handler)
|
|
300
|
+
.toBeUndefined()
|
|
247
301
|
})
|
|
248
302
|
})
|
|
249
303
|
|
|
250
|
-
|
|
251
|
-
|
|
304
|
+
test.describe(`${Commander.subcommand.name}`, () => {
|
|
305
|
+
test.it("should add subcommand", () => {
|
|
252
306
|
const subCmd = Commander
|
|
253
307
|
.make({ name: "format" })
|
|
254
308
|
.option(
|
|
@@ -262,13 +316,17 @@ t.describe(`${Commander.subcommand.name}`, () => {
|
|
|
262
316
|
.make({ name: "main" })
|
|
263
317
|
.subcommand(subCmd)
|
|
264
318
|
|
|
265
|
-
|
|
266
|
-
|
|
319
|
+
test
|
|
320
|
+
.expect(main.subcommands.length)
|
|
321
|
+
.toBe(1)
|
|
322
|
+
test
|
|
323
|
+
.expect(main.subcommands[0]!.command.name)
|
|
324
|
+
.toBe("format")
|
|
267
325
|
})
|
|
268
326
|
})
|
|
269
327
|
|
|
270
|
-
|
|
271
|
-
|
|
328
|
+
test.describe(`${Commander.help.name}`, () => {
|
|
329
|
+
test.it("should generate help text", () => {
|
|
272
330
|
const cmd = Commander
|
|
273
331
|
.make({
|
|
274
332
|
name: "myapp",
|
|
@@ -285,33 +343,49 @@ t.describe(`${Commander.help.name}`, () => {
|
|
|
285
343
|
|
|
286
344
|
const helpText = Commander.help(cmd)
|
|
287
345
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
346
|
+
test
|
|
347
|
+
.expect(helpText)
|
|
348
|
+
.toContain("My awesome application")
|
|
349
|
+
test
|
|
350
|
+
.expect(helpText)
|
|
351
|
+
.toContain("Usage: myapp [options]")
|
|
352
|
+
test
|
|
353
|
+
.expect(helpText)
|
|
354
|
+
.toContain("--output")
|
|
355
|
+
test
|
|
356
|
+
.expect(helpText)
|
|
357
|
+
.toContain("-o,")
|
|
358
|
+
test
|
|
359
|
+
.expect(helpText)
|
|
360
|
+
.toContain("Output file")
|
|
361
|
+
test
|
|
362
|
+
.expect(helpText)
|
|
363
|
+
.toContain("--help")
|
|
294
364
|
})
|
|
295
365
|
})
|
|
296
366
|
|
|
297
|
-
|
|
298
|
-
|
|
367
|
+
test.describe("BooleanFromString", () => {
|
|
368
|
+
test.it("should decode true value", async () => {
|
|
299
369
|
const result = await Effect.runPromise(
|
|
300
370
|
Schema.decode(Schema.BooleanFromString)("true"),
|
|
301
371
|
)
|
|
302
|
-
|
|
372
|
+
test
|
|
373
|
+
.expect(result)
|
|
374
|
+
.toBe(true)
|
|
303
375
|
})
|
|
304
376
|
|
|
305
|
-
|
|
377
|
+
test.it("should decode false value", async () => {
|
|
306
378
|
const result = await Effect.runPromise(
|
|
307
379
|
Schema.decode(Schema.BooleanFromString)("false"),
|
|
308
380
|
)
|
|
309
|
-
|
|
381
|
+
test
|
|
382
|
+
.expect(result)
|
|
383
|
+
.toBe(false)
|
|
310
384
|
})
|
|
311
385
|
})
|
|
312
386
|
|
|
313
|
-
|
|
314
|
-
|
|
387
|
+
test.describe(`${Commander.choice.name}`, () => {
|
|
388
|
+
test.it("should accept valid choice", async () => {
|
|
315
389
|
const ColorSchema = Schema.compose(
|
|
316
390
|
Schema.String,
|
|
317
391
|
Schema.Literal("red", "green", "blue"),
|
|
@@ -321,10 +395,12 @@ t.describe(`${Commander.choice.name}`, () => {
|
|
|
321
395
|
Schema.decode(ColorSchema)("red"),
|
|
322
396
|
)
|
|
323
397
|
|
|
324
|
-
|
|
398
|
+
test
|
|
399
|
+
.expect(result)
|
|
400
|
+
.toBe("red")
|
|
325
401
|
})
|
|
326
402
|
|
|
327
|
-
|
|
403
|
+
test.it("should fail on invalid choice", async () => {
|
|
328
404
|
const ColorSchema = Schema.compose(
|
|
329
405
|
Schema.String,
|
|
330
406
|
Schema.Literal("red", "green", "blue"),
|
|
@@ -334,54 +410,64 @@ t.describe(`${Commander.choice.name}`, () => {
|
|
|
334
410
|
Effect.either(Schema.decode(ColorSchema)("yellow")),
|
|
335
411
|
)
|
|
336
412
|
|
|
337
|
-
|
|
413
|
+
test
|
|
414
|
+
.expect(result._tag)
|
|
415
|
+
.toBe("Left")
|
|
338
416
|
})
|
|
339
417
|
})
|
|
340
418
|
|
|
341
|
-
|
|
342
|
-
|
|
419
|
+
test.describe(`${Commander.repeatable.name}`, () => {
|
|
420
|
+
test.it("should parse comma-separated values", async () => {
|
|
343
421
|
const schema = Commander.repeatable(Schema.String)
|
|
344
422
|
|
|
345
423
|
const result = await Effect.runPromise(
|
|
346
424
|
Schema.decode(schema)("foo,bar,baz"),
|
|
347
425
|
)
|
|
348
426
|
|
|
349
|
-
|
|
427
|
+
test
|
|
428
|
+
.expect(result)
|
|
429
|
+
.toEqual(["foo", "bar", "baz"])
|
|
350
430
|
})
|
|
351
431
|
|
|
352
|
-
|
|
432
|
+
test.it("should parse comma-separated numbers", async () => {
|
|
353
433
|
const schema = Commander.repeatable(Commander.NumberFromString)
|
|
354
434
|
|
|
355
435
|
const result = await Effect.runPromise(
|
|
356
436
|
Schema.decode(schema)("1,2,3,4,5"),
|
|
357
437
|
)
|
|
358
438
|
|
|
359
|
-
|
|
439
|
+
test
|
|
440
|
+
.expect(result)
|
|
441
|
+
.toEqual([1, 2, 3, 4, 5])
|
|
360
442
|
})
|
|
361
443
|
|
|
362
|
-
|
|
444
|
+
test.it("should trim whitespace", async () => {
|
|
363
445
|
const schema = Commander.repeatable(Schema.String)
|
|
364
446
|
|
|
365
447
|
const result = await Effect.runPromise(
|
|
366
448
|
Schema.decode(schema)("foo, bar , baz"),
|
|
367
449
|
)
|
|
368
450
|
|
|
369
|
-
|
|
451
|
+
test
|
|
452
|
+
.expect(result)
|
|
453
|
+
.toEqual(["foo", "bar", "baz"])
|
|
370
454
|
})
|
|
371
455
|
|
|
372
|
-
|
|
456
|
+
test.it("should encode back to string", async () => {
|
|
373
457
|
const schema = Commander.repeatable(Schema.String)
|
|
374
458
|
|
|
375
459
|
const result = await Effect.runPromise(
|
|
376
460
|
Schema.encode(schema)(["foo", "bar", "baz"]),
|
|
377
461
|
)
|
|
378
462
|
|
|
379
|
-
|
|
463
|
+
test
|
|
464
|
+
.expect(result)
|
|
465
|
+
.toBe("foo,bar,baz")
|
|
380
466
|
})
|
|
381
467
|
})
|
|
382
468
|
|
|
383
|
-
|
|
384
|
-
|
|
469
|
+
test.describe("integration", () => {
|
|
470
|
+
test.it("should work with builder pattern", async () => {
|
|
385
471
|
const cmd = Commander
|
|
386
472
|
.make({
|
|
387
473
|
name: "converter",
|
|
@@ -423,13 +509,21 @@ t.describe("integration", () => {
|
|
|
423
509
|
]),
|
|
424
510
|
)
|
|
425
511
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
512
|
+
test
|
|
513
|
+
.expect(result.input)
|
|
514
|
+
.toBe("input.txt")
|
|
515
|
+
test
|
|
516
|
+
.expect(result.output)
|
|
517
|
+
.toBe("output.txt")
|
|
518
|
+
test
|
|
519
|
+
.expect(result.format)
|
|
520
|
+
.toBe("yaml")
|
|
521
|
+
test
|
|
522
|
+
.expect(result.help)
|
|
523
|
+
.toBe(false)
|
|
524
|
+
})
|
|
525
|
+
|
|
526
|
+
test.it("should handle kebab-case option names", async () => {
|
|
433
527
|
const cmd = Commander
|
|
434
528
|
.make({ name: "app" })
|
|
435
529
|
.option(
|
|
@@ -448,13 +542,17 @@ t.describe("integration", () => {
|
|
|
448
542
|
Commander.parse(cmd, ["--dry-run", "true", "--cache-dir", "/tmp/cache"]),
|
|
449
543
|
)
|
|
450
544
|
|
|
451
|
-
|
|
452
|
-
|
|
545
|
+
test
|
|
546
|
+
.expect(result.dryRun)
|
|
547
|
+
.toBe(true)
|
|
548
|
+
test
|
|
549
|
+
.expect(result.cacheDir)
|
|
550
|
+
.toBe("/tmp/cache")
|
|
453
551
|
})
|
|
454
552
|
})
|
|
455
553
|
|
|
456
|
-
|
|
457
|
-
|
|
554
|
+
test.describe(`${Commander.parse.name} - comprehensive`, () => {
|
|
555
|
+
test.it("should parse with explicit args", async () => {
|
|
458
556
|
const cmd = Commander
|
|
459
557
|
.make({ name: "app" })
|
|
460
558
|
.option(
|
|
@@ -467,10 +565,12 @@ t.describe(`${Commander.parse.name} - comprehensive`, () => {
|
|
|
467
565
|
Commander.parse(cmd, ["--port", "3000"]),
|
|
468
566
|
)
|
|
469
567
|
|
|
470
|
-
|
|
568
|
+
test
|
|
569
|
+
.expect(result.port)
|
|
570
|
+
.toBe(3000)
|
|
471
571
|
})
|
|
472
572
|
|
|
473
|
-
|
|
573
|
+
test.it("should parse short options", async () => {
|
|
474
574
|
const cmd = Commander
|
|
475
575
|
.make({ name: "app" })
|
|
476
576
|
.option(
|
|
@@ -483,10 +583,12 @@ t.describe(`${Commander.parse.name} - comprehensive`, () => {
|
|
|
483
583
|
Commander.parse(cmd, ["-p", "8080"]),
|
|
484
584
|
)
|
|
485
585
|
|
|
486
|
-
|
|
586
|
+
test
|
|
587
|
+
.expect(result.port)
|
|
588
|
+
.toBe(8080)
|
|
487
589
|
})
|
|
488
590
|
|
|
489
|
-
|
|
591
|
+
test.it("should parse multiple options", async () => {
|
|
490
592
|
const cmd = Commander
|
|
491
593
|
.make({ name: "app" })
|
|
492
594
|
.option(
|
|
@@ -504,11 +606,15 @@ t.describe(`${Commander.parse.name} - comprehensive`, () => {
|
|
|
504
606
|
Commander.parse(cmd, ["--host", "localhost", "--port", "3000"]),
|
|
505
607
|
)
|
|
506
608
|
|
|
507
|
-
|
|
508
|
-
|
|
609
|
+
test
|
|
610
|
+
.expect(result.host)
|
|
611
|
+
.toBe("localhost")
|
|
612
|
+
test
|
|
613
|
+
.expect(result.port)
|
|
614
|
+
.toBe(3000)
|
|
509
615
|
})
|
|
510
616
|
|
|
511
|
-
|
|
617
|
+
test.it("should handle options with equals syntax", async () => {
|
|
512
618
|
const cmd = Commander
|
|
513
619
|
.make({ name: "app" })
|
|
514
620
|
.option(
|
|
@@ -521,10 +627,12 @@ t.describe(`${Commander.parse.name} - comprehensive`, () => {
|
|
|
521
627
|
Commander.parse(cmd, ["--port=3000"]),
|
|
522
628
|
)
|
|
523
629
|
|
|
524
|
-
|
|
630
|
+
test
|
|
631
|
+
.expect(result.port)
|
|
632
|
+
.toBe(3000)
|
|
525
633
|
})
|
|
526
634
|
|
|
527
|
-
|
|
635
|
+
test.it("should parse combined short flags", async () => {
|
|
528
636
|
const cmd = Commander
|
|
529
637
|
.make({ name: "app" })
|
|
530
638
|
.option(
|
|
@@ -544,13 +652,17 @@ t.describe(`${Commander.parse.name} - comprehensive`, () => {
|
|
|
544
652
|
Commander.parse(cmd, []),
|
|
545
653
|
)
|
|
546
654
|
|
|
547
|
-
|
|
548
|
-
|
|
655
|
+
test
|
|
656
|
+
.expect(result.verbose)
|
|
657
|
+
.toBe(false)
|
|
658
|
+
test
|
|
659
|
+
.expect(result.debug)
|
|
660
|
+
.toBe(false)
|
|
549
661
|
})
|
|
550
662
|
})
|
|
551
663
|
|
|
552
|
-
|
|
553
|
-
|
|
664
|
+
test.describe("boolean options", () => {
|
|
665
|
+
test.it("should return false for boolean flag when not specified", async () => {
|
|
554
666
|
const cmd = Commander
|
|
555
667
|
.make({ name: "app" })
|
|
556
668
|
.option(
|
|
@@ -564,10 +676,12 @@ t.describe("boolean options", () => {
|
|
|
564
676
|
Commander.parse(cmd, []),
|
|
565
677
|
)
|
|
566
678
|
|
|
567
|
-
|
|
679
|
+
test
|
|
680
|
+
.expect(result.verbose)
|
|
681
|
+
.toBe(false)
|
|
568
682
|
})
|
|
569
683
|
|
|
570
|
-
|
|
684
|
+
test.it("should return true for boolean flag when specified", async () => {
|
|
571
685
|
const cmd = Commander
|
|
572
686
|
.make({ name: "app" })
|
|
573
687
|
.option(
|
|
@@ -581,10 +695,12 @@ t.describe("boolean options", () => {
|
|
|
581
695
|
Commander.parse(cmd, ["--verbose", "true"]),
|
|
582
696
|
)
|
|
583
697
|
|
|
584
|
-
|
|
698
|
+
test
|
|
699
|
+
.expect(result.verbose)
|
|
700
|
+
.toBe(true)
|
|
585
701
|
})
|
|
586
702
|
|
|
587
|
-
|
|
703
|
+
test.it("should handle boolean with custom default", async () => {
|
|
588
704
|
const cmd = Commander
|
|
589
705
|
.make({ name: "app" })
|
|
590
706
|
.option(
|
|
@@ -598,12 +714,14 @@ t.describe("boolean options", () => {
|
|
|
598
714
|
Commander.parse(cmd, []),
|
|
599
715
|
)
|
|
600
716
|
|
|
601
|
-
|
|
717
|
+
test
|
|
718
|
+
.expect(result.color)
|
|
719
|
+
.toBe("auto")
|
|
602
720
|
})
|
|
603
721
|
})
|
|
604
722
|
|
|
605
|
-
|
|
606
|
-
|
|
723
|
+
test.describe("options with choices", () => {
|
|
724
|
+
test.it("should accept valid choice", async () => {
|
|
607
725
|
const cmd = Commander
|
|
608
726
|
.make({ name: "app" })
|
|
609
727
|
.option(
|
|
@@ -621,10 +739,12 @@ t.describe("options with choices", () => {
|
|
|
621
739
|
Commander.parse(cmd, ["--color", "red"]),
|
|
622
740
|
)
|
|
623
741
|
|
|
624
|
-
|
|
742
|
+
test
|
|
743
|
+
.expect(result.color)
|
|
744
|
+
.toBe("red")
|
|
625
745
|
})
|
|
626
746
|
|
|
627
|
-
|
|
747
|
+
test.it("should reject invalid choice", async () => {
|
|
628
748
|
const cmd = Commander
|
|
629
749
|
.make({ name: "app" })
|
|
630
750
|
.option(
|
|
@@ -642,10 +762,12 @@ t.describe("options with choices", () => {
|
|
|
642
762
|
Effect.either(Commander.parse(cmd, ["--color", "yellow"])),
|
|
643
763
|
)
|
|
644
764
|
|
|
645
|
-
|
|
765
|
+
test
|
|
766
|
+
.expect(result._tag)
|
|
767
|
+
.toBe("Left")
|
|
646
768
|
})
|
|
647
769
|
|
|
648
|
-
|
|
770
|
+
test.it("should handle multiple choice options", async () => {
|
|
649
771
|
const cmd = Commander
|
|
650
772
|
.make({ name: "app" })
|
|
651
773
|
.option(
|
|
@@ -675,13 +797,17 @@ t.describe("options with choices", () => {
|
|
|
675
797
|
Commander.parse(cmd, ["--format", "xml", "--level", "debug"]),
|
|
676
798
|
)
|
|
677
799
|
|
|
678
|
-
|
|
679
|
-
|
|
800
|
+
test
|
|
801
|
+
.expect(result.format)
|
|
802
|
+
.toBe("xml")
|
|
803
|
+
test
|
|
804
|
+
.expect(result.level)
|
|
805
|
+
.toBe("debug")
|
|
680
806
|
})
|
|
681
807
|
})
|
|
682
808
|
|
|
683
|
-
|
|
684
|
-
|
|
809
|
+
test.describe("options with defaults", () => {
|
|
810
|
+
test.it("should use default when option not specified", async () => {
|
|
685
811
|
const cmd = Commander
|
|
686
812
|
.make({ name: "app" })
|
|
687
813
|
.option(
|
|
@@ -695,10 +821,12 @@ t.describe("options with defaults", () => {
|
|
|
695
821
|
Commander.parse(cmd, []),
|
|
696
822
|
)
|
|
697
823
|
|
|
698
|
-
|
|
824
|
+
test
|
|
825
|
+
.expect(result.port)
|
|
826
|
+
.toBe(3000)
|
|
699
827
|
})
|
|
700
828
|
|
|
701
|
-
|
|
829
|
+
test.it("should override default when option specified", async () => {
|
|
702
830
|
const cmd = Commander
|
|
703
831
|
.make({ name: "app" })
|
|
704
832
|
.option(
|
|
@@ -712,10 +840,12 @@ t.describe("options with defaults", () => {
|
|
|
712
840
|
Commander.parse(cmd, ["--port", "8080"]),
|
|
713
841
|
)
|
|
714
842
|
|
|
715
|
-
|
|
843
|
+
test
|
|
844
|
+
.expect(result.port)
|
|
845
|
+
.toBe(8080)
|
|
716
846
|
})
|
|
717
847
|
|
|
718
|
-
|
|
848
|
+
test.it("should handle multiple defaults", async () => {
|
|
719
849
|
const cmd = Commander
|
|
720
850
|
.make({ name: "app" })
|
|
721
851
|
.option(
|
|
@@ -741,12 +871,18 @@ t.describe("options with defaults", () => {
|
|
|
741
871
|
Commander.parse(cmd, []),
|
|
742
872
|
)
|
|
743
873
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
874
|
+
test
|
|
875
|
+
.expect(result.host)
|
|
876
|
+
.toBe("localhost")
|
|
877
|
+
test
|
|
878
|
+
.expect(result.port)
|
|
879
|
+
.toBe(3000)
|
|
880
|
+
test
|
|
881
|
+
.expect(result.debug)
|
|
882
|
+
.toBe(false)
|
|
747
883
|
})
|
|
748
884
|
|
|
749
|
-
|
|
885
|
+
test.it("should use default for string option", async () => {
|
|
750
886
|
const cmd = Commander
|
|
751
887
|
.make({ name: "app" })
|
|
752
888
|
.option(
|
|
@@ -760,12 +896,14 @@ t.describe("options with defaults", () => {
|
|
|
760
896
|
Commander.parse(cmd, []),
|
|
761
897
|
)
|
|
762
898
|
|
|
763
|
-
|
|
899
|
+
test
|
|
900
|
+
.expect(result.output)
|
|
901
|
+
.toBe("output.txt")
|
|
764
902
|
})
|
|
765
903
|
})
|
|
766
904
|
|
|
767
|
-
|
|
768
|
-
|
|
905
|
+
test.describe("action/handler", () => {
|
|
906
|
+
test.it("should invoke handler with parsed options", async () => {
|
|
769
907
|
let capturedOptions: any = null
|
|
770
908
|
|
|
771
909
|
const cmd = Commander
|
|
@@ -785,10 +923,12 @@ t.describe("action/handler", () => {
|
|
|
785
923
|
Commander.parse(cmd, ["--name", "test"]),
|
|
786
924
|
)
|
|
787
925
|
|
|
788
|
-
|
|
926
|
+
test
|
|
927
|
+
.expect(parsed.name)
|
|
928
|
+
.toBe("test")
|
|
789
929
|
})
|
|
790
930
|
|
|
791
|
-
|
|
931
|
+
test.it("should support async handlers", async () => {
|
|
792
932
|
let executed = false
|
|
793
933
|
|
|
794
934
|
const cmd = Commander
|
|
@@ -810,10 +950,12 @@ t.describe("action/handler", () => {
|
|
|
810
950
|
Commander.parse(cmd, ["--delay", "10"]),
|
|
811
951
|
)
|
|
812
952
|
|
|
813
|
-
|
|
953
|
+
test
|
|
954
|
+
.expect(executed)
|
|
955
|
+
.toBe(false)
|
|
814
956
|
})
|
|
815
957
|
|
|
816
|
-
|
|
958
|
+
test.it("should pass all options to handler", async () => {
|
|
817
959
|
let capturedOpts: any = null
|
|
818
960
|
|
|
819
961
|
const cmd = Commander
|
|
@@ -846,38 +988,50 @@ t.describe("action/handler", () => {
|
|
|
846
988
|
})
|
|
847
989
|
})
|
|
848
990
|
|
|
849
|
-
|
|
850
|
-
|
|
991
|
+
test.describe(`${Commander.optionVersion.name} - version behavior`, () => {
|
|
992
|
+
test.it("should include version in command definition", () => {
|
|
851
993
|
const cmd = Commander
|
|
852
994
|
.make({ name: "app", version: "1.0.0" })
|
|
853
995
|
.optionVersion()
|
|
854
996
|
|
|
855
|
-
|
|
856
|
-
|
|
997
|
+
test
|
|
998
|
+
.expect(cmd.version)
|
|
999
|
+
.toBe("1.0.0")
|
|
1000
|
+
test
|
|
1001
|
+
.expect(cmd.options.version)
|
|
1002
|
+
.toBeDefined()
|
|
857
1003
|
})
|
|
858
1004
|
|
|
859
|
-
|
|
1005
|
+
test.it("should handle version without version option", () => {
|
|
860
1006
|
const cmd = Commander
|
|
861
1007
|
.make({ name: "app", version: "2.0.0" })
|
|
862
1008
|
|
|
863
|
-
|
|
864
|
-
|
|
1009
|
+
test
|
|
1010
|
+
.expect(cmd.version)
|
|
1011
|
+
.toBe("2.0.0")
|
|
1012
|
+
test
|
|
1013
|
+
.expect(cmd.options["version"])
|
|
1014
|
+
.toBeUndefined()
|
|
865
1015
|
})
|
|
866
1016
|
|
|
867
|
-
|
|
1017
|
+
test.it("should include version option in help", () => {
|
|
868
1018
|
const cmd = Commander
|
|
869
1019
|
.make({ name: "app", version: "1.0.0" })
|
|
870
1020
|
.optionVersion()
|
|
871
1021
|
|
|
872
1022
|
const help = Commander.help(cmd)
|
|
873
1023
|
|
|
874
|
-
|
|
875
|
-
|
|
1024
|
+
test
|
|
1025
|
+
.expect(help)
|
|
1026
|
+
.toContain("--version")
|
|
1027
|
+
test
|
|
1028
|
+
.expect(help)
|
|
1029
|
+
.toContain("-V")
|
|
876
1030
|
})
|
|
877
1031
|
})
|
|
878
1032
|
|
|
879
|
-
|
|
880
|
-
|
|
1033
|
+
test.describe(`${Commander.help.name} - comprehensive`, () => {
|
|
1034
|
+
test.it("should generate help with description", () => {
|
|
881
1035
|
const cmd = Commander
|
|
882
1036
|
.make({
|
|
883
1037
|
name: "myapp",
|
|
@@ -887,11 +1041,15 @@ t.describe(`${Commander.help.name} - comprehensive`, () => {
|
|
|
887
1041
|
|
|
888
1042
|
const help = Commander.help(cmd)
|
|
889
1043
|
|
|
890
|
-
|
|
891
|
-
|
|
1044
|
+
test
|
|
1045
|
+
.expect(help)
|
|
1046
|
+
.toContain("A test application")
|
|
1047
|
+
test
|
|
1048
|
+
.expect(help)
|
|
1049
|
+
.toContain("Usage: myapp [options]")
|
|
892
1050
|
})
|
|
893
1051
|
|
|
894
|
-
|
|
1052
|
+
test.it("should include all options in help", () => {
|
|
895
1053
|
const cmd = Commander
|
|
896
1054
|
.make({ name: "app" })
|
|
897
1055
|
.option(
|
|
@@ -910,15 +1068,27 @@ t.describe(`${Commander.help.name} - comprehensive`, () => {
|
|
|
910
1068
|
|
|
911
1069
|
const help = Commander.help(cmd)
|
|
912
1070
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1071
|
+
test
|
|
1072
|
+
.expect(help)
|
|
1073
|
+
.toContain("--input")
|
|
1074
|
+
test
|
|
1075
|
+
.expect(help)
|
|
1076
|
+
.toContain("-i,")
|
|
1077
|
+
test
|
|
1078
|
+
.expect(help)
|
|
1079
|
+
.toContain("Input file")
|
|
1080
|
+
test
|
|
1081
|
+
.expect(help)
|
|
1082
|
+
.toContain("--output")
|
|
1083
|
+
test
|
|
1084
|
+
.expect(help)
|
|
1085
|
+
.toContain("-o,")
|
|
1086
|
+
test
|
|
1087
|
+
.expect(help)
|
|
1088
|
+
.toContain("Output file")
|
|
1089
|
+
})
|
|
1090
|
+
|
|
1091
|
+
test.it("should show subcommands in help", () => {
|
|
922
1092
|
const subCmd = Commander
|
|
923
1093
|
.make({ name: "init", description: "Initialize project" })
|
|
924
1094
|
.handle(() => Effect.void)
|
|
@@ -930,12 +1100,18 @@ t.describe(`${Commander.help.name} - comprehensive`, () => {
|
|
|
930
1100
|
|
|
931
1101
|
const help = Commander.help(cmd)
|
|
932
1102
|
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
1103
|
+
test
|
|
1104
|
+
.expect(help)
|
|
1105
|
+
.toContain("Commands:")
|
|
1106
|
+
test
|
|
1107
|
+
.expect(help)
|
|
1108
|
+
.toContain("init")
|
|
1109
|
+
test
|
|
1110
|
+
.expect(help)
|
|
1111
|
+
.toContain("Initialize project")
|
|
936
1112
|
})
|
|
937
1113
|
|
|
938
|
-
|
|
1114
|
+
test.it("should format option descriptions properly", () => {
|
|
939
1115
|
const cmd = Commander
|
|
940
1116
|
.make({ name: "app" })
|
|
941
1117
|
.option(
|
|
@@ -947,13 +1123,17 @@ t.describe(`${Commander.help.name} - comprehensive`, () => {
|
|
|
947
1123
|
|
|
948
1124
|
const help = Commander.help(cmd)
|
|
949
1125
|
|
|
950
|
-
|
|
951
|
-
|
|
1126
|
+
test
|
|
1127
|
+
.expect(help)
|
|
1128
|
+
.toContain("-c, --config")
|
|
1129
|
+
test
|
|
1130
|
+
.expect(help)
|
|
1131
|
+
.toContain("Config file path")
|
|
952
1132
|
})
|
|
953
1133
|
})
|
|
954
1134
|
|
|
955
|
-
|
|
956
|
-
|
|
1135
|
+
test.describe(`${Commander.subcommand.name} - comprehensive`, () => {
|
|
1136
|
+
test.it("should add subcommand", () => {
|
|
957
1137
|
const subCmd = Commander
|
|
958
1138
|
.make({ name: "build" })
|
|
959
1139
|
.option(
|
|
@@ -968,30 +1148,40 @@ t.describe(`${Commander.subcommand.name} - comprehensive`, () => {
|
|
|
968
1148
|
.make({ name: "app" })
|
|
969
1149
|
.subcommand(subCmd)
|
|
970
1150
|
|
|
971
|
-
|
|
972
|
-
|
|
1151
|
+
test
|
|
1152
|
+
.expect(cmd.subcommands.length)
|
|
1153
|
+
.toBe(1)
|
|
1154
|
+
test
|
|
1155
|
+
.expect(cmd.subcommands[0]!.command.name)
|
|
1156
|
+
.toBe("build")
|
|
973
1157
|
})
|
|
974
1158
|
|
|
975
|
-
|
|
1159
|
+
test.it("should add multiple subcommands", () => {
|
|
976
1160
|
const build = Commander
|
|
977
1161
|
.make({ name: "build" })
|
|
978
1162
|
.handle(() => Effect.void)
|
|
979
1163
|
|
|
980
|
-
const
|
|
1164
|
+
const testCmd = Commander
|
|
981
1165
|
.make({ name: "test" })
|
|
982
1166
|
.handle(() => Effect.void)
|
|
983
1167
|
|
|
984
1168
|
const cmd = Commander
|
|
985
1169
|
.make({ name: "app" })
|
|
986
1170
|
.subcommand(build)
|
|
987
|
-
.subcommand(
|
|
1171
|
+
.subcommand(testCmd)
|
|
988
1172
|
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1173
|
+
test
|
|
1174
|
+
.expect(cmd.subcommands.length)
|
|
1175
|
+
.toBe(2)
|
|
1176
|
+
test
|
|
1177
|
+
.expect(cmd.subcommands[0]!.command.name)
|
|
1178
|
+
.toBe("build")
|
|
1179
|
+
test
|
|
1180
|
+
.expect(cmd.subcommands[1]!.command.name)
|
|
1181
|
+
.toBe("test")
|
|
992
1182
|
})
|
|
993
1183
|
|
|
994
|
-
|
|
1184
|
+
test.it("should nest subcommands", () => {
|
|
995
1185
|
const deploy = Commander
|
|
996
1186
|
.make({ name: "deploy" })
|
|
997
1187
|
.handle(() => Effect.void)
|
|
@@ -1005,15 +1195,17 @@ t.describe(`${Commander.subcommand.name} - comprehensive`, () => {
|
|
|
1005
1195
|
.make({ name: "app" })
|
|
1006
1196
|
.subcommand(build)
|
|
1007
1197
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1198
|
+
test
|
|
1199
|
+
.expect(cmd.subcommands[0]!.command.subcommands.length)
|
|
1200
|
+
.toBe(1)
|
|
1201
|
+
test
|
|
1202
|
+
.expect(cmd.subcommands[0]!.command.subcommands[0]!.command.name)
|
|
1203
|
+
.toBe("deploy")
|
|
1012
1204
|
})
|
|
1013
1205
|
})
|
|
1014
1206
|
|
|
1015
|
-
|
|
1016
|
-
|
|
1207
|
+
test.describe("option types", () => {
|
|
1208
|
+
test.it("should parse string option", async () => {
|
|
1017
1209
|
const cmd = Commander
|
|
1018
1210
|
.make({ name: "app" })
|
|
1019
1211
|
.option(
|
|
@@ -1026,11 +1218,15 @@ t.describe("option types", () => {
|
|
|
1026
1218
|
Commander.parse(cmd, ["--name", "test"]),
|
|
1027
1219
|
)
|
|
1028
1220
|
|
|
1029
|
-
|
|
1030
|
-
|
|
1221
|
+
test
|
|
1222
|
+
.expect(result.name)
|
|
1223
|
+
.toBe("test")
|
|
1224
|
+
test
|
|
1225
|
+
.expect(typeof result.name)
|
|
1226
|
+
.toBe("string")
|
|
1031
1227
|
})
|
|
1032
1228
|
|
|
1033
|
-
|
|
1229
|
+
test.it("should parse number option", async () => {
|
|
1034
1230
|
const cmd = Commander
|
|
1035
1231
|
.make({ name: "app" })
|
|
1036
1232
|
.option(
|
|
@@ -1043,11 +1239,15 @@ t.describe("option types", () => {
|
|
|
1043
1239
|
Commander.parse(cmd, ["--count", "42"]),
|
|
1044
1240
|
)
|
|
1045
1241
|
|
|
1046
|
-
|
|
1047
|
-
|
|
1242
|
+
test
|
|
1243
|
+
.expect(result.count)
|
|
1244
|
+
.toBe(42)
|
|
1245
|
+
test
|
|
1246
|
+
.expect(typeof result.count)
|
|
1247
|
+
.toBe("number")
|
|
1048
1248
|
})
|
|
1049
1249
|
|
|
1050
|
-
|
|
1250
|
+
test.it("should parse boolean option", async () => {
|
|
1051
1251
|
const cmd = Commander
|
|
1052
1252
|
.make({ name: "app" })
|
|
1053
1253
|
.option(
|
|
@@ -1060,11 +1260,15 @@ t.describe("option types", () => {
|
|
|
1060
1260
|
Commander.parse(cmd, ["--enabled", "true"]),
|
|
1061
1261
|
)
|
|
1062
1262
|
|
|
1063
|
-
|
|
1064
|
-
|
|
1263
|
+
test
|
|
1264
|
+
.expect(result.enabled)
|
|
1265
|
+
.toBe(true)
|
|
1266
|
+
test
|
|
1267
|
+
.expect(typeof result.enabled)
|
|
1268
|
+
.toBe("boolean")
|
|
1065
1269
|
})
|
|
1066
1270
|
|
|
1067
|
-
|
|
1271
|
+
test.it("should fail on invalid number", async () => {
|
|
1068
1272
|
const cmd = Commander
|
|
1069
1273
|
.make({ name: "app" })
|
|
1070
1274
|
.option(
|
|
@@ -1077,12 +1281,14 @@ t.describe("option types", () => {
|
|
|
1077
1281
|
Effect.either(Commander.parse(cmd, ["--count", "not-a-number"])),
|
|
1078
1282
|
)
|
|
1079
1283
|
|
|
1080
|
-
|
|
1284
|
+
test
|
|
1285
|
+
.expect(result._tag)
|
|
1286
|
+
.toBe("Left")
|
|
1081
1287
|
})
|
|
1082
1288
|
})
|
|
1083
1289
|
|
|
1084
|
-
|
|
1085
|
-
|
|
1290
|
+
test.describe("complex scenarios", () => {
|
|
1291
|
+
test.it("should handle mixed option types", async () => {
|
|
1086
1292
|
const cmd = Commander
|
|
1087
1293
|
.make({ name: "server" })
|
|
1088
1294
|
.option(
|
|
@@ -1128,13 +1334,21 @@ t.describe("complex scenarios", () => {
|
|
|
1128
1334
|
]),
|
|
1129
1335
|
)
|
|
1130
1336
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1337
|
+
test
|
|
1338
|
+
.expect(result.host)
|
|
1339
|
+
.toBe("0.0.0.0")
|
|
1340
|
+
test
|
|
1341
|
+
.expect(result.port)
|
|
1342
|
+
.toBe(8080)
|
|
1343
|
+
test
|
|
1344
|
+
.expect(result.ssl)
|
|
1345
|
+
.toBe(true)
|
|
1346
|
+
test
|
|
1347
|
+
.expect(result.env)
|
|
1348
|
+
.toBe("production")
|
|
1349
|
+
})
|
|
1350
|
+
|
|
1351
|
+
test.it("should handle repeatable options", async () => {
|
|
1138
1352
|
const cmd = Commander
|
|
1139
1353
|
.make({ name: "app" })
|
|
1140
1354
|
.option(
|
|
@@ -1147,10 +1361,12 @@ t.describe("complex scenarios", () => {
|
|
|
1147
1361
|
Commander.parse(cmd, ["--tags", "foo,bar,baz"]),
|
|
1148
1362
|
)
|
|
1149
1363
|
|
|
1150
|
-
|
|
1364
|
+
test
|
|
1365
|
+
.expect(result.tags)
|
|
1366
|
+
.toEqual(["foo", "bar", "baz"])
|
|
1151
1367
|
})
|
|
1152
1368
|
|
|
1153
|
-
|
|
1369
|
+
test.it("should preserve option order independence", async () => {
|
|
1154
1370
|
const cmd = Commander
|
|
1155
1371
|
.make({ name: "app" })
|
|
1156
1372
|
.option(
|
|
@@ -1172,13 +1388,21 @@ t.describe("complex scenarios", () => {
|
|
|
1172
1388
|
Commander.parse(cmd, ["--second", "2", "--first", "1"]),
|
|
1173
1389
|
)
|
|
1174
1390
|
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1391
|
+
test
|
|
1392
|
+
.expect(result1.first)
|
|
1393
|
+
.toBe("1")
|
|
1394
|
+
test
|
|
1395
|
+
.expect(result1.second)
|
|
1396
|
+
.toBe("2")
|
|
1397
|
+
test
|
|
1398
|
+
.expect(result2.first)
|
|
1399
|
+
.toBe("1")
|
|
1400
|
+
test
|
|
1401
|
+
.expect(result2.second)
|
|
1402
|
+
.toBe("2")
|
|
1403
|
+
})
|
|
1404
|
+
|
|
1405
|
+
test.it("should handle options with hyphens in names", async () => {
|
|
1182
1406
|
const cmd = Commander
|
|
1183
1407
|
.make({ name: "app" })
|
|
1184
1408
|
.option(
|
|
@@ -1198,13 +1422,17 @@ t.describe("complex scenarios", () => {
|
|
|
1198
1422
|
Commander.parse(cmd, ["--dry-run", "true", "--no-cache", "true"]),
|
|
1199
1423
|
)
|
|
1200
1424
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1425
|
+
test
|
|
1426
|
+
.expect(result.dryRun)
|
|
1427
|
+
.toBe(true)
|
|
1428
|
+
test
|
|
1429
|
+
.expect(result.noCache)
|
|
1430
|
+
.toBe(true)
|
|
1203
1431
|
})
|
|
1204
1432
|
})
|
|
1205
1433
|
|
|
1206
|
-
|
|
1207
|
-
|
|
1434
|
+
test.describe("error handling", () => {
|
|
1435
|
+
test.it("should fail gracefully on invalid option value", async () => {
|
|
1208
1436
|
const cmd = Commander
|
|
1209
1437
|
.make({ name: "app" })
|
|
1210
1438
|
.option(
|
|
@@ -1218,10 +1446,12 @@ t.describe("error handling", () => {
|
|
|
1218
1446
|
)
|
|
1219
1447
|
|
|
1220
1448
|
assert.strictEqual(result._tag, "Left")
|
|
1221
|
-
|
|
1449
|
+
test
|
|
1450
|
+
.expect(result.left.message)
|
|
1451
|
+
.toContain("Invalid value")
|
|
1222
1452
|
})
|
|
1223
1453
|
|
|
1224
|
-
|
|
1454
|
+
test.it("should fail on invalid choice", async () => {
|
|
1225
1455
|
const cmd = Commander
|
|
1226
1456
|
.make({ name: "app" })
|
|
1227
1457
|
.option(
|
|
@@ -1234,12 +1464,14 @@ t.describe("error handling", () => {
|
|
|
1234
1464
|
Effect.either(Commander.parse(cmd, ["--mode", "staging"])),
|
|
1235
1465
|
)
|
|
1236
1466
|
|
|
1237
|
-
|
|
1467
|
+
test
|
|
1468
|
+
.expect(result._tag)
|
|
1469
|
+
.toBe("Left")
|
|
1238
1470
|
})
|
|
1239
1471
|
})
|
|
1240
1472
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1473
|
+
test.describe("builder pattern", () => {
|
|
1474
|
+
test.it("should chain option definitions fluently", () => {
|
|
1243
1475
|
const cmd = Commander
|
|
1244
1476
|
.make({ name: "app" })
|
|
1245
1477
|
.option(
|
|
@@ -1256,12 +1488,18 @@ t.describe("builder pattern", () => {
|
|
|
1256
1488
|
.schema(Schema.String),
|
|
1257
1489
|
)
|
|
1258
1490
|
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1491
|
+
test
|
|
1492
|
+
.expect(cmd.options.input.description)
|
|
1493
|
+
.toBe("Input file")
|
|
1494
|
+
test
|
|
1495
|
+
.expect(cmd.options.output.description)
|
|
1496
|
+
.toBe("Output file")
|
|
1497
|
+
test
|
|
1498
|
+
.expect(cmd.options.output.defaultValue)
|
|
1499
|
+
.toBe("out.txt")
|
|
1262
1500
|
})
|
|
1263
1501
|
|
|
1264
|
-
|
|
1502
|
+
test.it("should chain description and default in any order", () => {
|
|
1265
1503
|
const cmd1 = Commander
|
|
1266
1504
|
.make({ name: "app" })
|
|
1267
1505
|
.option(
|
|
@@ -1282,13 +1520,21 @@ t.describe("builder pattern", () => {
|
|
|
1282
1520
|
.schema(Commander.NumberFromString),
|
|
1283
1521
|
)
|
|
1284
1522
|
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1523
|
+
test
|
|
1524
|
+
.expect(cmd1.options.port.description)
|
|
1525
|
+
.toBe("Port number")
|
|
1526
|
+
test
|
|
1527
|
+
.expect(cmd1.options.port.defaultValue)
|
|
1528
|
+
.toBe(3000)
|
|
1529
|
+
test
|
|
1530
|
+
.expect(cmd2.options.port.description)
|
|
1531
|
+
.toBe("Port number")
|
|
1532
|
+
test
|
|
1533
|
+
.expect(cmd2.options.port.defaultValue)
|
|
1534
|
+
.toBe(3000)
|
|
1289
1535
|
})
|
|
1290
1536
|
|
|
1291
|
-
|
|
1537
|
+
test.it("should support method chaining with subcommands", () => {
|
|
1292
1538
|
const sub1 = Commander
|
|
1293
1539
|
.make({ name: "sub1" })
|
|
1294
1540
|
.handle(() => Effect.void)
|
|
@@ -1308,14 +1554,20 @@ t.describe("builder pattern", () => {
|
|
|
1308
1554
|
.subcommand(sub2)
|
|
1309
1555
|
.optionHelp()
|
|
1310
1556
|
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1557
|
+
test
|
|
1558
|
+
.expect(cmd.options.global)
|
|
1559
|
+
.toBeDefined()
|
|
1560
|
+
test
|
|
1561
|
+
.expect(cmd.options.help)
|
|
1562
|
+
.toBeDefined()
|
|
1563
|
+
test
|
|
1564
|
+
.expect(cmd.subcommands.length)
|
|
1565
|
+
.toBe(2)
|
|
1314
1566
|
})
|
|
1315
1567
|
})
|
|
1316
1568
|
|
|
1317
|
-
|
|
1318
|
-
|
|
1569
|
+
test.describe("example scenario", () => {
|
|
1570
|
+
test.it("should handle main command with subcommand", async () => {
|
|
1319
1571
|
const unhandledFormat = Commander.make({
|
|
1320
1572
|
name: "format",
|
|
1321
1573
|
description: "Format source files",
|
|
@@ -1362,16 +1614,26 @@ t.describe("example scenario", () => {
|
|
|
1362
1614
|
Commander.parse(main, ["--source", "test.ts", "--verbose", "true"]),
|
|
1363
1615
|
)
|
|
1364
1616
|
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1617
|
+
test
|
|
1618
|
+
.expect(resultMain.source)
|
|
1619
|
+
.toBe("test.ts")
|
|
1620
|
+
test
|
|
1621
|
+
.expect(resultMain.verbose)
|
|
1622
|
+
.toBe(true)
|
|
1623
|
+
test
|
|
1624
|
+
.expect(resultMain.help)
|
|
1625
|
+
.toBe(false)
|
|
1626
|
+
test
|
|
1627
|
+
.expect(main.subcommands.length)
|
|
1628
|
+
.toBe(1)
|
|
1629
|
+
test
|
|
1630
|
+
.expect(main.subcommands[0]!.command.name)
|
|
1631
|
+
.toBe("format")
|
|
1632
|
+
test
|
|
1633
|
+
.expect(main.subcommands[0]!.command.options.style)
|
|
1634
|
+
.toBeDefined()
|
|
1635
|
+
test
|
|
1636
|
+
.expect(main.subcommands[0]!.command.options.style.defaultValue)
|
|
1637
|
+
.toBe("standard")
|
|
1376
1638
|
})
|
|
1377
1639
|
})
|