Skip to content

Commit

Permalink
don't generate individual api pages
Browse files Browse the repository at this point in the history
  • Loading branch information
KaelWD committed Aug 7, 2024
1 parent c363026 commit 482d0aa
Show file tree
Hide file tree
Showing 13 changed files with 151 additions and 171 deletions.
167 changes: 16 additions & 151 deletions packages/docs/build/api-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,163 +1,28 @@
// Imports
import fs from 'fs'
import path, { resolve } from 'path'
import { createRequire } from 'module'
import { startCase } from 'lodash-es'
import locales from '../src/i18n/locales.json'
import pageToApi from '../src/data/page-to-api.json'
import fs from 'node:fs/promises'
import path from 'node:path'
import type { Plugin } from 'vite'
import { rimraf } from 'rimraf'
import { mkdirp } from 'mkdirp'

const API_ROOT = resolve('../api-generator/dist/api')
const API_PAGES_ROOT = resolve('./node_modules/.cache/api-pages')

const require = createRequire(import.meta.url)

const sections = ['props', 'events', 'slots', 'exposed', 'sass', 'argument', 'modifiers', 'value'] as const
// This can't be imported from the api-generator because it mixes the type definitions up
type Data = {
displayName: string // user visible name used in page titles
fileName: string // file name for translation strings and generated types
pathName: string // kebab-case name for use in urls
} & Record<typeof sections[number], Record<string, any>>

const localeList = locales
.filter(item => item.enabled)
.map(item => item.alternate || item.locale)

function genApiLinks (componentName: string, header: string) {
const section = ['<promoted-entry />', '<api-search />']
const links = (Object.keys(pageToApi) as (keyof typeof pageToApi)[])
.filter(page => pageToApi[page].includes(componentName))
.reduce<string[]>((acc, href) => {
const name = href.split('/')[1]
acc.push(`- [${startCase(name)}](/${href})`)
return acc
}, [])

if (links.length && header) {
section.unshift(...[links.join('\n'), `## ${header} {#links}`])
}

return `${section.join('\n\n')}\n\n`
}

function genFrontMatter (component: string) {
const fm = [
`title: ${component} API`,
`description: API for the ${component} component.`,
`keywords: ${component}, api, vuetify`,
]

return `---\nmeta:\n${fm.map(s => ' ' + s).join('\n')}\n---`
}

function genHeader (componentName: string) {
const header = [
genFrontMatter(componentName),
`# ${componentName} API`,
'<page-features />',
]

return `${header.join('\n\n')}\n\n`
}

const sanitize = (str: string) => str.replace(/\$/g, '')

async function loadMessages (locale: string) {
const prefix = path.resolve('./src/i18n/messages/')
const fallback = require(path.join(prefix, 'en.json'))

try {
const messages = require(path.join(prefix, `${locale}.json`))

return {
...fallback['api-headers'],
...(messages['api-headers'] || {}),
}
} catch (err) {
return fallback['api-headers']
}
}

async function createMdFile (component: Data, locale: string) {
const messages = await loadMessages(locale)
let str = ''

str += genHeader(component.displayName)
str += genApiLinks(component.displayName, messages.links)

for (const section of sections) {
if (Object.keys(component[section] ?? {}).length) {
str += `## ${messages[section]} {#${section}}\n\n`
str += `<api-section name="${component.fileName}" section="${section}" />\n\n`
}
}

return str
}

async function writeFile (componentApi: Data, locale: string) {
if (!componentApi?.fileName) return

const folder = resolve(API_PAGES_ROOT, locale, 'api')

if (!fs.existsSync(folder)) {
fs.mkdirSync(folder, { recursive: true })
}

fs.writeFileSync(resolve(folder, `${sanitize(componentApi.pathName)}.md`), await createMdFile(componentApi, locale))
}

function getApiData () {
const files = fs.readdirSync(API_ROOT)
const data: Data[] = []

for (const file of files) {
const obj = JSON.parse(fs.readFileSync(resolve(API_ROOT, file), 'utf-8'))

data.push(obj)
}

return data
}

