diff --git a/.changeset/add-public-decorator.md b/.changeset/add-public-decorator.md new file mode 100644 index 00000000..f5c16b30 --- /dev/null +++ b/.changeset/add-public-decorator.md @@ -0,0 +1,5 @@ +--- +"varlock": patch +--- + +Add `@public` item decorator as the counterpart to `@sensitive`, matching the pattern of `@required`/`@optional` decorator pairs diff --git a/packages/varlock-website/src/content/docs/reference/item-decorators.mdx b/packages/varlock-website/src/content/docs/reference/item-decorators.mdx index f27c236e..f2a525de 100644 --- a/packages/varlock-website/src/content/docs/reference/item-decorators.mdx +++ b/packages/varlock-website/src/content/docs/reference/item-decorators.mdx @@ -76,6 +76,20 @@ SERVICE_X_CLIENT_ID= ``` +
+### `@public` +**Value type:** `boolean` + +Opposite of [`@sensitive`](#sensitive). Equivalent to writing `@sensitive=false`. + +```env-spec +# @defaultSensitive=true +# --- +# @public +PUBLIC_API_URL=https://api.example.com +``` +
+
### `@type` **Value type:** [`data type`](/reference/data-types) (name only or function call) diff --git a/packages/varlock/src/env-graph/lib/config-item.ts b/packages/varlock/src/env-graph/lib/config-item.ts index f80e85f8..d937a40d 100644 --- a/packages/varlock/src/env-graph/lib/config-item.ts +++ b/packages/varlock/src/env-graph/lib/config-item.ts @@ -336,21 +336,26 @@ export class ConfigItem { private async processSensitive() { const sensitiveFromDataType = this.dataType?.isSensitive; for (const def of this.defs) { - const sensitiveDec = def.itemDef.decorators?.find((d) => d.name === 'sensitive'); + const sensitiveDecs = def.itemDef.decorators?.filter((d) => d.name === 'sensitive' || d.name === 'public') || []; + // NOTE - checks for duplicates and using sensitive+public together are already handled more generally + const sensitiveDec = sensitiveDecs[0]; + + // Explicit per-item decorators if (sensitiveDec) { + const usingPublic = sensitiveDec.name === 'public'; + const sensitiveDecValue = await sensitiveDec.resolve(); // can bail if the decorator value resolution failed if (sensitiveDec.schemaErrors.length) { return; } if (![true, false, undefined].includes(sensitiveDecValue)) { - throw new SchemaError('@sensitive must resolve to a boolean or undefined'); + throw new SchemaError('@sensitive/@public must resolve to a boolean or undefined'); } if (sensitiveDecValue !== undefined) { - this._isSensitive = sensitiveDecValue; + this._isSensitive = usingPublic ? !sensitiveDecValue : sensitiveDecValue; return; } - // TODO: do we want an opposite decorator similar to @required/@optional -- maybe @public? } // we skip `defaultSensitive` behaviour if the data type specifies sensitivity diff --git a/packages/varlock/src/env-graph/lib/decorators.ts b/packages/varlock/src/env-graph/lib/decorators.ts index 6714fb3d..711607f1 100644 --- a/packages/varlock/src/env-graph/lib/decorators.ts +++ b/packages/varlock/src/env-graph/lib/decorators.ts @@ -235,6 +235,10 @@ export const builtInItemDecorators: Array> = [ { name: 'sensitive', }, + { + name: 'public', + incompatibleWith: ['sensitive'], + }, { name: 'type', useFnArgsResolver: true, diff --git a/packages/varlock/src/env-graph/test/sensitive-decorator.test.ts b/packages/varlock/src/env-graph/test/sensitive-decorator.test.ts index 41570eb1..254fad36 100644 --- a/packages/varlock/src/env-graph/test/sensitive-decorator.test.ts +++ b/packages/varlock/src/env-graph/test/sensitive-decorator.test.ts @@ -43,6 +43,45 @@ describe('@sensitive and @defaultSensitive tests', () => { }, })); + test('@public and @sensitive mark items properly', envFilesTest({ + envFile: outdent` + SENSITIVE= # @sensitive + SENSITIVE_TRUE= # @sensitive=true + SENSITIVE_FALSE= # @sensitive=false + SENSITIVE_UNDEF= # @sensitive=undefined + PUBLIC= # @public + PUBLIC_TRUE= # @public=true + PUBLIC_FALSE= # @public=false + PUBLIC_UNDEF= # @public=undefined + `, + expectSensitive: { + SENSITIVE: true, + SENSITIVE_TRUE: true, + SENSITIVE_FALSE: false, + SENSITIVE_UNDEF: true, // stays as default + PUBLIC: false, + PUBLIC_TRUE: false, + PUBLIC_FALSE: true, + PUBLIC_UNDEF: true, // stays as default + }, + })); + + test('@public and @sensitive can be overridden', envFilesTest({ + files: { + '.env.schema': outdent` + WAS_SENSITIVE= # @sensitive + WAS_PUBLIC= # @public + `, + '.env': outdent` + WAS_SENSITIVE= # @public + WAS_PUBLIC= # @sensitive + `, + }, + expectSensitive: { + WAS_SENSITIVE: false, WAS_PUBLIC: true, + }, + })); + describe('dynamic @sensitive', () => { test('dynamic @sensitive works', envFilesTest({ envFile: outdent` @@ -54,6 +93,17 @@ describe('@sensitive and @defaultSensitive tests', () => { TRUE: true, FALSE: false, UNDEF: true, }, })); + + test('dynamic @public works', envFilesTest({ + envFile: outdent` + TRUE= # @public=if(yes) + FALSE= # @public=if(0) + UNDEF= # @public=if(true, undefined) # uses default + `, + expectSensitive: { + TRUE: false, FALSE: true, UNDEF: true, + }, + })); }); describe('inferFromPrefix() - use key prefix to infer sensitivity', () => {