mirror of
https://github.com/vuejs/core.git
synced 2024-11-22 04:51:10 +00:00
205 lines
6.7 KiB
JavaScript
205 lines
6.7 KiB
JavaScript
// @ts-check
|
|
import assert from 'node:assert/strict'
|
|
import { parse } from '@babel/parser'
|
|
import { existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
|
|
import MagicString from 'magic-string'
|
|
import dts from 'rollup-plugin-dts'
|
|
|
|
if (!existsSync('temp/packages')) {
|
|
console.warn(
|
|
'no temp dts files found. run `tsc -p tsconfig.build-browser.json && tsc -p tsconfig.build-node.json` first.',
|
|
)
|
|
process.exit(1)
|
|
}
|
|
|
|
const packages = readdirSync('temp/packages')
|
|
const targets = process.env.TARGETS ? process.env.TARGETS.split(',') : null
|
|
const targetPackages = targets
|
|
? packages.filter(pkg => targets.includes(pkg))
|
|
: packages
|
|
|
|
export default targetPackages.map(
|
|
/** @returns {import('rollup').RollupOptions} */
|
|
pkg => {
|
|
return {
|
|
input: `./temp/packages/${pkg}/src/index.d.ts`,
|
|
output: {
|
|
file: `packages/${pkg}/dist/${pkg}.d.ts`,
|
|
format: 'es',
|
|
},
|
|
plugins: [dts(), patchTypes(pkg), ...(pkg === 'vue' ? [copyMts()] : [])],
|
|
onwarn(warning, warn) {
|
|
// during dts rollup, everything is externalized by default
|
|
if (
|
|
warning.code === 'UNRESOLVED_IMPORT' &&
|
|
!warning.exporter?.startsWith('.')
|
|
) {
|
|
return
|
|
}
|
|
warn(warning)
|
|
},
|
|
}
|
|
},
|
|
)
|
|
|
|
/**
|
|
* Patch the dts generated by rollup-plugin-dts
|
|
* 1. Convert all types to inline exports
|
|
* and remove them from the big export {} declaration
|
|
* otherwise it gets weird in vitepress `defineComponent` call with
|
|
* "the inferred type cannot be named without a reference"
|
|
* 2. Append custom augmentations (jsx, macros)
|
|
*
|
|
* @param {string} pkg
|
|
* @returns {import('rollup').Plugin}
|
|
*/
|
|
function patchTypes(pkg) {
|
|
return {
|
|
name: 'patch-types',
|
|
renderChunk(code, chunk) {
|
|
const s = new MagicString(code)
|
|
const ast = parse(code, {
|
|
plugins: ['typescript'],
|
|
sourceType: 'module',
|
|
})
|
|
|
|
/**
|
|
* @param {import('@babel/types').VariableDeclarator | import('@babel/types').TSTypeAliasDeclaration | import('@babel/types').TSInterfaceDeclaration | import('@babel/types').TSDeclareFunction | import('@babel/types').TSInterfaceDeclaration | import('@babel/types').TSEnumDeclaration | import('@babel/types').ClassDeclaration} node
|
|
* @param {import('@babel/types').VariableDeclaration} [parentDecl]
|
|
*/
|
|
function processDeclaration(node, parentDecl) {
|
|
if (!node.id) {
|
|
return
|
|
}
|
|
assert(node.id.type === 'Identifier')
|
|
const name = node.id.name
|
|
if (name.startsWith('_')) {
|
|
return
|
|
}
|
|
shouldRemoveExport.add(name)
|
|
if (isExported.has(name)) {
|
|
const start = (parentDecl || node).start
|
|
assert(typeof start === 'number')
|
|
s.prependLeft(start, `export `)
|
|
}
|
|
}
|
|
|
|
const isExported = new Set()
|
|
const shouldRemoveExport = new Set()
|
|
|
|
// pass 0: check all exported types
|
|
for (const node of ast.program.body) {
|
|
if (node.type === 'ExportNamedDeclaration' && !node.source) {
|
|
for (let i = 0; i < node.specifiers.length; i++) {
|
|
const spec = node.specifiers[i]
|
|
if (spec.type === 'ExportSpecifier') {
|
|
isExported.add(spec.local.name)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// pass 1: add exports
|
|
for (const node of ast.program.body) {
|
|
if (node.type === 'VariableDeclaration') {
|
|
processDeclaration(node.declarations[0], node)
|
|
if (node.declarations.length > 1) {
|
|
assert(typeof node.start === 'number')
|
|
assert(typeof node.end === 'number')
|
|
throw new Error(
|
|
`unhandled declare const with more than one declarators:\n${code.slice(
|
|
node.start,
|
|
node.end,
|
|
)}`,
|
|
)
|
|
}
|
|
} else if (
|
|
node.type === 'TSTypeAliasDeclaration' ||
|
|
node.type === 'TSInterfaceDeclaration' ||
|
|
node.type === 'TSDeclareFunction' ||
|
|
node.type === 'TSEnumDeclaration' ||
|
|
node.type === 'ClassDeclaration'
|
|
) {
|
|
processDeclaration(node)
|
|
}
|
|
}
|
|
|
|
// pass 2: remove exports
|
|
for (const node of ast.program.body) {
|
|
if (node.type === 'ExportNamedDeclaration' && !node.source) {
|
|
let removed = 0
|
|
for (let i = 0; i < node.specifiers.length; i++) {
|
|
const spec = node.specifiers[i]
|
|
if (
|
|
spec.type === 'ExportSpecifier' &&
|
|
shouldRemoveExport.has(spec.local.name)
|
|
) {
|
|
assert(spec.exported.type === 'Identifier')
|
|
const exported = spec.exported.name
|
|
if (exported !== spec.local.name) {
|
|
// this only happens if we have something like
|
|
// type Foo
|
|
// export { Foo as Bar }
|
|
continue
|
|
}
|
|
const next = node.specifiers[i + 1]
|
|
if (next) {
|
|
assert(typeof spec.start === 'number')
|
|
assert(typeof next.start === 'number')
|
|
s.remove(spec.start, next.start)
|
|
} else {
|
|
// last one
|
|
const prev = node.specifiers[i - 1]
|
|
assert(typeof spec.start === 'number')
|
|
assert(typeof spec.end === 'number')
|
|
s.remove(
|
|
prev
|
|
? (assert(typeof prev.end === 'number'), prev.end)
|
|
: spec.start,
|
|
spec.end,
|
|
)
|
|
}
|
|
removed++
|
|
}
|
|
}
|
|
if (removed === node.specifiers.length) {
|
|
assert(typeof node.start === 'number')
|
|
assert(typeof node.end === 'number')
|
|
s.remove(node.start, node.end)
|
|
}
|
|
}
|
|
}
|
|
code = s.toString()
|
|
|
|
// append pkg specific types
|
|
const additionalTypeDir = `packages/${pkg}/types`
|
|
if (existsSync(additionalTypeDir)) {
|
|
code +=
|
|
'\n' +
|
|
readdirSync(additionalTypeDir)
|
|
.map(file => readFileSync(`${additionalTypeDir}/${file}`, 'utf-8'))
|
|
.join('\n')
|
|
}
|
|
return code
|
|
},
|
|
}
|
|
}
|
|
|
|
/**
|
|
* According to https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html#packagejson-exports-imports-and-self-referencing
|
|
* the only way to correct provide types for both Node ESM and CJS is to have
|
|
* two separate declaration files, so we need to copy vue.d.ts to vue.d.mts
|
|
* upon build.
|
|
*
|
|
* @returns {import('rollup').Plugin}
|
|
*/
|
|
function copyMts() {
|
|
return {
|
|
name: 'copy-vue-mts',
|
|
writeBundle(_, bundle) {
|
|
assert('code' in bundle['vue.d.ts'])
|
|
writeFileSync('packages/vue/dist/vue.d.mts', bundle['vue.d.ts'].code)
|
|
},
|
|
}
|
|
}
|