Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-invalid-value-doubled-expected.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"effect": patch
---

Fix doubled `Expected: Expected ...` prefixes in CLI `InvalidValue` error messages, closes #6312.
9 changes: 6 additions & 3 deletions packages/effect/src/unstable/cli/CliError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,13 +362,16 @@ export class InvalidValue extends Schema.TaggedErrorClass<InvalidValue>(
* @since 4.0.0
*/
override get message() {
const expectation = this.expected.startsWith("Expected ") || this.expected.startsWith("Expected:")
? this.expected
: `Expected: ${this.expected}`
if (this.kind === "argument") {
return `Invalid value for argument <${this.option}>: "${this.value}". Expected: ${this.expected}`
return `Invalid value for argument <${this.option}>: "${this.value}". ${expectation}`
}
if (this.value.length === 0) {
return `Missing value for flag --${this.option}. Expected: ${this.expected}`
return `Missing value for flag --${this.option}. ${expectation}`
}
return `Invalid value for flag --${this.option}: "${this.value}". Expected: ${this.expected}`
return `Invalid value for flag --${this.option}: "${this.value}". ${expectation}`
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/effect/src/unstable/cli/Primitive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ export const choice = <A>(
if (choiceMap.has(value)) {
return Effect.succeed(choiceMap.get(value)!)
}
return Effect.fail(`Expected ${validChoices}, got ${format(value)}`)
return Effect.fail(validChoices)
})
return Object.assign(primitive, { choiceKeys: choices.map(([key]) => key) })
}
Expand Down
2 changes: 1 addition & 1 deletion packages/effect/test/unstable/cli/Arguments.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ describe("Command arguments", () => {
expect(errorText).toMatchInlineSnapshot(`
"
ERROR
Invalid value for argument <count>: "not-a-number". Expected: Failed to parse integer: Expected an integer, got NaN"
Invalid value for argument <count>: "not-a-number". Expected a string representing a finite number, got "not-a-number""
`)
}).pipe(Effect.provide(TestLayer)))

Expand Down
21 changes: 21 additions & 0 deletions packages/effect/test/unstable/cli/Command.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,27 @@ describe("Command", () => {
}).pipe(Effect.provide(TestLayer)))
}

it.effect("should render invalid choice values without doubling the Expected prefix", () =>
Effect.gen(function*() {
let invoked = false
const command = Command.make("demo", {
size: Flag.choice("size", ["small", "medium", "large"])
}, () =>
Effect.sync(() => {
invoked = true
}))

yield* Command.runWith(command, { version: "1.0.0" })(["--size", "bogus"]).pipe(Effect.ignore)

const stderr = yield* TestConsole.errorLines
assert.isFalse(invoked)
assert.isTrue(
stderr.some((line) =>
String(line).includes(`Invalid value for flag --size: "bogus". Expected: "small" | "medium" | "large"`)
)
)
}).pipe(Effect.provide(TestLayer)))

it.effect("should execute handler with parsed config", () =>
Effect.gen(function*() {
const path = yield* Path.Path
Expand Down
56 changes: 56 additions & 0 deletions packages/effect/test/unstable/cli/Errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,60 @@ describe("Command errors", () => {
assert.strictEqual(output, "")
})
})

describe("InvalidValue", () => {
it("labels a bare expected description", () => {
const error = new CliError.InvalidValue({
option: "size",
value: "bogus",
expected: `"small" | "medium" | "large"`,
kind: "flag"
})

assert.strictEqual(
error.message,
`Invalid value for flag --size: "bogus". Expected: "small" | "medium" | "large"`
)
})

it("does not double the prefix for an Expected sentence", () => {
const error = new CliError.InvalidValue({
option: "count",
value: "3.14",
expected: "Expected an integer, got 3.14",
kind: "argument"
})

assert.strictEqual(
error.message,
`Invalid value for argument <count>: "3.14". Expected an integer, got 3.14`
)

const labeled = new CliError.InvalidValue({
option: "count",
value: "x",
expected: "Expected: an integer",
kind: "flag"
})

assert.strictEqual(
labeled.message,
`Invalid value for flag --count: "x". Expected: an integer`
)
})

it("does not double the prefix for a missing flag value", () => {
const error = new CliError.InvalidValue({
option: "count",
value: "",
expected: `Expected a string representing a finite number, got ""`,
kind: "flag"
})

assert.strictEqual(
error.message,
`Missing value for flag --count. Expected a string representing a finite number, got ""`
)
})
})
})
6 changes: 3 additions & 3 deletions packages/effect/test/unstable/cli/Primitive.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,9 @@ describe("Primitive", () => {
colorChoice,
["yellow", "purple", ""],
[
`Expected "red" | "green" | "blue", got "yellow"`,
`Expected "red" | "green" | "blue", got "purple"`,
`Expected "red" | "green" | "blue", got ""`
`"red" | "green" | "blue"`,
`"red" | "green" | "blue"`,
`"red" | "green" | "blue"`
]
))

Expand Down
Loading