catalog.json during build that contains component props, composables, and tokens. The solidprofessor-packages skill reads this for accurate documentation. Zero developer effort required.
Adding or modifying components requires no extra steps. The catalog is generated automatically from source code during the build process.
The solidprofessor-packages skill contains a manually-maintained list of components with their props. This creates two problems:
We want accurate prop documentation without any manual maintenance.
<button)Detection patterns rarely change (how often do we add totally new component categories?). They're easier to maintain as a simple table in the shelf skill than as JSON that devs would need to remember to update.
{
"name": "@solidprofessorhub/shared-components",
"version": "1.29.3",
"generatedAt": "2026-10-21T15:30:00Z",
"components": {
"BaseButton": {
"props": {
"variant": {
"type": "'primary' | 'secondary' | 'ghost' | 'danger' | 'link' | 'icon'",
"required": false,
"default": "'primary'"
},
"size": {
"type": "'default' | 'small' | 'xs'",
"required": false,
"default": "'default'"
},
"loading": {
"type": "boolean",
"required": false,
"default": "false"
},
"icon": {
"type": "string",
"required": false
},
"to": {
"type": "string | RouteLocationRaw",
"required": false,
"description": "Vue Router path - renders as router-link"
},
"href": {
"type": "string",
"required": false,
"description": "External link - renders as anchor"
}
}
},
"TextField": {
"props": {
"modelValue": { "type": "string", "required": true },
"label": { "type": "string", "required": true },
"error": { "type": "string", "required": false },
"type": { "type": "string", "default": "'text'" },
"size": { "type": "'default' | 'small'" }
}
}
// ... all other components auto-extracted
},
"composables": {
"useModal": {
"returns": ["isOpen", "open", "close"]
},
"useForm": {
"returns": ["values", "errors", "validate", "reset"]
},
"useFormModal": {
"returns": ["isOpen", "open", "close", "submit"]
}
},
"utilities": ["cn", "getBaseUrl", "getUrlWithQueryParameters"],
"icons": {
"tokenSet": ["angle-down", "angle-up", "arrow-left", "arrow-right", "ellipsis", "magnifying-glass", "plus", "xmark", "eye", "eye-slash"]
},
"tokens": {
"colors": {
"neutral-0": "#FFFFFF",
"neutral-5": "#F9FAFB",
"neutral-10": "#F3F5F7",
"neutral-50": "#606D80",
"neutral-90": "#121A26",
"primary-50": "#479E5B",
"primary-60": "#2D833F",
"primary-70": "#1E6C2E"
// ... extracted from theme.css
}
}
}
// scripts/generate-catalog.ts
// Uses vue-component-meta to extract props from Vue SFCs
import { createComponentMetaChecker } from 'vue-component-meta'
import { readFileSync, writeFileSync } from 'fs'
import { globSync } from 'glob'
import { resolve } from 'path'
import pkg from '../package.json'
// 1. Set up the Vue component meta checker
const checker = createComponentMetaChecker(
resolve(__dirname, '../tsconfig.json')
)
// 2. Find all Vue components
const componentFiles = globSync('src/components/**/*.vue', {
cwd: resolve(__dirname, '..')
})
// 3. Extract props from each component
const components: Record<string, any> = {}
for (const file of componentFiles) {
const fullPath = resolve(__dirname, '..', file)
const meta = checker.getComponentMeta(fullPath)
// Skip internal components (not exported)
if (meta.name.startsWith('_')) continue
components[meta.name] = {
props: Object.fromEntries(
meta.props
.filter(p => !p.global) // Skip global props like class, style
.map(p => [p.name, {
type: p.type,
required: p.required,
default: p.default,
description: p.description
}])
)
}
}
// 4. Extract composables from index.ts exports
const composables = extractComposablesFromIndex()
// 5. Extract utilities
const utilities = extractUtilitiesFromIndex()
// 6. Extract icon token set from BaseIcon
const icons = extractIconTokens()
// 7. Extract design tokens from theme.css
const tokens = extractTokensFromCSS('src/styles/theme.css')
// 8. Build the catalog
const catalog = {
name: pkg.name,
version: pkg.version,
generatedAt: new Date().toISOString(),
components,
composables,
utilities,
icons,
tokens
}
// 9. Write to dist/
writeFileSync(
resolve(__dirname, '../dist/catalog.json'),
JSON.stringify(catalog, null, 2)
)
console.log(`✓ Generated catalog.json for ${pkg.name}@${pkg.version}`)
console.log(` ${Object.keys(components).length} components`)
console.log(` ${Object.keys(composables).length} composables`)
console.log(` ${Object.keys(tokens.colors || {}).length} color tokens`)
// package.json
{
"scripts": {
"build": "vite build && npm run generate-catalog",
"generate-catalog": "tsx scripts/generate-catalog.ts"
},
"files": [
"dist" // catalog.json included automatically
],
"devDependencies": {
"vue-component-meta": "^2.0.0",
"tsx": "^4.0.0"
}
}
The existing release workflow runs npm run build, which now includes catalog generation. No changes to CI/CD needed.
Instead of hardcoded prop lists, the skill reads from the installed package:
# In SKILL.md
## Component Documentation
For accurate, up-to-date component props, read the catalog:
```bash
cat node_modules/@solidprofessorhub/shared-components/dist/catalog.json
```
Use `components[name].props` for prop details.
Use `composables` for available composables.
Use `tokens.colors` for design token values.
Shelf keeps its detection patterns as simple tables in the SKILL.md. No changes needed.
| Skill | Uses catalog.json? | What for |
|---|---|---|
solidprofessor-packages |
Yes | Component props, composables, tokens |
shelf |
No | Keeps detection patterns in skill (stable, rarely change) |
| Scenario | Before | After |
|---|---|---|
| Add new component | Update skill with props | Nothing — auto-extracted |
| Add/change props | Update skill with new props | Nothing — auto-extracted |
| Add new composable | Update skill with exports | Nothing — auto-extracted |
| Add design token | Update skill with value | Nothing — auto-extracted from CSS |
| Add icon to BaseIcon token set | Update both skills | Nothing — auto-extracted |
If you add a completely new component category that shelf should detect (rare), add one row to shelf's detection table. Example: if we add a Toast component and want to detect hand-rolled toasts.
| Step | Task | Effort |
|---|---|---|
| 1 | Add vue-component-meta and tsx to devDependencies |
5 min |
| 2 | Create scripts/generate-catalog.ts |
2-3 hours |
| 3 | Test locally: npm run generate-catalog |
30 min |
| 4 | Add to build script in package.json | 5 min |
| 5 | Publish new version (catalog.json included) | Normal release |
| 6 | Update solidprofessor-packages skill to read from catalog | 30 min |