Skip to content

fix(varlock): preserve typed builtin vars referenced from root decorators#790

Merged
theoephraim merged 1 commit into
mainfrom
fix-boolean-builtin-coercion
Jun 16, 2026
Merged

fix(varlock): preserve typed builtin vars referenced from root decorators#790
theoephraim merged 1 commit into
mainfrom
fix-boolean-builtin-coercion

Conversation

@theoephraim

Copy link
Copy Markdown
Member

What

Typed builtin vars (e.g. VARLOCK_IS_CI, which is declared boolean) were being stringified to "false"/"true" when referenced from a root decorator argument such as @import(enabled=...) or a plugin's @initOp(...). Because a non-empty string is truthy, this silently broke boolean logic — e.g. not($VARLOCK_IS_CI) evaluated to false even when not in CI.

Why

registerBuiltinVar sets the builtin item's dataType correctly, but only in the "create from scratch" branch, relying on the finishLoad loop not revisiting the new key. When a builtin is registered early (during root-decorator processing), the item later does get a process() call — and since the builtin's resolver had no inferredType and the item has no @type decorator, type inference defaulted it back to string, coercing the boolean to a string.

The fix: the builtin's resolver now advertises its declared type via inferredType, so config-item type inference preserves it. One-line change in registerBuiltinVar.

Referencing the same builtin from a normal item value already worked; this only affected the early/root-decorator registration path.

Tests

Added regression tests in builtin-vars.test.ts covering a boolean builtin referenced from a root decorator (@import(enabled=not($VARLOCK_IS_CI))) in both CI and non-CI — verified they fail without the fix and pass with it. Full env-graph suite (482 tests) green.

…tors

Builtin vars like VARLOCK_IS_CI declare a type (boolean), but when registered
early via a root-decorator reference (e.g. @import/@initOp args), the finishLoad
process() pass recomputed the type and defaulted it back to 'string',
stringifying false -> "false". That made not()/if() treat it as a truthy
string. The builtin resolver now advertises its declared type via inferredType
so config-item type inference preserves it.
@github-actions

Copy link
Copy Markdown
Contributor

bumpy-frog

The changes in this PR will be included in the next version bump.

patch Patch releases

  • varlock 1.7.0 → 1.7.1

Bump files in this PR

Click here if you want to add another bump file to this PR


This comment is maintained by bumpy.

@pkg-pr-new

pkg-pr-new Bot commented Jun 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/varlock@790

commit: d44feeb

@theoephraim theoephraim merged commit e2381b7 into main Jun 16, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants