@cyia/vscode-valibot-config
v1.0.8
Published
VSCode configuration manager based on Valibot schemas
Maintainers
Readme
@cyia/vscode-valibot-config
VSCode configuration manager based on Valibot schemas. Provides reactive signals that automatically sync with VS Code's workspace settings, with built-in validation and real-time update support.
Features
- Schema Validation: Define configuration structure using Valibot schemas
- Reactive Signals: Configuration values are exposed as writable signals with automatic change detection
- Deep Nesting: Full support for nested object configurations
- Real-time Updates: Automatically listens to VS Code configuration changes
- JSON Schema Export: Generate VSCode-compatible JSON Schema from Valibot schemas
- Type Safety: End-to-end TypeScript type inference from schema definitions
- Deep Equality: Uses deep comparison to prevent unnecessary signal updates
- Union & Variant Support: Handles complex union types and discriminated unions
Installation
npm install @cyia/vscode-valibot-config
# or
pnpm add @cyia/vscode-valibot-configUsage
Basic Example
import * as v from 'valibot';
import { createConfig } from '@cyia/vscode-valibot-config';
// Define configuration schema
const configSchema = v.object({
enabled: v.boolean(),
timeout: v.pipe(v.number(), v.minValue(100), v.maxValue(5000)),
theme: v.picklist(['dark', 'light', 'auto']),
tags: v.array(v.string()),
nested: v.object({
host: v.string(),
port: v.number(),
}),
});
// Create reactive configuration
const proxy = createConfig(configSchema, 'myExtension');
const config = proxy.root();
// Read values (call as function)
console.log(config.enabled()); // true
console.log(config.timeout()); // 1000
console.log(config.nested.host()); // "localhost"
// Set values
await config.enabled.set(false);
await config.timeout.set(2000);
// Update values with function
await config.theme.update((current) => (current === 'dark' ? 'light' : 'dark'));
// Nested objects
await config.nested.set({ host: 'api.example.com', port: 8080 });Signal API
Each configuration property returns a signal with the following methods:
| Method | Description |
| ------------------- | ---------------------------------------- |
| signal() | Get current value |
| signal.set(value) | Set new value (updates VS Code settings) |
| signal.update(fn) | Update using previous value |
JSON Schema Generation
Convert Valibot schemas to VSCode contributes.configuration.properties format:
import * as v from 'valibot';
import { valibotToVscodeConfig } from '@cyia/vscode-valibot-config';
import { asVirtualGroup } from '@piying/valibot-visit';
const schema = v.object({
name: v.pipe(v.string(), v.description('The user name')),
role: v.pipe(
v.picklist(['admin', 'user']),
v.metadata({
enumOptions: [
{ label: 'Administrator', description: 'Full access' },
{ label: 'Regular User', description: 'Limited access' },
],
}),
),
});
const jsonSchema = valibotToVscodeConfig(schema, {
title: 'My Extension Config',
prefix: 'myExtension',
id: 'myExtension.schema.json',
order: 1,
});Writing to package.json
Use writePackageJsonConfig to automatically write configuration into your VS Code extension's package.json file:
import * as v from 'valibot';
import { writePackageJsonConfig } from '@cyia/vscode-valibot-config';
const schema = v.object({
apiKey: v.string(),
maxRetries: v.pipe(v.number(), v.minValue(1), v.maxValue(10)),
});
// Write to file
const writer = writePackageJsonConfig(schema, {
title: 'My Extension Config',
prefix: 'myExtension',
});
await writer('./package.json');
// The generated package.json will automatically add:
// "contributes": {
// "configuration": {
// "title": "My Extension Config",
// "properties": {
// "myExtension.apiKey": { "type": "string" },
// "myExtension.maxRetries": { "type": "number" }
// }
// }
// }
// Or manipulate the object directly
const packageJson = {
name: 'my-extension',
contributes: {} as any,
};
writer(packageJson);Advanced Options
Using metadata for Enhanced UI
const schema = v.object({
mode: v.pipe(
v.picklist(['fast', 'balanced', 'quality']),
v.metadata({
isOptional: true,
enumOptions: [
{ label: 'Fast', description: 'Best performance' },
{ label: 'Balanced', description: 'Balanced trade-off' },
{ label: 'Quality', description: 'Best output quality' },
],
}),
),
});Virtual Groups
Objects inside intersect are merged, allowing nested merging:
import { asVirtualGroup } from '@piying/valibot-visit';
const schema = v.object({
network: v.pipe(
v.intersect([
v.object({ proxy: v.string() }),
v.object({ timeout: v.number() }),
]),
asVirtualGroup(),
),
});