diff --git a/pkl-core/src/main/java/org/pkl/core/runtime/CommandSpecParser.java b/pkl-core/src/main/java/org/pkl/core/runtime/CommandSpecParser.java index 0c677556..b80c934a 100644 --- a/pkl-core/src/main/java/org/pkl/core/runtime/CommandSpecParser.java +++ b/pkl-core/src/main/java/org/pkl/core/runtime/CommandSpecParser.java @@ -32,7 +32,6 @@ import java.util.Set; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; -import java.util.stream.Collectors; import org.graalvm.collections.EconomicMap; import org.pkl.core.CommandSpec; import org.pkl.core.CommandSpec.Argument; @@ -771,18 +770,18 @@ public final class CommandSpecParser { return true; } else if (typeNode instanceof TypeNode.UnionOfStringLiteralsTypeNode unionOfStringLiteralsTypeNode) { - var choices = unionOfStringLiteralsTypeNode.getStringLiterals().stream().sorted(); + var choices = unionOfStringLiteralsTypeNode.getStringLiterals().stream().sorted().toList(); if (each == null) each = (rawValue, workingDirUri) -> { if (!unionOfStringLiteralsTypeNode.getStringLiterals().contains(rawValue)) { - throw BadValue.invalidChoice(rawValue, choices.toList()); + throw BadValue.invalidChoice(rawValue, choices); } return rawValue; }; if (all == null) all = this::allChooseLast; if (multiple == null) multiple = false; - if (metavar == null) metavar = "[" + choices.collect(Collectors.joining(", ")) + "]"; + if (metavar == null) metavar = "[" + String.join(", ", choices) + "]"; if (completionCandidates == null) completionCandidates = new Fixed(unionOfStringLiteralsTypeNode.getStringLiterals()); return true; diff --git a/pkl-core/src/test/kotlin/org/pkl/core/runtime/CommandSpecParserTest.kt b/pkl-core/src/test/kotlin/org/pkl/core/runtime/CommandSpecParserTest.kt index bafbd485..05aaa1d1 100644 --- a/pkl-core/src/test/kotlin/org/pkl/core/runtime/CommandSpecParserTest.kt +++ b/pkl-core/src/test/kotlin/org/pkl/core/runtime/CommandSpecParserTest.kt @@ -787,4 +787,31 @@ class CommandSpecParserTest { .contains("Option `foo` with annotation `@CountedFlag` has invalid type `String`.") assertThat(exc.message).contains("Expected type: `Int`") } + + @Test + fun `union typed option validates invalid choice without stream error`() { + val moduleUri = + writePklFile( + "cmd.pkl", + renderOptions + + """ + class Options { + format: "json" | "yaml" | "toml" + } + """ + .trimIndent(), + ) + + val spec = parse(moduleUri) + val flag = spec.options.first() as CommandSpec.Flag + + assertThat(flag.metavar()).isEqualTo("[json, toml, yaml]") + + val apply = + assertThrows { + flag.transformEach().apply("xml", URI("file:///tmp")) + } + assertThat(apply.message).contains("invalid choice") + assertThat(apply.message).contains("xml") + } }