async function generateFiles () {
// const api: Record<string, any>[] = getCompleteApi(localeList)
const api = getApiData()

for (const locale of localeList) {
// const pages = {} as Record<string, any>

for (const item of api) {
await writeFile(item, locale)

// pages[`/${locale}/api/${sanitize(kebabCase(item.name))}/`] = item.name
}

// fs.writeFileSync(resolve(API_PAGES_ROOT, `${locale}/pages.json`), JSON.stringify(pages, null, 2))
fs.writeFileSync(resolve(API_PAGES_ROOT, `${locale}.js`), `export default require.context('./${locale}/api', true, /\\.md$/)`)
}

// for (const item of api) {
// writeData(item.name, item)
// }

// fs.writeFileSync(resolve(API_PAGES_ROOT, 'sass.json'), JSON.stringify([
// ...api.filter(item => item && item.sass && item.sass.length > 0).map(item => item.name),
// ]))
}
const API_ROOT = path.resolve('../api-generator/dist/api')

export default function Api (): Plugin {
return {
name: 'vuetify:api',
enforce: 'pre',
async config () {
await rimraf(API_PAGES_ROOT)
await mkdirp(API_PAGES_ROOT)
resolveId (id) {
return id === 'virtual:api-list' ? '\0' + id : undefined
},
async load (id) {
if (id === '\0virtual:api-list') {
const files = await fs.readdir(API_ROOT)

const names = files
.sort((a, b) => a.localeCompare(b))
.map(file => `'${file.split('.')[0]}'`)
.join(', ')

await generateFiles()
return `export default [${names}]`
}
},
}
}
2 changes: 2 additions & 0 deletions packages/docs/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ declare module 'vue' {
AboutTeamMembers: typeof import('./src/components/about/TeamMembers.vue')['default']
Alert: typeof import('./src/components/Alert.vue')['default']
ApiApiTable: typeof import('./src/components/api/ApiTable.vue')['default']
ApiBacklinks: typeof import('./src/components/api/Backlinks.vue')['default']
ApiDirectiveTable: typeof import('./src/components/api/DirectiveTable.vue')['default']
ApiEventsTable: typeof import('./src/components/api/EventsTable.vue')['default']
ApiExposedTable: typeof import('./src/components/api/ExposedTable.vue')['default']
Expand All @@ -23,6 +24,7 @@ declare module 'vue' {
ApiSearch: typeof import('./src/components/api/Search.vue')['default']
ApiSection: typeof import('./src/components/api/Section.vue')['default']
ApiSlotsTable: typeof import('./src/components/api/SlotsTable.vue')['default']
ApiView: typeof import('./src/components/api/View.vue')['default']
AppBackToTop: typeof import('./src/components/app/BackToTop.vue')['default']
AppBarBar: typeof import('./src/components/app/bar/Bar.vue')['default']
AppBarEcosystemMenu: typeof import('./src/components/app/bar/EcosystemMenu.vue')['default']
Expand Down
3 changes: 3 additions & 0 deletions packages/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,13 @@
"vuetify": "workspace:*"
},
"devDependencies": {
"@babel/generator": "^7.25.0",
"@babel/types": "^7.25.2",
"@emailjs/browser": "^4.3.3",
"@intlify/unplugin-vue-i18n": "^4.0.0",
"@mdi/js": "7.4.47",
"@mdi/svg": "7.4.47",
"@types/babel__generator": "^7.6.8",
"@types/lodash-es": "^4.17.12",
"@types/markdown-it": "^14.0.0",
"@types/markdown-it-container": "^2.0.10",
Expand Down
34 changes: 34 additions & 0 deletions packages/docs/src/components/api/Backlinks.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<template>
<div class="mb-4 d-flex flex-column">
<div v-for="link in links" :key="link.name">
<AppLink :href="link.href">{{ link.name }}</AppLink>
</div>
</div>
</template>

<script setup lang="ts">
import pageToApi from '@/data/page-to-api.json'
const props = defineProps({
name: {
type: String,
required: true,
},
})
const route = useRoute()
const router = useRouter()
const links = computed(() => {
return Object.keys(pageToApi)
.filter(page => pageToApi[page].includes(props.name))
.map(page => {
const resolved = router.resolve('/' + route.meta.locale + '/' + page)
const name = resolved.meta.nav ?? page.split('/').at(-1)
return {
name,
href: resolved.href,
}
})
})
</script>
1 change: 0 additions & 1 deletion packages/docs/src/components/api/Inline.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
<ApiSection
:name="name"
:section="section"
show-headline
/>
</template>
</div>
Expand Down
3 changes: 1 addition & 2 deletions packages/docs/src/components/api/Section.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
@input="filter = $event"
/>
</div> -->
<AppHeadline v-if="showHeadline" :path="`api-headers.${section}`" />
<AppHeadline :path="`api-headers.${section}`" />
<TableComponent :items="items" :name="name" />
</div>
</template>
Expand Down Expand Up @@ -45,7 +45,6 @@
type: String as PropType<PartKey>,
required: true,
},
showHeadline: Boolean,
})
const store = useLocaleStore()
Expand Down
35 changes: 35 additions & 0 deletions packages/docs/src/components/api/View.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script setup lang="ts">
import type { PartData } from '@vuetify/api-generator/src/types'
const emit = defineEmits(['update:name'])
const sections = ['props', 'events', 'slots', 'exposed', 'sass', 'argument', 'modifiers', 'value'] as const
const route = useRoute()
const name = computed(() => {
const name = route.params.name as string
if (name.endsWith('-directive')) return name.replace('-directive', '')
else if (name.startsWith('use-')) return camelCase(name)
else return `${name.charAt(0).toUpperCase()}${camelize(name.slice(1))}`
})
const component = shallowRef<any>({})
watch(name, async () => {
emit('update:name', name.value)
component.value = await getApi(name.value)
}, { immediate: true })
function getApi (name: string): Promise<{ default: PartData }> {
return import(`../../../../api-generator/dist/api/${name}.json`).then(m => m.default)
}
</script>

