When Clauses
When clauses gate visibility and executability of docks, commands, and UI surfaces via VS Code's when-clause contexts. The evaluator whenexpr re-exports at devframe/utils/when.
Usage
On commands
Gates palette visibility and shortcuts.
ctx.commands.register({
id: 'my-devtool:embedded-only',
title: 'Embedded-Only Action',
when: 'clientType == embedded',
handler: async () => { /* … */ },
})On dock entries
Gates dock-bar visibility.
ctx.docks.register({
id: 'my-devtool:inspector',
title: 'Inspector',
type: 'action',
icon: 'ph:cursor-duotone',
when: 'clientType == embedded',
action: { importFrom: 'my-devtool/inspector' },
})Render-only visibility on dock entries
A dock entry also takes visibility, a second expression that hides only its dock-bar button while keeping the entry registered and reachable (e.g. a subTabs anchor).
ctx.docks.register({
id: 'my-devtool:anchor',
title: 'My Devtool',
type: 'iframe',
icon: 'ph:squares-four-duotone',
url: '/__my-devtool/',
subTabs: { protocol: 'postmessage' },
visibility: 'false', // hide the anchor's own button; its tabs still render
})Expression syntax
Operators
| Category | Operators | Example |
|---|---|---|
| Bare truthy | identifier | dockOpen |
| Literals | true, false, numbers, strings | 42, 'dev' |
| Unary | !, -, + | !paletteOpen |
| Logical | &&, || | dockOpen && !paletteOpen |
| Equality | ==, !=, ===, !== | clientType == embedded |
| Relational | <, <=, >, >= | count >= 10 |
| Arithmetic | +, -, *, /, % | (a + b) * c |
| Grouping | ( … ) | (a || b) |
Precedence (low → high)
|| → && → equality → relational → + - → * / % → unary → primary.
== vs ===
==/!=— VS Code idiom; RHS a single token, compared as a string.===/!==— JS strict equality; full expressions both sides, no coercion.
evaluateWhen('clientType == embedded', ctx) // string-style
evaluateWhen('count === 1', { count: 1 }) // true
evaluateWhen('count === 1', { count: '1' }) // falseExamples
when: 'true' // always visible
when: 'false' // never visible
when: 'clientType == embedded' // only embedded
when: 'dockOpen && !paletteOpen' // dock open and palette closed
when: '(clientType == embedded && dockOpen) || clientType == standalone'
when: 'my-devtool.ready' // custom plugin contextBuilt-in context variables
| Variable | Type | Description |
|---|---|---|
clientType | 'embedded' | 'standalone' | embedded in the host overlay, standalone in a separate window. |
dockOpen | boolean | Dock panel open. |
paletteOpen | boolean | Command palette open. |
dockSelectedId | string | Selected dock entry ID; '' if none. |
Namespaced context keys
Plugins add keys with . or ::
context['my-devtool.ready'] = true
context['my-devtool:step'] = 'build'
context.myDevtool = { ready: true, step: 'build' } // nested formwhen: 'my-devtool.ready'
when: 'my-devtool:step == build'
when: 'myDevtool.ready'Lookup order
Resolves the exact key ctx['my-devtool.ready'] first, then nested ctx['my-devtool']?.ready; flat wins.
Type-safe when clauses
defineCommand and defineDockEntry type-check when: against WhenContext.
import { defineCommand } from 'devframe'
defineCommand({
id: 'my-devtool:toggle',
title: 'Toggle',
when: 'dockOpen && !paletteOpen', // ✓ ok
handler: async () => {},
})
defineCommand({
id: 'my-devtool:broken',
title: 'Broken',
when: 'dockOpen &&& !paletteOpen',
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Type error: syntax error
handler: async () => {},
})Key validation with plugin contexts
The default WhenContext leaves plugin keys open-ended ([key: string]: unknown). To validate names, declare a narrower context and wrapper:
import type { WhenContext, WhenExpression } from 'devframe/utils/when'
interface MyPluginContext extends Omit<WhenContext, keyof any> {
'clientType': 'embedded' | 'standalone'
'dockOpen': boolean
'paletteOpen': boolean
'dockSelectedId': string
'my-devtool.ready': boolean
}
function defineMyCommand<const W extends string>(cmd: {
id: string
title: string
when?: WhenExpression<MyPluginContext, W>
handler: (...args: any[]) => Promise<unknown>
}): typeof cmd {
return cmd
}
defineMyCommand({
id: 'my-devtool:toggle',
title: 'Toggle',
when: 'my-devtool.ready && dockOpen', // ✓ ok
handler: async () => {},
})
defineMyCommand({
id: 'my-devtool:broken',
title: 'Broken',
when: 'my-devtool.read', // ← typo
// ^^^^^^^^^^^^^^^^^^^ Type error: Unknown context key
handler: async () => {},
})API reference
import type { WhenContext } from 'devframe/utils/when'
import { evaluateWhen, resolveContextValue } from 'devframe/utils/when'
const ctx: WhenContext = {
'clientType': 'embedded',
'dockOpen': true,
'paletteOpen': false,
'dockSelectedId': 'my-dock',
'my-devtool.ready': true,
}
evaluateWhen('dockOpen && my-devtool.ready', ctx) // true
evaluateWhen('clientType == standalone', ctx) // false
resolveContextValue('my-devtool.ready', ctx) // trueevaluateWhen(expression, ctx, options?)
Returns boolean; { strict: true } throws on unknown keys.
resolveContextValue(key, ctx)
Returns one (possibly namespaced) key's value.
WhenExpression<Ctx, S>
The branded whenexpr expression type for typed define* helpers (above).