mirror of
https://git.hmsn.ink/kospo/svcm/dmz.git
synced 2026-03-20 00:32:23 +09:00
first
This commit is contained in:
157
scripts/generate-component-meta.ts
Normal file
157
scripts/generate-component-meta.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
/// <reference types="node" />
|
||||
|
||||
import { join, basename } from 'node:path'
|
||||
import { readdir, lstat, writeFile } from 'node:fs/promises'
|
||||
|
||||
import type {
|
||||
MetaCheckerOptions,
|
||||
EventMeta,
|
||||
PropertyMeta,
|
||||
ExposeMeta,
|
||||
SlotMeta,
|
||||
} from 'vue-component-meta'
|
||||
import { createCheckerByJson } from 'vue-component-meta'
|
||||
|
||||
const checkerOptions: MetaCheckerOptions = {
|
||||
forceUseTs: true,
|
||||
schema: false,
|
||||
printer: { newLine: 1 },
|
||||
}
|
||||
|
||||
type Checker = ReturnType<typeof createCheckerByJson>
|
||||
async function main() {
|
||||
const root = process.cwd()
|
||||
const tsconfig = join(root, './tsconfig.json')
|
||||
const componentDir = join(root, './src/components/')
|
||||
const out = join(root, './src/data/documentation/components-meta.ts')
|
||||
|
||||
const checker = createCheckerByJson(root, {
|
||||
extends: tsconfig,
|
||||
}, checkerOptions)
|
||||
|
||||
const components: Record<string, any> = {}
|
||||
const directories = ['base', 'base-addons', 'layouts']
|
||||
await Promise.all(
|
||||
directories.map(dir => walk(components, checker, join(componentDir, dir))),
|
||||
)
|
||||
|
||||
const sorted: Record<string, any> = {}
|
||||
Object.keys(components).sort().forEach((key) => {
|
||||
sorted[key] = components[key]
|
||||
})
|
||||
|
||||
const content = [
|
||||
`/* eslint-disable */`,
|
||||
`// This file is auto generated by scripts/generate-component-meta.ts`,
|
||||
`import type { ComponentMeta } from 'vue-component-meta'`,
|
||||
``,
|
||||
`export const components = ${JSON.stringify(
|
||||
Object.keys(sorted),
|
||||
)} as const`,
|
||||
``,
|
||||
...Object.entries(sorted).map(([name, meta]) => {
|
||||
return `export const ${name}Meta: ComponentMeta = ${JSON.stringify(
|
||||
meta,
|
||||
)} as const`
|
||||
}),
|
||||
].join('\n')
|
||||
|
||||
await writeFile(out, content)
|
||||
}
|
||||
|
||||
async function walk(
|
||||
components: Record<string, any>,
|
||||
checker: Checker,
|
||||
dir: string,
|
||||
) {
|
||||
const files = await readdir(dir)
|
||||
for (const file of files) {
|
||||
const path = join(dir, file)
|
||||
const stat = await lstat(path)
|
||||
if (stat.isDirectory()) {
|
||||
await walk(components, checker, path) // recursive
|
||||
}
|
||||
|
||||
const isVueFile = path.endsWith('.vue')
|
||||
if (!isVueFile) continue
|
||||
|
||||
const name = basename(path, '.vue')
|
||||
const meta = await extractMeta(checker, path)
|
||||
components[name] = meta
|
||||
}
|
||||
}
|
||||
|
||||
async function extractMeta(checker: Checker, path: string) {
|
||||
const metaFields = checker.getComponentMeta(path)
|
||||
const meta = {
|
||||
type: metaFields.type,
|
||||
props: metaFields.props.filter(field => !field.global),
|
||||
events: metaFields.events,
|
||||
exposed: metaFields.exposed.filter((field) => {
|
||||
const isProps
|
||||
= metaFields.props?.findIndex(prop => prop.name === field.name) >= 0
|
||||
const isEvent
|
||||
= metaFields.events?.findIndex(
|
||||
(event: any) =>
|
||||
`on${event.name}`.toLowerCase() === field.name?.toLowerCase(),
|
||||
) >= 0
|
||||
const isExcluded = field.name?.startsWith('$')
|
||||
const isModel = field.name === 'modelValue'
|
||||
|
||||
return !(isProps || isEvent || isExcluded || isModel)
|
||||
}),
|
||||
slots: metaFields.slots,
|
||||
}
|
||||
|
||||
meta.props.forEach(field => cleanMeta(field))
|
||||
meta.events.forEach(field => cleanMeta(field))
|
||||
meta.slots.forEach(field => cleanMeta(field))
|
||||
meta.exposed.forEach(field => cleanMeta(field))
|
||||
|
||||
meta.props.sort((a, b) => {
|
||||
// sort required properties first
|
||||
if (!a.required && b.required) {
|
||||
return 1
|
||||
}
|
||||
if (a.required && !b.required) {
|
||||
return -1
|
||||
}
|
||||
// then ensure boolean properties are sorted last
|
||||
if (a.type === 'boolean' && b.type !== 'boolean') {
|
||||
return 1
|
||||
}
|
||||
if (a.type !== 'boolean' && b.type === 'boolean') {
|
||||
return -1
|
||||
}
|
||||
|
||||
return a.name.localeCompare(b.name)
|
||||
})
|
||||
meta.events.sort((a, b) => a.name.localeCompare(b.name))
|
||||
meta.slots.sort((a, b) => a.name.localeCompare(b.name))
|
||||
meta.exposed.sort((a, b) => a.name.localeCompare(b.name))
|
||||
|
||||
return meta
|
||||
}
|
||||
|
||||
function cleanMeta(field: EventMeta | PropertyMeta | ExposeMeta | SlotMeta) {
|
||||
if ('schema' in field) {
|
||||
// @ts-expect-error can't be undefined
|
||||
delete field.schema
|
||||
|
||||
if ('signature' in field) {
|
||||
field.schema = []
|
||||
}
|
||||
else {
|
||||
field.schema = ''
|
||||
}
|
||||
}
|
||||
|
||||
if ('declarations' in field) {
|
||||
// @ts-expect-error can't be undefined
|
||||
delete field.declarations
|
||||
|
||||
field.declarations = []
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error)
|
||||
Reference in New Issue
Block a user