refactor: a volar types shim generator
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -104,3 +104,6 @@ tests/*/screenshots
|
|||||||
|
|
||||||
# Tests videos
|
# Tests videos
|
||||||
tests/*/videos
|
tests/*/videos
|
||||||
|
|
||||||
|
# Andrew's crazy Volar shim generator
|
||||||
|
shims-volar.d.ts
|
||||||
|
|||||||
129
modules/emit-volar-types.ts
Normal file
129
modules/emit-volar-types.ts
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
import { resolve } from "path"
|
||||||
|
import { Module } from "@nuxt/types"
|
||||||
|
import ts from "typescript"
|
||||||
|
|
||||||
|
const { readdir, writeFile } = require("fs").promises
|
||||||
|
|
||||||
|
function titleCase(str: string): string {
|
||||||
|
return str[0].toUpperCase() + str.substring(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function* getFilesInDir(dir: string): AsyncIterable<string> {
|
||||||
|
const dirents = await readdir(dir, { withFileTypes: true })
|
||||||
|
for (const dirent of dirents) {
|
||||||
|
const res = resolve(dir, dirent.name)
|
||||||
|
if (dirent.isDirectory()) {
|
||||||
|
yield* getFilesInDir(res)
|
||||||
|
} else {
|
||||||
|
yield res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAllVueComponentPaths(): Promise<string[]> {
|
||||||
|
const vueFilePaths: string[] = []
|
||||||
|
|
||||||
|
for await (const f of getFilesInDir("./components")) {
|
||||||
|
if (f.endsWith(".vue")) {
|
||||||
|
const componentsIndex = f.split("/").indexOf("components")
|
||||||
|
|
||||||
|
vueFilePaths.push(
|
||||||
|
`./${f
|
||||||
|
.split("/")
|
||||||
|
.slice(componentsIndex + 1)
|
||||||
|
.join("/")}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vueFilePaths
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveComponentName(filename: string): string {
|
||||||
|
const index = filename.split("/").indexOf("components")
|
||||||
|
|
||||||
|
return filename
|
||||||
|
.split("/")
|
||||||
|
.slice(index + 1)
|
||||||
|
.map((x) => x.split(".vue")[0]) // Remove extension
|
||||||
|
.filter((x) => x.toUpperCase() !== x.toLowerCase())
|
||||||
|
.map((x) => titleCase(x)) // titlecase it
|
||||||
|
.join("")
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTSImports(components: [string, string][]) {
|
||||||
|
return components.map(([componentName, componentPath]) => {
|
||||||
|
return ts.factory.createImportDeclaration(
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
ts.factory.createImportClause(
|
||||||
|
false,
|
||||||
|
ts.factory.createIdentifier(componentName),
|
||||||
|
undefined
|
||||||
|
),
|
||||||
|
ts.factory.createStringLiteral(componentPath)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTSProps(components: [string, string][]) {
|
||||||
|
return components.map(([componentName]) => {
|
||||||
|
return ts.factory.createPropertySignature(
|
||||||
|
undefined,
|
||||||
|
ts.factory.createIdentifier(componentName),
|
||||||
|
undefined,
|
||||||
|
ts.factory.createTypeQueryNode(ts.factory.createIdentifier(componentName))
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateTypeScriptDef(components: [string, string][]) {
|
||||||
|
const statements = [
|
||||||
|
...createTSImports(components),
|
||||||
|
ts.factory.createModuleDeclaration(
|
||||||
|
undefined,
|
||||||
|
[ts.factory.createModifier(ts.SyntaxKind.DeclareKeyword)],
|
||||||
|
ts.factory.createIdentifier("global"),
|
||||||
|
ts.factory.createModuleBlock([
|
||||||
|
ts.factory.createInterfaceDeclaration(
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
ts.factory.createIdentifier("__VLS_GlobalComponents"),
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
[...createTSProps(components)]
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
ts.NodeFlags.ExportContext |
|
||||||
|
ts.NodeFlags.GlobalAugmentation |
|
||||||
|
ts.NodeFlags.ContextFlags
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
const source = ts.factory.createSourceFile(
|
||||||
|
statements,
|
||||||
|
ts.factory.createToken(ts.SyntaxKind.EndOfFileToken),
|
||||||
|
ts.NodeFlags.None
|
||||||
|
)
|
||||||
|
|
||||||
|
const printer = ts.createPrinter({
|
||||||
|
newLine: ts.NewLineKind.LineFeed,
|
||||||
|
})
|
||||||
|
|
||||||
|
return printer.printFile(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
const module: Module<{}> = async function () {
|
||||||
|
if (!this.nuxt.options.dev) return
|
||||||
|
|
||||||
|
const results = await getAllVueComponentPaths()
|
||||||
|
const fileComponentNameCombo: [string, string][] = results.map((x) => [
|
||||||
|
resolveComponentName(x),
|
||||||
|
x,
|
||||||
|
])
|
||||||
|
const typescriptString = generateTypeScriptDef(fileComponentNameCombo)
|
||||||
|
|
||||||
|
await writeFile(resolve("shims-volar.d.ts"), typescriptString)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default module
|
||||||
@@ -133,6 +133,7 @@ export default {
|
|||||||
"@nuxtjs/composition-api/module",
|
"@nuxtjs/composition-api/module",
|
||||||
// https://github.com/antfu/unplugin-vue2-script-setup
|
// https://github.com/antfu/unplugin-vue2-script-setup
|
||||||
"unplugin-vue2-script-setup/nuxt",
|
"unplugin-vue2-script-setup/nuxt",
|
||||||
|
"~/modules/emit-volar-types.ts",
|
||||||
],
|
],
|
||||||
|
|
||||||
// Modules (https://go.nuxtjs.dev/config-modules)
|
// Modules (https://go.nuxtjs.dev/config-modules)
|
||||||
|
|||||||
Reference in New Issue
Block a user