When Clauses
When clauses gate visibility and executability of docks, commands, and custom UI 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-rail 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-rail 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 devframe contextBuilt-in context variables
| Variable | Type | Description |
|---|---|---|
clientType | 'embedded' | 'standalone' | embedded in the host page's 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
Devframes 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 devframe contexts
The default WhenContext leaves devframe 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).
Terms
The canonical vocabulary of these docs: one name per concept, the API or package that anchors it, and how the pieces talk to each other.
Events Reference
Devframe carries change notifications across channels of differing direction and reach: a node event bus, server RPC, and server-pushed broadcasts and shared state.