npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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 id to each schema node (root, properties, nested objects, array items).
  • Tuple Arrays: Emits prefixItems for TypeScript tuple props (JSON Schema tuple validation).
  • Literal Inference: Emits const for 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 typescript and vue-component-meta as 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.