{"_id":"whenexpr","_rev":"4-f3cc1052946c75b7c0e07ef842d75b75","name":"whenexpr","dist-tags":{"latest":"0.1.2"},"versions":{"0.0.0":{"name":"whenexpr","version":"0.0.0","keywords":[],"author":{"name":"Anthony Fu","email":"anthonyfu117@hotmail.com"},"license":"MIT","_id":"whenexpr@0.0.0","maintainers":[{"name":"antfu","email":"anthonyfu117@hotmail.com"}],"homepage":"https://github.com/antfu/whenexpr#readme","bugs":{"url":"https://github.com/antfu/whenexpr/issues"},"dist":{"shasum":"542fcca5f61455539aa05e9e0ede2456ed53e303","tarball":"https://registry.npmjs.org/whenexpr/-/whenexpr-0.0.0.tgz","fileCount":5,"integrity":"sha512-99uZI8Sk3DzFSzBSfCwAxckTP9O+NAtFcVX/yIjDb9x8Cp9Aflx5jKFSUrCXR5yf1INpPluEe2nyx9rqZal1Kg==","signatures":[{"sig":"MEYCIQDQt7KAWAUpr/HTYF95xVG3jelwpMN4M7rAkkRVpQ5p8QIhAPDBknW9Mpiqv1HwCvmykNSp0KEgsPpIoGg9OPNlmCSM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":4925},"main":"./dist/index.mjs","type":"module","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs","./package.json":"./package.json"},"funding":"https://github.com/sponsors/antfu","scripts":{"dev":"tsdown --watch","lint":"eslint","test":"vitest","build":"tsdown","start":"tsx src/index.ts","prepare":"simple-git-hooks","release":"bumpp","typecheck":"tsc","prepublishOnly":"nr build"},"_npmUser":{"name":"antfu","email":"anthonyfu117@hotmail.com"},"repository":{"url":"git+https://github.com/antfu/whenexpr.git","type":"git"},"_npmVersion":"11.6.2","description":"When experssion","directories":{},"lint-staged":{"*":"eslint --fix"},"sideEffects":false,"_nodeVersion":"24.12.0","_hasShrinkwrap":false,"packageManager":"pnpm@10.33.0","devDependencies":{"tsx":"catalog:cli","vite":"catalog:cli","bumpp":"catalog:cli","eslint":"catalog:cli","tsdown":"catalog:cli","tsnapi":"catalog:testing","vitest":"catalog:testing","publint":"catalog:cli","@antfu/ni":"catalog:cli","typescript":"catalog:cli","@types/node":"catalog:types","lint-staged":"catalog:cli","@antfu/utils":"catalog:inlined","simple-git-hooks":"catalog:cli","@antfu/eslint-config":"catalog:cli"},"simple-git-hooks":{"pre-commit":"pnpm i --frozen-lockfile --ignore-scripts --offline && pnpm run build && npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/whenexpr_0.0.0_1776907437781_0.6775487621534855","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"whenexpr","version":"0.1.1","keywords":["when","when-clause","expression","evaluator","vscode"],"author":{"name":"Anthony Fu","email":"anthonyfu117@hotmail.com"},"license":"MIT","_id":"whenexpr@0.1.1","maintainers":[{"name":"antfu","email":"anthonyfu117@hotmail.com"}],"homepage":"https://github.com/antfu/whenexpr#readme","bugs":{"url":"https://github.com/antfu/whenexpr/issues"},"dist":{"shasum":"e2d8a4b02159a5939f872883d9d359ab1ee6e1d2","tarball":"https://registry.npmjs.org/whenexpr/-/whenexpr-0.1.1.tgz","fileCount":5,"integrity":"sha512-XlXvh9+xXLIOqR/ZYISaUz3e1D+Pzr/9rlej7rsCoyhi0QGxQVosbMoK2DgGD3Kf8zlD7QljPGw5qZNCu7YMyg==","signatures":[{"sig":"MEUCIGyEqm4yxOgAJoq4gZJAHPdoZBLiiZibI5u5zX2gcjoXAiEA5GZNekm+xCcd6z2DiUPwd2/+Et2EwROf6/F9IDTKsV0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/whenexpr@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":22904},"main":"./dist/index.mjs","type":"module","_from":"file:whenexpr-0.1.1.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs","./package.json":"./package.json"},"funding":"https://github.com/sponsors/antfu","scripts":{"dev":"tsdown --watch","lint":"eslint","test":"vitest","build":"tsdown","start":"tsx src/index.ts","release":"bumpp","typecheck":"tsc"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1292be9a-e5ce-429c-91c4-b3453539193d"}},"_resolved":"/tmp/4a6db8702b4183e5f9a74894c6d83321/whenexpr-0.1.1.tgz","_integrity":"sha512-XlXvh9+xXLIOqR/ZYISaUz3e1D+Pzr/9rlej7rsCoyhi0QGxQVosbMoK2DgGD3Kf8zlD7QljPGw5qZNCu7YMyg==","repository":{"url":"git+https://github.com/antfu/whenexpr.git","type":"git"},"_npmVersion":"11.12.1","description":"Tiny when-clause expression evaluator, inspired by VS Code's when clauses","directories":{},"lint-staged":{"*":"eslint --fix"},"sideEffects":false,"_nodeVersion":"24.15.0","_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","vite":"^8.0.8","bumpp":"^11.0.1","eslint":"^10.2.0","tsdown":"^0.17.3","tsnapi":"^0.1.1","vitest":"^4.1.4","publint":"^0.3.18","@antfu/ni":"^30.0.0","typescript":"^6.0.2","@types/node":"^25.6.0","lint-staged":"^16.4.0","@antfu/utils":"^9.3.0","simple-git-hooks":"^2.13.1","@antfu/eslint-config":"^8.1.1"},"simple-git-hooks":{"pre-commit":"pnpm i --frozen-lockfile --ignore-scripts --offline && pnpm run build && npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/whenexpr_0.1.1_1776911237660_0.5823908312517263","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"whenexpr","version":"0.1.0","keywords":[],"author":{"name":"Anthony Fu","email":"anthonyfu117@hotmail.com"},"license":"MIT","_id":"whenexpr@0.1.0","maintainers":[{"name":"antfu","email":"anthonyfu117@hotmail.com"}],"homepage":"https://github.com/antfu/whenexpr#readme","bugs":{"url":"https://github.com/antfu/whenexpr/issues"},"dist":{"shasum":"cfb15b86799ad5055d10e8b9454cec92b537c68e","tarball":"https://registry.npmjs.org/whenexpr/-/whenexpr-0.1.0.tgz","fileCount":5,"integrity":"sha512-I9AVdUJxZBwhqMrrpGou05fjwzgvwYbaCcCkuK/YLo6Lr6oNc4M9gqkpmp90SwqbtgET3Z8oGivaiIg0LarWfg==","signatures":[{"sig":"MEYCIQDwSIv1LeceAE2jv5AhUt2XE4oi1JIaqAZmHffyYCjUnwIhAM3XE/EN61v6g2vMCrYba6Qqb5I3a56oh5xgS65kM7kr","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/whenexpr@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":4739},"main":"./dist/index.mjs","type":"module","_from":"file:whenexpr-0.1.0.tgz","types":"./dist/index.d.mts","module":"./dist/index.mjs","exports":{".":"./dist/index.mjs","./package.json":"./package.json"},"funding":"https://github.com/sponsors/antfu","scripts":{"dev":"tsdown --watch","lint":"eslint","test":"vitest","build":"tsdown","start":"tsx src/index.ts","release":"bumpp","typecheck":"tsc"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1292be9a-e5ce-429c-91c4-b3453539193d"}},"_resolved":"/tmp/f649271ba90f707d9039d8e78e15388b/whenexpr-0.1.0.tgz","_integrity":"sha512-I9AVdUJxZBwhqMrrpGou05fjwzgvwYbaCcCkuK/YLo6Lr6oNc4M9gqkpmp90SwqbtgET3Z8oGivaiIg0LarWfg==","repository":{"url":"git+https://github.com/antfu/whenexpr.git","type":"git"},"_npmVersion":"11.12.1","description":"When experssion","directories":{},"lint-staged":{"*":"eslint --fix"},"sideEffects":false,"_nodeVersion":"24.15.0","_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.21.0","vite":"^8.0.8","bumpp":"^11.0.1","eslint":"^10.2.0","tsdown":"^0.17.3","tsnapi":"^0.1.1","vitest":"^4.1.4","publint":"^0.3.18","@antfu/ni":"^30.0.0","typescript":"^6.0.2","@types/node":"^25.6.0","lint-staged":"^16.4.0","@antfu/utils":"^9.3.0","simple-git-hooks":"^2.13.1","@antfu/eslint-config":"^8.1.1"},"simple-git-hooks":{"pre-commit":"pnpm i --frozen-lockfile --ignore-scripts --offline && pnpm run build && npx lint-staged"},"_npmOperationalInternal":{"tmp":"tmp/whenexpr_0.1.0_1776911240797_0.37055150590808483","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"whenexpr","type":"module","version":"0.1.2","description":"Tiny when-clause expression evaluator, inspired by VS Code's when clauses","author":{"name":"Anthony Fu","email":"anthonyfu117@hotmail.com"},"license":"MIT","funding":"https://github.com/sponsors/antfu","homepage":"https://github.com/antfu/whenexpr#readme","repository":{"type":"git","url":"git+https://github.com/antfu/whenexpr.git"},"bugs":{"url":"https://github.com/antfu/whenexpr/issues"},"keywords":["when","when-clause","expression","evaluator","vscode"],"sideEffects":false,"exports":{".":"./dist/index.mjs","./package.json":"./package.json"},"types":"./dist/index.d.mts","devDependencies":{"@antfu/eslint-config":"^8.1.1","@antfu/ni":"^30.0.0","@antfu/utils":"^9.3.0","@types/node":"^25.6.0","bumpp":"^11.0.1","eslint":"^10.2.0","lint-staged":"^16.4.0","publint":"^0.3.18","simple-git-hooks":"^2.13.1","tsdown":"^0.21.9","tsdown-stale-guard":"^0.1.1","tsnapi":"^0.3.2","tsx":"^4.21.0","typescript":"^6.0.2","vite":"^8.0.8","vitest":"^4.1.4"},"simple-git-hooks":{"pre-commit":"pnpm i --frozen-lockfile --ignore-scripts --offline && pnpm run build && npx lint-staged"},"lint-staged":{"*":"eslint --fix"},"scripts":{"build":"tsdown","dev":"tsdown --watch","lint":"eslint","release":"bumpp","start":"tsx src/index.ts","test":"pnpm run build && vitest","typecheck":"tsc"},"_id":"whenexpr@0.1.2","_integrity":"sha512-VVSufnKy206AoAYrxiZ0xof2nx0fqHCFYi7Ox/kAn7azSHsEc4geVlENPb4Nq8mKKlYPRKQrgIQbjrWldMvGCg==","_resolved":"/tmp/9f2cad0e1d457c991a32eec52f7b9baf/whenexpr-0.1.2.tgz","_from":"file:whenexpr-0.1.2.tgz","_nodeVersion":"24.14.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-VVSufnKy206AoAYrxiZ0xof2nx0fqHCFYi7Ox/kAn7azSHsEc4geVlENPb4Nq8mKKlYPRKQrgIQbjrWldMvGCg==","shasum":"236cf18049e38ef864ae8c27d4e62e11f7470b62","tarball":"https://registry.npmjs.org/whenexpr/-/whenexpr-0.1.2.tgz","fileCount":5,"unpackedSize":38761,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/whenexpr@0.1.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCbM2r/qN43ml0lFtNCRw4opL4lIYzDVPVW4qzDxraS5gIhAJ08EM4t3/1X/z/CxSZQ4I451xwR8gWcDK25ar6BycH6"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1292be9a-e5ce-429c-91c4-b3453539193d"}},"directories":{},"maintainers":[{"name":"antfu","email":"anthonyfu117@hotmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/whenexpr_0.1.2_1776919759360_0.9289509782947662"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-23T01:23:57.780Z","modified":"2026-04-23T04:49:19.831Z","0.0.0":"2026-04-23T01:23:57.917Z","0.1.1":"2026-04-23T02:27:17.817Z","0.1.0":"2026-04-23T02:27:20.946Z","0.1.2":"2026-04-23T04:49:19.510Z"},"bugs":{"url":"https://github.com/antfu/whenexpr/issues"},"author":{"name":"Anthony Fu","email":"anthonyfu117@hotmail.com"},"license":"MIT","homepage":"https://github.com/antfu/whenexpr#readme","keywords":["when","when-clause","expression","evaluator","vscode"],"repository":{"type":"git","url":"git+https://github.com/antfu/whenexpr.git"},"description":"Tiny when-clause expression evaluator, inspired by VS Code's when clauses","maintainers":[{"name":"antfu","email":"anthonyfu117@hotmail.com"}],"readme":"# whenexpr\n\n[![npm version][npm-version-src]][npm-version-href]\n[![npm downloads][npm-downloads-src]][npm-downloads-href]\n[![bundle][bundle-src]][bundle-href]\n[![JSDocs][jsdocs-src]][jsdocs-href]\n[![License][license-src]][license-href]\n\nA tiny, zero-dependency evaluator for **when-clause expressions** — a mini expression language for conditionally enabling UI, commands, and features based on a context object.\n\nInspired by [VS Code's when clause contexts](https://code.visualstudio.com/api/references/when-clause-contexts).\n\n**Type-safe**: expression strings are statically validated against your context type at the call site. Typos and unknown keys surface as TypeScript errors before the code runs.\n\n## Install\n\n```sh\npnpm add whenexpr\n```\n\n## Usage\n\n```ts\nimport { evaluateWhen } from 'whenexpr'\n\ninterface Context {\n  mode: 'development' | 'production'\n  debug: boolean\n  verbose: boolean\n}\n\nconst ctx: Context = {\n  mode: 'development',\n  debug: true,\n  verbose: false,\n}\n\nevaluateWhen('debug && mode == development', ctx) // true\nevaluateWhen('verbose || mode == production', ctx) // false\nevaluateWhen('!verbose', ctx) // true\n\n// Typos are caught at compile time:\nevaluateWhen('degub && mode == development', ctx)\n//           ^^^^^^^ Type error: Unknown context key: \"degub\"\n```\n\n## Expression Syntax\n\nwhenexpr supports a JavaScript-expression subset: logical, equality, relational, and arithmetic operators, plus parentheses for grouping.\n\n### Literals\n\n| Kind    | Example                |\n| ------- | ---------------------- |\n| Boolean | `true`, `false`        |\n| Number  | `42`, `1.5`            |\n| String  | `\"dev\"`, `'dev'`       |\n\n### Operators\n\n| Category   | Operators                        | Example                       |\n| ---------- | -------------------------------- | ----------------------------- |\n| Unary      | `!`, `-`, `+`                    | `!verbose`, `-x`              |\n| Logical    | `&&`, `\\|\\|`                     | `debug && !verbose`           |\n| Equality   | `==`, `!=`, `===`, `!==`         | `mode == development`, `x === 1` |\n| Relational | `<`, `<=`, `>`, `>=`             | `x >= 10`                     |\n| Arithmetic | `+`, `-`, `*`, `/`, `%`          | `a + b * c`                   |\n| Grouping   | `( … )`                          | `(a \\|\\| b) && c`             |\n\n### Precedence (low to high)\n\n`||` → `&&` → equality → relational → `+` `-` → `*` `/` `%` → unary → primary\n\n### `==` vs `===` semantics\n\n- **`==` / `!=`** follow the original VS Code when-clause idiom: the right-hand side is a single value token (bare identifier, quoted string, number, or boolean), compared as a string.\n  ```ts\n  evaluateWhen('mode == development', { mode: 'development' }) // true\n  evaluateWhen('count == 5', { count: 5 }) // true — stringified\n  ```\n\n- **`===` / `!==`** follow JavaScript strict equality. Both sides are full expressions.\n  ```ts\n  evaluateWhen('x === 1', { x: 1 }) // true\n  evaluateWhen('x === 1', { x: '1' }) // false — no coercion\n  ```\n\n### Examples\n\n```ts\n// Conditional UI visibility\nevaluateWhen('debug && !verbose', ctx)\n\n// Either/or\nevaluateWhen('mode == development || mode == staging', ctx)\n\n// Arithmetic + strict comparison\nevaluateWhen('(((a || b) && c) + foo) === 1', {\n  a: false,\n  b: true,\n  c: true,\n  foo: 0,\n}) // true\n\n// Ranges\nevaluateWhen('x >= 10 && x < 100', { x: 42 }) // true\n```\n\n## Namespaced Context Keys\n\nKeys can be namespaced using `.` or `:` separators to avoid collisions between unrelated features or plugins:\n\n```ts\n// Flat keys (recommended)\nconst ctx = {\n  'vite.mode': 'development',\n  'vite:buildMode': 'lib',\n}\n\n// Nested objects (also supported)\nconst ctx = {\n  vite: { mode: 'development', ssr: true },\n}\n```\n\nBoth styles work in expressions:\n\n```ts\nevaluateWhen('vite.mode == development', ctx)\nevaluateWhen('vite:buildMode == lib', ctx)\nevaluateWhen('vite.ssr', ctx)\n```\n\n### Lookup Order\n\nWhen resolving a namespaced key like `vite.mode`:\n\n1. **Exact match** — looks for `ctx['vite.mode']` first\n2. **Nested path** — falls back to `ctx.vite?.mode`\n\nFlat keys take priority over nested objects if both exist.\n\n## Type Safety\n\nWhen `ctx` is typed with known keys, `evaluateWhen` parses and validates the expression string **in the TypeScript type system**. Unknown keys and syntax errors become type errors at the call site — no runtime check needed, no `strict` flag to remember.\n\n```ts\ninterface Context {\n  mode: 'development' | 'production'\n  debug: boolean\n  editor: { lang: string }\n}\ndeclare const ctx: Context\n\nevaluateWhen('debug && mode == development', ctx) // ok\nevaluateWhen('editor.lang == ts', ctx) // ok — nested path\nevaluateWhen('debug || unknownKey', ctx)\n//                     ^^^^^^^^^^ Unknown context key: \"unknownKey\"\nevaluateWhen('debug &&& verbose', ctx)\n//           ^^^^^^^^^^^^^^^^^^^^ Syntax error\n```\n\n### Levels of checking\n\nValidation is layered so you pay only for what you need:\n\n| `ctx` type | `expression` | Syntax check | Key check |\n| ---------- | ------------ | :----------: | :-------: |\n| Specific (`interface Ctx { … }`) | literal | ✓ | ✓ |\n| Wide (`object`, `{}`, `Record<string, unknown>`, `any`, `unknown`) | literal | ✓ | — |\n| anything | `string` variable | — | — |\n\nSo a wide context still catches `(unbalanced` or `debug &&& verbose` — you just don't need to enumerate every key. And a dynamic `string` expression opts out entirely.\n\n```ts\nconst loose: Record<string, unknown> = {}\nevaluateWhen('anything && at-all', loose) // ok — keys not checked\nevaluateWhen('(unbalanced', loose) // type error: syntax\n\nconst expr: string = loadExprFromDisk()\nevaluateWhen(expr, ctx) // ok — no validation at all\n```\n\n### Building your own typed `define` helpers\n\nLibraries that expose `defineCommand`, `defineAction`, etc. can carry the validation into their own APIs with the `WhenExpression<Ctx, S>` helper:\n\n```ts\nimport type { WhenExpression } from 'whenexpr'\n\ninterface AppCtx {\n  mode: 'dev' | 'prod'\n  debug: boolean\n}\n\nfunction defineCommand<const W extends string>(cmd: {\n  name: string\n  title: string\n  when?: WhenExpression<AppCtx, W>\n}): typeof cmd {\n  return cmd\n}\n\ndefineCommand({ name: 'toggle', title: 'Toggle', when: 'debug && mode == dev' })\ndefineCommand({ name: 'x', title: 'X', when: 'typo' })\n//                                            ^^^^^^ type error\n```\n\nThe `const W extends string` captures the literal so `WhenExpression` can validate it. Runtime behavior is unchanged — the helper is purely a type.\n\n## API\n\n### `evaluateWhen(expression, ctx, options?)`\n\nEvaluate a when-clause expression against a context object. Returns `boolean`.\n\n```ts\nfunction evaluateWhen<T extends object, const E extends string>(\n  expression: E & ValidateExpression<E, T>,\n  ctx: T,\n  options?: { strict?: boolean },\n): boolean\n```\n\nThe `ValidateExpression<E, T>` in the signature is what performs static checking — see [Type Safety](#type-safety) above.\n\n#### Strict mode\n\nBy default, unknown context keys evaluate to `undefined` (falsy). Pass `{ strict: true }` to throw an error instead — useful for catching typos or stale expressions during development:\n\n```ts\nevaluateWhen('unknownKey', {}, { strict: true })\n// → Error: Unknown context key: \"unknownKey\"\n```\n\nShort-circuit evaluation still applies, so keys that aren't reached are not checked:\n\n```ts\n// `debug` is truthy, so `unknownKey` is never evaluated — no throw\nevaluateWhen('debug || unknownKey', { debug: true }, { strict: true })\n```\n\n### `parse(expression)` and `evaluate(node, ctx, options?)`\n\nUnder the hood, `evaluateWhen` is `evaluate(parse(expression), ctx, options)`. You can split the two steps to avoid re-parsing when the same expression is evaluated against many contexts:\n\n```ts\nimport { evaluate, parse } from 'whenexpr'\n\nconst node = parse('debug && mode == development')\n\nevaluate(node, { debug: true, mode: 'development' }) // true\nevaluate(node, { debug: true, mode: 'production' }) // false\n```\n\n`parse` returns a `WhenNode` — a discriminated union you can also inspect or transform:\n\n```ts\ntype WhenNode\n  = | { type: 'literal', value: boolean | number | string }\n    | { type: 'key', key: string }\n    | { type: 'unary', op: UnaryOp, operand: WhenNode }\n    | { type: 'binary', op: BinaryOp, left: WhenNode, right: WhenNode }\n\ntype UnaryOp = '!' | '-' | '+'\n\ntype BinaryOp\n  = | '||' | '&&'\n    | '==' | '!=' | '===' | '!=='\n    | '<' | '>' | '<=' | '>='\n    | '+' | '-' | '*' | '/' | '%'\n```\n\n### `resolveContextValue(key, ctx)`\n\nResolve a single context key (including namespaced keys) from the context object. Returns `unknown`, or `undefined` if the key is not found.\n\n```ts\nfunction resolveContextValue<T extends Record<string, unknown>>(\n  key: string,\n  ctx: T,\n): unknown\n```\n\n### Type helpers\n\n| Type | Purpose |\n| ---- | ------- |\n| `WhenExpression<T, S>` | Branded expression type for use in your own `define`-style helpers (see [Type Safety](#building-your-own-typed-define-helpers)). |\n| `ValidateExpression<S, T>` | Lower-level: returns `S` on success, `WhenExpressionError<Msg>` on failure. |\n| `WhenExpressionError<Msg>` | Branded error string. Assignability failure surfaces `Msg` in the TS tooltip. |\n| `ContextPaths<T>` | Union of valid flat + `.`/`:` nested paths for `T`. |\n\n## Sponsors\n\n<p align=\"center\">\n  <a href=\"https://cdn.jsdelivr.net/gh/antfu/static/sponsors.svg\">\n    <img src=\"https://cdn.jsdelivr.net/gh/antfu/static/sponsors.svg\" alt=\"Sponsors\"/>\n  </a>\n</p>\n\n## License\n\n[MIT](./LICENSE) License © [Anthony Fu](https://github.com/antfu)\n\n<!-- Badges -->\n\n[npm-version-src]: https://img.shields.io/npm/v/whenexpr?style=flat&colorA=080f12&colorB=1fa669\n[npm-version-href]: https://npmx.dev/package/whenexpr\n[npm-downloads-src]: https://img.shields.io/npm/dm/whenexpr?style=flat&colorA=080f12&colorB=1fa669\n[npm-downloads-href]: https://npmx.dev/package/whenexpr\n[bundle-src]: https://img.shields.io/bundlephobia/minzip/whenexpr?style=flat&colorA=080f12&colorB=1fa669&label=minzip\n[bundle-href]: https://bundlephobia.com/result?p=whenexpr\n[license-src]: https://img.shields.io/github/license/antfu/whenexpr.svg?style=flat&colorA=080f12&colorB=1fa669\n[license-href]: https://github.com/antfu/whenexpr/blob/main/LICENSE\n[jsdocs-src]: https://img.shields.io/badge/jsdocs-reference-080f12?style=flat&colorA=080f12&colorB=1fa669\n[jsdocs-href]: https://www.jsdocs.io/package/whenexpr\n","readmeFilename":"README.md"}