<template>
<template v-for="section of sections" :key="section">
<ApiSection
v-if="section in component && Object.keys(component[section]).length"
:name="name"
:section="section"
/>
</template>
</template>
23 changes: 12 additions & 11 deletions packages/docs/src/components/app/list/List.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@

<script setup lang="ts">
// Types
import type { RouteLocationRaw, RouteRecordRaw } from 'vue-router'
import type { RouteLocationRaw } from 'vue-router'
import type { Prop } from 'vue'
import apiList from 'virtual:api-list'
export type Item = {
title?: string
Expand All @@ -81,15 +82,13 @@
}
function generateApiItems (locale: string) {
return (generatedRoutes as RouteRecordRaw[])
.filter(route => route.path.includes(`${locale}/api/`))
.map(route => {
return {
title: (route.meta!.title as string).slice(0, -4),
to: route.path,
}
})
.sort((a, b) => a.title.localeCompare(b.title))
return apiList.map(name => {
const path = kebabCase(name.startsWith('v-') ? name + '-directive' : name)
return {
title: name,
to: `/${locale}/api/${path}`,
}
})
}
function generateListItem (item: string | Item, path = '', locale = 'en', t = (key: string) => key): any {
Expand Down Expand Up @@ -170,7 +169,9 @@
onClick: item?.onClick,
rel: item.href ? 'noopener noreferrer' : undefined,
target: item.href ? '_blank' : undefined,
children: item.title === 'api' ? generateApiItems(locale.value) : generateListItems(item, item.title!, locale.value, t),
children: item.title === 'api'
? generateApiItems(locale.value)
: generateListItems(item, item.title!, locale.value, t),
prependIcon: opened.value.includes(title ?? '') ? item.activeIcon : item.inactiveIcon,
value: title,
appendIcon: item.appendIcon,
Expand Down
8 changes: 3 additions & 5 deletions packages/docs/src/components/doc/Explorer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
<ApiSection
:name="model"
:section="section"
show-headline
/>
</template>
</template>
Expand All @@ -56,15 +55,14 @@
</template>

<script setup>
import files from 'virtual:api-list'
const route = useRoute()
const router = useRouter()
const files = import.meta.glob('../../../../api-generator/dist/api/*.json')
const search = shallowRef()
const components = Object.keys(files).reduce((acc, cur) => {
const name = cur.split('/').pop().split('.')[0]
const components = files.reduce((acc, name) => {
let prependIcon
let subtitle
Expand Down
Loading

0 comments on commit 482d0aa

Please sign in to comment.