From ce165634b81e6e545ac6302636c2f59bc3a1e32b Mon Sep 17 00:00:00 2001 From: Victor Fan Date: Wed, 17 Jun 2026 14:40:42 -0700 Subject: [PATCH 1/2] wire format for a nonEmpty field in string/[]string params --- spec/fixtures/sources/commonjs-params/index.js | 4 ++-- spec/runtime/loader.spec.ts | 2 ++ src/params/index.ts | 5 +++-- src/params/types.ts | 9 ++++++++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/spec/fixtures/sources/commonjs-params/index.js b/spec/fixtures/sources/commonjs-params/index.js index 76d07559c..42597fb6d 100644 --- a/spec/fixtures/sources/commonjs-params/index.js +++ b/spec/fixtures/sources/commonjs-params/index.js @@ -6,7 +6,7 @@ const params = require("../../../../src/params"); params.defineString("BORING"); const foo = params.defineString("FOO", { input: { text: { validationRegex: "w+" } } }); -const bar = params.defineString("BAR", { default: foo, label: "asdf" }); +const bar = params.defineString("BAR", { default: foo, label: "asdf", nonEmpty: true }); params.defineString("BAZ", { input: { select: { options: [{ value: "a" }, { value: "b" }] } } }); params.defineInt("AN_INT", { default: bar.equals("qux").thenElse(0, 1) }); @@ -21,7 +21,7 @@ params.defineInt("ANOTHER_INT", { }, }); -params.defineList("LIST_PARAM", {input: { multiSelect: { options: [{ value: "c" }, { value: "d" }, { value: "e" }]}}}) +params.defineList("LIST_PARAM", {nonEmpty: true, input: { multiSelect: { options: [{ value: "c" }, { value: "d" }, { value: "e" }]}}}) params.defineSecret("SUPER_SECRET_FLAG"); diff --git a/spec/runtime/loader.spec.ts b/spec/runtime/loader.spec.ts index 9070c995f..c88e06976 100644 --- a/spec/runtime/loader.spec.ts +++ b/spec/runtime/loader.spec.ts @@ -405,6 +405,7 @@ describe("loadStack", () => { type: "string", default: "{{ params.FOO }}", label: "asdf", + nonEmpty: true, }, { name: "BAZ", @@ -429,6 +430,7 @@ describe("loadStack", () => { { name: "LIST_PARAM", type: "list", + nonEmpty: true, input: { multiSelect: { options: [{ value: "c" }, { value: "d" }, { value: "e" }] }, }, diff --git a/src/params/index.ts b/src/params/index.ts index e824f61fa..95310c541 100644 --- a/src/params/index.ts +++ b/src/params/index.ts @@ -39,6 +39,7 @@ import { SecretParamOptions, InternalExpression, InterpolationExpression, + SupportsNonEmpty, } from "./types"; export { BUCKET_PICKER, select, multiSelect } from "./types"; @@ -181,7 +182,7 @@ export function defineJsonSecret( * @param options Configuration options for the parameter. * @returns A parameter with a `string` return type for `.value`. */ -export function defineString(name: string, options: ParamOptions = {}): StringParam { +export function defineString(name: string, options: ParamOptions & SupportsNonEmpty = {}): StringParam { const param = new StringParam(name, options); registerParam(param); return param; @@ -235,7 +236,7 @@ export function defineFloat(name: string, options: ParamOptions = {}): F * @param options Configuration options for the parameter. * @returns A parameter with a `string[]` return type for `.value`. */ -export function defineList(name: string, options: ParamOptions = {}): ListParam { +export function defineList(name: string, options: ParamOptions & SupportsNonEmpty = {}): ListParam { const param = new ListParam(name, options); registerParam(param); return param; diff --git a/src/params/types.ts b/src/params/types.ts index 946cedf51..a3cd86cb6 100644 --- a/src/params/types.ts +++ b/src/params/types.ts @@ -411,6 +411,8 @@ export type ParamSpec = { input?: ParamInput; /** Optional format annotation for additional type information (e.g., "json" for JSON-encoded secrets). */ format?: string; + + nonEmpty?: boolean; }; /** @@ -429,14 +431,19 @@ export type WireParamSpec = { type: ParamValueType; input?: ParamInput; format?: string; + nonEmpty?: boolean; }; /** Configuration options which can be used to customize the prompting behavior of a parameter. */ export type ParamOptions = Omit< ParamSpec, - "name" | "type" + "name" | "type" | "nonEmpty" >; +export type SupportsNonEmpty = { + nonEmpty?: boolean; +} + /** Configuration options which can be used to customize the behavior of a secret parameter. */ export interface SecretParamOptions { /** An optional human-readable string to be used as a replacement for the parameter's name when prompting. */ From 3bf4abf3b974d9475c0eb37bce5d4c388ccca6cf Mon Sep 17 00:00:00 2001 From: Victor Fan Date: Wed, 17 Jun 2026 14:41:47 -0700 Subject: [PATCH 2/2] missing comment --- src/params/types.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/params/types.ts b/src/params/types.ts index a3cd86cb6..d6807effc 100644 --- a/src/params/types.ts +++ b/src/params/types.ts @@ -411,7 +411,7 @@ export type ParamSpec = { input?: ParamInput; /** Optional format annotation for additional type information (e.g., "json" for JSON-encoded secrets). */ format?: string; - + /** Disallows the empty string/empty list when prompting for input. */ nonEmpty?: boolean; }; @@ -434,12 +434,12 @@ export type WireParamSpec = { nonEmpty?: boolean; }; -/** Configuration options which can be used to customize the prompting behavior of a parameter. */ +/** Basic configuration options which can be used to customize the prompting behavior of a parameter. */ export type ParamOptions = Omit< ParamSpec, "name" | "type" | "nonEmpty" >; - +/** A configuration to disallow empty string/empty list, which is unioned to Paramoptions for types where it has meaning. */ export type SupportsNonEmpty = { nonEmpty?: boolean; } @@ -460,7 +460,7 @@ export interface SecretParamOptions { export abstract class Param extends Expression { static type: ParamValueType = "string"; - constructor(readonly name: string, readonly options: ParamOptions = {}) { + constructor(readonly name: string, readonly options: ParamOptions & SupportsNonEmpty = {}) { super(); }