2022-04-15 15:19:05 +00:00
|
|
|
import { promises as fsp } from 'node:fs'
|
2022-02-07 10:20:01 +00:00
|
|
|
import { isAbsolute, join, relative, resolve } from 'pathe'
|
2021-11-21 16:14:46 +00:00
|
|
|
import { Nuxt, TSReference } from '@nuxt/schema'
|
2021-11-16 12:32:21 +00:00
|
|
|
import defu from 'defu'
|
2021-10-13 20:01:50 +00:00
|
|
|
import type { TSConfig } from 'pkg-types'
|
2021-10-07 13:53:31 +00:00
|
|
|
import { getModulePaths, getNearestPackage } from './cjs'
|
|
|
|
|
|
|
|
export const writeTypes = async (nuxt: Nuxt) => {
|
|
|
|
const modulePaths = getModulePaths(nuxt.options.modulesDir)
|
|
|
|
|
2021-11-16 12:32:21 +00:00
|
|
|
const tsConfig: TSConfig = defu(nuxt.options.typescript?.tsConfig, {
|
2021-10-13 20:01:50 +00:00
|
|
|
compilerOptions: {
|
2022-03-01 18:25:23 +00:00
|
|
|
jsx: 'preserve',
|
2021-10-13 20:01:50 +00:00
|
|
|
target: 'ESNext',
|
|
|
|
module: 'ESNext',
|
|
|
|
moduleResolution: 'Node',
|
2021-11-10 13:18:25 +00:00
|
|
|
skipLibCheck: true,
|
2021-11-16 15:20:27 +00:00
|
|
|
strict: nuxt.options.typescript?.strict ?? false,
|
2021-10-13 20:01:50 +00:00
|
|
|
allowJs: true,
|
|
|
|
noEmit: true,
|
|
|
|
resolveJsonModule: true,
|
2021-11-10 16:39:19 +00:00
|
|
|
allowSyntheticDefaultImports: true,
|
2021-10-13 20:01:50 +00:00
|
|
|
types: ['node'],
|
|
|
|
baseUrl: relative(nuxt.options.buildDir, nuxt.options.rootDir),
|
|
|
|
paths: {}
|
2021-10-22 22:33:22 +00:00
|
|
|
},
|
|
|
|
include: [
|
|
|
|
'./nuxt.d.ts',
|
|
|
|
join(relative(nuxt.options.buildDir, nuxt.options.rootDir), '**/*'),
|
2022-09-22 13:50:40 +00:00
|
|
|
...nuxt.options.srcDir !== nuxt.options.rootDir ? [join(relative(nuxt.options.buildDir, nuxt.options.srcDir), '**/*')] : [],
|
2022-10-17 17:53:04 +00:00
|
|
|
...nuxt.options.typescript.includeWorkspace && nuxt.options.workspaceDir !== nuxt.options.rootDir ? [join(relative(nuxt.options.buildDir, nuxt.options.workspaceDir), '**/*')] : []
|
2021-10-22 22:33:22 +00:00
|
|
|
]
|
2021-11-16 12:32:21 +00:00
|
|
|
})
|
2021-10-13 20:01:50 +00:00
|
|
|
|
2022-08-26 15:47:29 +00:00
|
|
|
const aliases: Record<string, string> = {
|
2021-10-13 20:01:50 +00:00
|
|
|
...nuxt.options.alias,
|
2022-04-07 11:28:04 +00:00
|
|
|
'#build': nuxt.options.buildDir
|
2021-10-13 20:01:50 +00:00
|
|
|
}
|
|
|
|
|
2021-11-18 18:11:43 +00:00
|
|
|
// Exclude bridge alias types to support Volar
|
|
|
|
const excludedAlias = [/^@vue\/.*$/]
|
|
|
|
|
2021-10-13 20:01:50 +00:00
|
|
|
for (const alias in aliases) {
|
2021-11-18 18:11:43 +00:00
|
|
|
if (excludedAlias.some(re => re.test(alias))) {
|
|
|
|
continue
|
|
|
|
}
|
2022-04-25 17:07:01 +00:00
|
|
|
const relativePath = isAbsolute(aliases[alias])
|
|
|
|
? relative(nuxt.options.rootDir, aliases[alias]) || '.'
|
|
|
|
: aliases[alias]
|
2021-10-13 20:01:50 +00:00
|
|
|
|
2022-04-25 17:07:01 +00:00
|
|
|
const stats = await fsp.stat(resolve(nuxt.options.rootDir, relativePath)).catch(() => null /* file does not exist */)
|
2022-08-26 15:47:29 +00:00
|
|
|
tsConfig.compilerOptions = tsConfig.compilerOptions || {}
|
2022-04-25 17:07:01 +00:00
|
|
|
if (stats?.isDirectory()) {
|
|
|
|
tsConfig.compilerOptions.paths[alias] = [relativePath]
|
|
|
|
tsConfig.compilerOptions.paths[`${alias}/*`] = [`${relativePath}/*`]
|
|
|
|
} else {
|
|
|
|
tsConfig.compilerOptions.paths[alias] = [relativePath.replace(/(?<=\w)\.\w+$/g, '')] /* remove extension */
|
|
|
|
}
|
2021-10-13 20:01:50 +00:00
|
|
|
}
|
|
|
|
|
2021-10-07 13:53:31 +00:00
|
|
|
const references: TSReference[] = [
|
|
|
|
...nuxt.options.buildModules,
|
|
|
|
...nuxt.options.modules,
|
|
|
|
...nuxt.options._modules
|
|
|
|
]
|
|
|
|
.filter(f => typeof f === 'string')
|
|
|
|
.map(id => ({ types: getNearestPackage(id, modulePaths)?.name || id }))
|
|
|
|
|
2022-03-18 10:45:30 +00:00
|
|
|
if (nuxt.options.experimental?.reactivityTransform) {
|
2022-03-17 22:17:59 +00:00
|
|
|
references.push({ types: 'vue/macros-global' })
|
|
|
|
}
|
|
|
|
|
2021-10-07 13:53:31 +00:00
|
|
|
const declarations: string[] = []
|
|
|
|
|
2021-10-13 20:01:50 +00:00
|
|
|
await nuxt.callHook('prepare:types', { references, declarations, tsConfig })
|
2021-10-07 13:53:31 +00:00
|
|
|
|
|
|
|
const declaration = [
|
|
|
|
...references.map((ref) => {
|
2022-02-07 10:20:01 +00:00
|
|
|
if ('path' in ref && isAbsolute(ref.path)) {
|
2021-10-22 22:33:22 +00:00
|
|
|
ref.path = relative(nuxt.options.buildDir, ref.path)
|
2021-10-07 13:53:31 +00:00
|
|
|
}
|
|
|
|
return `/// <reference ${renderAttrs(ref)} />`
|
|
|
|
}),
|
|
|
|
...declarations,
|
2021-10-22 22:33:22 +00:00
|
|
|
'',
|
2021-10-07 13:53:31 +00:00
|
|
|
'export {}',
|
|
|
|
''
|
|
|
|
].join('\n')
|
|
|
|
|
2021-10-18 14:22:02 +00:00
|
|
|
async function writeFile () {
|
2021-10-22 22:33:22 +00:00
|
|
|
const GeneratedBy = '// Generated by nuxi'
|
|
|
|
|
2021-10-18 14:22:02 +00:00
|
|
|
const tsConfigPath = resolve(nuxt.options.buildDir, 'tsconfig.json')
|
2021-12-01 20:40:40 +00:00
|
|
|
await fsp.mkdir(nuxt.options.buildDir, { recursive: true })
|
2021-10-22 22:33:22 +00:00
|
|
|
await fsp.writeFile(tsConfigPath, GeneratedBy + '\n' + JSON.stringify(tsConfig, null, 2))
|
|
|
|
|
|
|
|
const declarationPath = resolve(nuxt.options.buildDir, 'nuxt.d.ts')
|
|
|
|
await fsp.writeFile(declarationPath, GeneratedBy + '\n' + declaration)
|
2021-10-18 14:22:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This is needed for Nuxt 2 which clears the build directory again before building
|
|
|
|
// https://github.com/nuxt/nuxt.js/blob/dev/packages/builder/src/builder.js#L144
|
|
|
|
nuxt.hook('builder:prepared', writeFile)
|
|
|
|
|
|
|
|
await writeFile()
|
2021-10-07 13:53:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function renderAttrs (obj: Record<string, string>) {
|
|
|
|
return Object.entries(obj).map(e => renderAttr(e[0], e[1])).join(' ')
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderAttr (key: string, value: string) {
|
|
|
|
return value ? `${key}="${value}"` : ''
|
|
|
|
}
|