Skip to content
orin-dxPublic

About

React component props, extracted from TypeScript in Rust with OXC. No TypeScript compiler and no type-check pass. CLI, Vite plugin and Node bindings.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

1,446 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

caliper, an Orin DX tool

Fast React component prop extraction. Parses TypeScript with OXC, no type-checking pass.

CI License


caliper-docgen reads your components and reports each one's props: type, required or optional, default, and JSDoc. It is a faster alternative to react-docgen-typescript for Storybook, docs sites, and LLM tooling.

react-docgen-typescript builds a full TypeScript Program, which takes seconds on a mid-size design system. Caliper parses files in parallel with OXC and skips the type checker.

On whole libraries (Mantine, Chakra, Ant Design, shadcn/ui and React Spectrum at pinned commits, source only), Caliper takes 34 to 81ms and is 17 to 39 times faster than react-docgen-typescript on the same files, a median of 22 times. CI checks this weekly (docs/performance.md). Recall and agreement with react-docgen-typescript on installed repos are in docs/measurement.md.

A component through Caliper

interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
  /** Visual style. */
  variant?: 'default' | 'destructive' | 'outline'
  loading?: boolean
}

export function Button({ variant = 'default', loading, ...rest }: ButtonProps) {
  return <button data-variant={variant} aria-busy={loading} {...rest} />
}
caliper-docgen extract --src src --format rdt
Prop Type Required Default Description
variant "default" | "destructive" | "outline" no "default" Visual style.
loading boolean no

By default all of an element's inherited HTML attributes are exposed (what react-docgen-typescript does); --html-attributes curated keeps a compact subset, none none. --format canonical is the tool's own shape, rdt matches react-docgen-typescript, and toon is a compact format for LLM agents.

%%{init: {'theme': 'base', 'flowchart': {'curve': 'basis', 'nodeSpacing': 40, 'rankSpacing': 56}, 'themeVariables': {'fontFamily': 'Inter, ui-sans-serif, system-ui, sans-serif', 'fontSize': '14px', 'lineColor': '#94a3b8', 'edgeLabelBackground': '#ffffff'}}}%%
flowchart LR
    classDef source fill:#eef2ff,stroke:#6366f1,stroke-width:1.5px,color:#1e1b4b,rx:10px,ry:10px,font-weight:600;
    classDef engine fill:#f5f3ff,stroke:#8b5cf6,stroke-width:1.5px,color:#4c1d95,rx:10px,ry:10px;
    classDef output fill:#ecfdf5,stroke:#10b981,stroke-width:1.5px,color:#064e3b,rx:10px,ry:10px,font-weight:600;

    files["<b>.tsx / .d.ts</b><br/>your source"] --> parse["<b>Parse</b><br/>OXC, in parallel"]
    parse --> merge["<b>Merge</b><br/>symbols across files"]
    merge --> resolve["<b>Resolve</b><br/>props per component"]
    resolve --> out["<b>Output</b><br/>canonical · rdt · toon"]

    class files source
    class parse,merge,resolve engine
    class out output
Loading

Caliper is pre-v1. docs/STATUS.md lists what works, and docs/edge-cases.md the known gaps. Conditional types and mapped types over an unbound generic need a real type checker, which OXC deliberately isn't.

Install

npm install --save-dev caliper-docgen                # CLI, with the prebuilt binary for your platform
npm install --save-dev caliper-docgen-vite-plugin    # Vite plugin
npm install --save-dev caliper-docgen-storybook      # Storybook 11 addon
cargo install caliper-docgen                         # CLI from crates.io

Coming from react-docgen-typescript? MIGRATING.md covers what's compatible today.

Quick start

# Extract every component under src/ to a file
caliper-docgen extract --src src --out docgen.json

# Props of one component, as a table
caliper-docgen inspect Button --src src

# Re-extract on every change
caliper-docgen watch --src src

# Fail CI on extraction errors (--strict also fails on warnings)
caliper-docgen check --src src

Settings can also live in a docgen.config.ts (srcDirs, htmlAttributes, cacheDir, and more). caliper-docgen --help lists the rest, including schema for the JSON Schema of the output.

Parsed declarations and the dependency index are cached under node_modules/.cache/caliper-docgen. --no-cache (config, NAPI, Vite and Storybook option cache: false) reads and writes nothing there; the output is the same.

Types your props import from installed packages are resolved by default: the declarations those names point to are loaded. --no-load-dependencies (config, NAPI and Vite option loadDependencies: false) leaves them as named references with an UNRESOLVABLE_IMPORT warning, and a project with no packages installed loads nothing either way. A package source contributing more than 30 props is then listed as one inherited layer with its notable props, as Storybook does; --collapse-inherited-props all does the same for the project's own sources and none lists every prop.

Vite plugin

// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { caliperDocgen } from 'caliper-docgen-vite-plugin'

export default defineConfig({
  plugins: [react(), caliperDocgen({ srcDirs: ['src'] })],
})
import docgen from 'virtual:caliper-docgen'

docgen.components['Button'].props

The module updates through HMR as components change. The virtual module is the canonical format; the injectDocgenInfo option assigns __docgenInfo in the react-docgen-typescript shape (see the plugin README).

Storybook

// .storybook/main.ts
export default {
  framework: '@storybook/react-vite',
  addons: [{ name: 'caliper-docgen-storybook', options: { srcDirs: ['src'] } }],
}

Storybook 11's docgen server then takes each component's argTypes from caliper-docgen instead of the TypeScript checker, and hands anything caliper can't document to React's own docgen. See packages/storybook.

Supported patterns

Pattern Example
Function and arrow components function Button(props: ButtonProps)
React.forwardRef forwardRef<HTMLButtonElement, ButtonProps>(...)
Wrapped components styled(Base)<ButtonProps>
Interface inheritance interface ButtonProps extends HTMLAttributes<HTMLButtonElement>
Intersections, Omit, Pick type ButtonProps = Omit<InputProps, 'value'>
ComponentPropsWithoutRef ComponentPropsWithoutRef<'button'>
VariantProps VariantProps<typeof buttonVariants> (CVA, TV, PandaCSS)
Discriminated unions variant: 'filled' | 'outlined' | 'standard'
JSDoc tags @description, @default, @deprecated, @internal

Components declared through a generic wrapper call, such as Mantine's factory<ButtonFactory>(), are recognized from their type arguments. Not recognized yet: wrapper calls with no type argument, such as lazy(). Props that come from packages that aren't installed stay unresolved and are reported as warnings. docs/edge-cases.md has the measured gaps.

Documentation

License

FSL-1.1-MIT: free for any non-competing use, and each version becomes MIT two years after its release.

About

React component props, extracted from TypeScript in Rust with OXC. No TypeScript compiler and no type-check pass. CLI, Vite plugin and Node bindings.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages