@demsking/vue-jsonschema
v1.3.0
Published
Convert Vue component props to JSON Schema
Readme
Vue JSON Schema Generator
A production-ready library to extract JSON Schema from Vue 3 component props. Supports Composition API (<script setup>), Options API, and TypeScript.
Features
- Deep Parsing: Extracts types, default values, enums, and required status.
- Deterministic IDs: Adds a stable
idto each schema node (root, properties, nested objects, array items). - Tuple Arrays: Emits
prefixItemsfor TypeScript tuple props (JSON Schema tuple validation). - Literal Inference: Emits
constfor resolved TypeScript literal values (including generic literal substitutions). - TypeScript Support: Handles complex TypeScript types, including imported types.
- JSDoc Support: Maps JSDoc comments (description, @default, @example) to JSON Schema fields.
- Custom Keywords: Support for
@pattern,@min,@max,@minLength,@maxLength, etc. - Vite Plugin: Generate JSON Schemas on the fly using a custom query (
?schema).
Installation
npm install vue-jsonschema[!NOTE] This library requires
typescriptandvue-component-metaas peer dependencies. Ensure they are installed in your project.
Usage
Library
import { VueComponentParser } from 'vue-jsonschema';
const parser = new VueComponentParser('path/to/tsconfig.json');
const schema = parser.getComponentSchema('path/to/MyComponent.vue');
console.log(JSON.stringify(schema, null, 2));Configuration
Both the library and the Vite plugin accept a ParserOptions object:
| Prop | Type | Description |
| :--------------------- | :---------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------- |
| tsconfigPath | string | Required. Path to your tsconfig.json. |
| ignoreProps | string[] | List of props to skip (e.g., ['key', 'ref']). |
| customTags | Array<string \| { name: string; onSchemaParsed?: (componentPath, parent, rawValue) => boolean \| void }> | Extra JSDoc tags and optional schema handlers. |
| definePropsFunctions | string[] | Prop macro names to parse. Defaults to ['defineProps']; when set, it replaces the default list (e.g. ['defineSchemaProps']). |
| schemaTypeWrappers | string[] | Type wrappers whose generic argument is parsed as props when no macro call exists (e.g. MyCustomNamespace.DefineSchema<T>). |
| schemaTypeWrapperIgnoreProps | string[] | Prop names to skip as JSON Schema when parsing schema type wrappers; their raw value is still passed to matching custom tag handlers. |
| opaqueTypeNames | string[] | Type names to treat as opaque JSON objects (skip deep schema parsing), e.g. JsonSchema, JSONSchema7. |
| idSeparator | string | Separator used when generating schema node IDs. Default: ".". |
When the parser needs transformed .vue temp files, it uses TMPDIR / TEMP / TMP (fallback: /tmp) and falls back to local temp files when relative imports are detected.
Examples
Ignoring Props
const parser = new VueComponentParser({
tsconfigPath: './tsconfig.json',
ignoreProps: ['internalId', 'debugMode'],
});Custom JSDoc Tags
If you use custom JSDoc tags that you want included in the schema:
const parser = new VueComponentParser({
tsconfigPath: './tsconfig.json',
customTags: ['ui:widget', 'ui:options'],
});These tags will be added to the schema under their respective names.
[!NOTE] Custom tag keys are emitted using the exact casing from the component JSDoc tag. Repeated custom tags are emitted as arrays in declaration order.
Ignore Fields In Schema Type Wrappers
If you parse props from wrapper types and need to skip specific fields:
const parser = new VueComponentParser({
tsconfigPath: './tsconfig.json',
schemaTypeWrappers: ['MyCustomNamespace.DefineSchema'],
schemaTypeWrapperIgnoreProps: ['internal', 'secret'],
});This omits internal and secret from the generated schema when they come from wrapper-derived props.
Custom Tag Schema Handlers
You can attach transformation handlers to custom tags. This lets you parse/transform a custom tag schema or its parent node.
Inside schema-like helper types, you can use keys such as $type and $i18nContext and map them with onSchemaParsed:
type TranslationField<T extends { context: string }> = {
$type: 'string';
$i18nContext: {
const: {
description: T['context'];
};
};
};const parser = new VueComponentParser({
tsconfigPath: './tsconfig.json',
customTags: [
{
name: '$type',
onSchemaParsed: (componentPath, parent, rawValue) => {
if (
parent &&
(typeof rawValue === 'string' ||
(Array.isArray(rawValue) &&
rawValue.every((item) => typeof item === 'string')))
) {
// e.g. use componentPath for per-component rules
if (!componentPath.endsWith('.vue')) return;
parent.type = rawValue;
return true; // consume the $type property
}
},
},
],
});This is emitted as:
{
"type": "string",
"$i18nContext": {
"description": "The morning greeting message"
}
}JSDoc Mapping
The following tags are automatically mapped to JSON Schema fields:
| JSDoc Tag | JSON Schema Field |
| :---------------------- | :---------------- |
| @title | title |
| @description | description |
| @default | default |
| @example | example |
| @pattern | pattern |
| @step / @multipleOf | multipleOf |
| @minimum / @min | minimum |
| @maximum / @max | maximum |
| @minLength | minLength |
| @maxLength | maxLength |
| @minItems | minItems |
| @maxItems | maxItems |
Vite Plugin
Add it to your vite.config.ts:
import vue from '@vitejs/plugin-vue';
import { defineConfig } from 'vite';
import { vueJsonSchemaPlugin } from 'vue-jsonschema/vite-plugin';
export default defineConfig({
plugins: [
vue(),
vueJsonSchemaPlugin({
tsconfigPath: './tsconfig.json', // optional, defaults to tsconfig.json
}),
],
});Usage
// vite.config.ts
import { defineConfig } from 'vite';
import { vueJsonschema } from 'vue-jsonschema';
export default defineConfig({
plugins: [
vueJsonschema({
// Path to your tsconfig.json (required)
tsconfigPath: './tsconfig.json',
// Props to ignore (optional)
ignoreProps: ['metricsName'],
// Custom JSDoc tags to include (optional)
customTags: ['ui:widget', 'ui:options'],
}),
],
});The plugin will automatically generate a JSON schema file for each Vue component in your project. The schema file will be named <Component>.schema.json and placed in the same directory as the component.
JSDoc Tags Support
The following JSDoc tags are supported and mapped to JSON Schema fields:
| JSDoc Tag | JSON Schema Field | Description |
| :--------------------- | :------------------ | :------------------------------------------ |
| @default | default | Default value |
| @example | example | Example value |
| @examples | examples | List of example values (JSON array) |
| @const | const | Constant value |
| @readonly | readOnly | Read-only property |
| @writeonly | writeOnly | Write-only property |
| @comment | $comment | Comment for schema maintainers |
| @minimum, @min | minimum | Minimum numeric value |
| @maximum, @max | maximum | Maximum numeric value |
| @multipleOf, @step | multipleOf | Number must be a multiple of this value |
| @minLength | minLength | Minimum string length |
| @maxLength | maxLength | Maximum string length |
| @pattern | pattern | Regex pattern for string |
| @format | format | String format (e.g., email, uri, date-time) |
| @minItems | minItems | Minimum array items |
| @maxItems | maxItems | Maximum array items |
| @dependentRequired | dependentRequired | Dependent required properties (JSON object) |
| @dependentSchemas | dependentSchemas | Dependent schemas (JSON object) |
| @contentMediaType | contentMediaType | MIME type of string content |
| @contentEncoding | contentEncoding | Encoding of string content |
| @contentSchema | contentSchema | Schema for string content (JSON object) |
| @ignore | - | Ignore property from schema |
You can also pass custom tags to the customTags option in vite.config.ts to include them in the schema.
Example
<script setup lang="ts">
export interface Props {
/**
* The name of the user
* @default "John Doe"
* @minLength 3
*/
name?: string;
/**
* The age of the user
* @minimum 18
* @maximum 100
*/
age: number;
/**
* Status of the user
* @ignore
*/
internalStatus?: string;
}
defineProps<Props>();
</script>Then you can import the schema in your project:
import MyComponentSchema from './components/MyComponent.vue?schema';
console.log(MyComponentSchema);Type Mapping Notes
Tuple arrays use prefixItems
For tuple props like:
coordinates: [number, number, string];the generated schema uses tuple validation:
{
"type": "array",
"prefixItems": [
{ "type": "number" },
{ "type": "number" },
{ "type": "string" }
]
}Regular arrays still use items.
Generic literal substitution emits const
For generic literal object fields like:
type MessageDefinitionContext<Context extends string> = { context: Context };
hello?: MessageDefinitionContext<'Generic hello message'>;the generated field is:
{
"type": "object",
"properties": {
"context": {
"type": "string",
"const": "Generic hello message"
}
}
}License
Under the MIT license. See LICENSE file for more details.
