|
1 | 1 | // Imports |
2 | | -import fs from 'fs' |
3 | | -import path, { resolve } from 'path' |
4 | | -import { createRequire } from 'module' |
5 | | -import { startCase } from 'lodash-es' |
6 | | -import locales from '../src/i18n/locales.json' |
7 | | -import pageToApi from '../src/data/page-to-api.json' |
| 2 | +import fs from 'node:fs/promises' |
| 3 | +import path from 'node:path' |
8 | 4 | import type { Plugin } from 'vite' |
9 | | -import { rimraf } from 'rimraf' |
10 | | -import { mkdirp } from 'mkdirp' |
11 | 5 |
|
12 | | -const API_ROOT = resolve('../api-generator/dist/api') |
13 | | -const API_PAGES_ROOT = resolve('./node_modules/.cache/api-pages') |
14 | | - |
15 | | -const require = createRequire(import.meta.url) |
16 | | - |
17 | | -const sections = ['props', 'events', 'slots', 'exposed', 'sass', 'argument', 'modifiers', 'value'] as const |
18 | | -// This can't be imported from the api-generator because it mixes the type definitions up |
19 | | -type Data = { |
20 | | - displayName: string // user visible name used in page titles |
21 | | - fileName: string // file name for translation strings and generated types |
22 | | - pathName: string // kebab-case name for use in urls |
23 | | -} & Record<typeof sections[number], Record<string, any>> |
24 | | - |
25 | | -const localeList = locales |
26 | | - .filter(item => item.enabled) |
27 | | - .map(item => item.alternate || item.locale) |
28 | | - |
29 | | -function genApiLinks (componentName: string, header: string) { |
30 | | - const section = ['<promoted-entry />', '<api-search />'] |
31 | | - const links = (Object.keys(pageToApi) as (keyof typeof pageToApi)[]) |
32 | | - .filter(page => pageToApi[page].includes(componentName)) |
33 | | - .reduce<string[]>((acc, href) => { |
34 | | - const name = href.split('/')[1] |
35 | | - acc.push(`- [${startCase(name)}](/${href})`) |
36 | | - return acc |
37 | | - }, []) |
38 | | - |
39 | | - if (links.length && header) { |
40 | | - section.unshift(...[links.join('\n'), `## ${header} {#links}`]) |
41 | | - } |
42 | | - |
43 | | - return `${section.join('\n\n')}\n\n` |
44 | | -} |
45 | | - |
46 | | -function genFrontMatter (component: string) { |
47 | | - const fm = [ |
48 | | - `title: ${component} API`, |
49 | | - `description: API for the ${component} component.`, |
50 | | - `keywords: ${component}, api, vuetify`, |
51 | | - ] |
52 | | - |
53 | | - return `---\nmeta:\n${fm.map(s => ' ' + s).join('\n')}\n---` |
54 | | -} |
55 | | - |
56 | | -function genHeader (componentName: string) { |
57 | | - const header = [ |
58 | | - genFrontMatter(componentName), |
59 | | - `# ${componentName} API`, |
60 | | - '<page-features />', |
61 | | - ] |
62 | | - |
63 | | - return `${header.join('\n\n')}\n\n` |
64 | | -} |
65 | | - |
66 | | -const sanitize = (str: string) => str.replace(/\$/g, '') |
67 | | - |
68 | | -async function loadMessages (locale: string) { |
69 | | - const prefix = path.resolve('./src/i18n/messages/') |
70 | | - const fallback = require(path.join(prefix, 'en.json')) |
71 | | - |
72 | | - try { |
73 | | - const messages = require(path.join(prefix, `${locale}.json`)) |
74 | | - |
75 | | - return { |
76 | | - ...fallback['api-headers'], |
77 | | - ...(messages['api-headers'] || {}), |
78 | | - } |
79 | | - } catch (err) { |
80 | | - return fallback['api-headers'] |
81 | | - } |
82 | | -} |
83 | | - |
84 | | -async function createMdFile (component: Data, locale: string) { |
85 | | - const messages = await loadMessages(locale) |
86 | | - let str = '' |
87 | | - |
88 | | - str += genHeader(component.displayName) |
89 | | - str += genApiLinks(component.displayName, messages.links) |
90 | | - |
91 | | - for (const section of sections) { |
92 | | - if (Object.keys(component[section] ?? {}).length) { |
93 | | - str += `## ${messages[section]} {#${section}}\n\n` |
94 | | - str += `<api-section name="${component.fileName}" section="${section}" />\n\n` |
95 | | - } |
96 | | - } |
97 | | - |
98 | | - return str |
99 | | -} |
100 | | - |
101 | | -async function writeFile (componentApi: Data, locale: string) { |
102 | | - if (!componentApi?.fileName) return |
103 | | - |
104 | | - const folder = resolve(API_PAGES_ROOT, locale, 'api') |
105 | | - |
106 | | - if (!fs.existsSync(folder)) { |
107 | | - fs.mkdirSync(folder, { recursive: true }) |
108 | | - } |
109 | | - |
110 | | - fs.writeFileSync(resolve(folder, `${sanitize(componentApi.pathName)}.md`), await createMdFile(componentApi, locale)) |
111 | | -} |
112 | | - |
113 | | -function getApiData () { |
114 | | - const files = fs.readdirSync(API_ROOT) |
115 | | - const data: Data[] = [] |
116 | | - |
117 | | - for (const file of files) { |
118 | | - const obj = JSON.parse(fs.readFileSync(resolve(API_ROOT, file), 'utf-8')) |
119 | | - |
120 | | - data.push(obj) |
121 | | - } |
122 | | - |
123 | | - return data |
124 | | -} |
125 | | - |
126 | | -async function generateFiles () { |
127 | | - // const api: Record<string, any>[] = getCompleteApi(localeList) |
128 | | - const api = getApiData() |
129 | | - |
130 | | - for (const locale of localeList) { |
131 | | - // const pages = {} as Record<string, any> |
132 | | - |
133 | | - for (const item of api) { |
134 | | - await writeFile(item, locale) |
135 | | - |
136 | | - // pages[`/${locale}/api/${sanitize(kebabCase(item.name))}/`] = item.name |
137 | | - } |
138 | | - |
139 | | - // fs.writeFileSync(resolve(API_PAGES_ROOT, `${locale}/pages.json`), JSON.stringify(pages, null, 2)) |
140 | | - fs.writeFileSync(resolve(API_PAGES_ROOT, `${locale}.js`), `export default require.context('./${locale}/api', true, /\\.md$/)`) |
141 | | - } |
142 | | - |
143 | | - // for (const item of api) { |
144 | | - // writeData(item.name, item) |
145 | | - // } |
146 | | - |
147 | | - // fs.writeFileSync(resolve(API_PAGES_ROOT, 'sass.json'), JSON.stringify([ |
148 | | - // ...api.filter(item => item && item.sass && item.sass.length > 0).map(item => item.name), |
149 | | - // ])) |
150 | | -} |
| 6 | +const API_ROOT = path.resolve('../api-generator/dist/api') |
151 | 7 |
|
152 | 8 | export default function Api (): Plugin { |
153 | 9 | return { |
154 | 10 | name: 'vuetify:api', |
155 | 11 | enforce: 'pre', |
156 | | - async config () { |
157 | | - await rimraf(API_PAGES_ROOT) |
158 | | - await mkdirp(API_PAGES_ROOT) |
| 12 | + resolveId (id) { |
| 13 | + return id === 'virtual:api-list' ? '\0' + id : undefined |
| 14 | + }, |
| 15 | + async load (id) { |
| 16 | + if (id === '\0virtual:api-list') { |
| 17 | + const files = await fs.readdir(API_ROOT) |
| 18 | + |
| 19 | + const names = files |
| 20 | + .sort((a, b) => a.localeCompare(b)) |
| 21 | + .map(file => `'${file.split('.')[0]}'`) |
| 22 | + .join(', ') |
159 | 23 |
|
160 | | - await generateFiles() |
| 24 | + return `export default [${names}]` |
| 25 | + } |
161 | 26 | }, |
162 | 27 | } |
163 | 28 | } |
0 commit comments