From dbe7109c8f6417770129dc92313f05feac0c0edb Mon Sep 17 00:00:00 2001 From: Evan You Date: Sat, 4 Feb 2023 11:59:42 +0800 Subject: [PATCH] build: improve dts rollup output --- package.json | 1 + pnpm-lock.yaml | 2 + rollup.dts.config.js | 125 +++++++++++++++++++++++++++++++++++++++++- scripts/const-enum.js | 12 ++-- 4 files changed, 132 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index f4d80ab4e64..af043f73b5c 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,7 @@ "esbuild": "^0.17.4", "eslint": "^8.33.0", "eslint-plugin-jest": "^27.2.1", + "estree-walker": "^2.0.2", "execa": "^4.0.2", "jsdom": "^21.1.0", "lint-staged": "^10.2.10", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4d7820f2df4..f5c2bf38de4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,7 @@ importers: esbuild: ^0.17.4 eslint: ^8.33.0 eslint-plugin-jest: ^27.2.1 + estree-walker: ^2.0.2 execa: ^4.0.2 jsdom: ^21.1.0 lint-staged: ^10.2.10 @@ -75,6 +76,7 @@ importers: esbuild: 0.17.5 eslint: 8.33.0 eslint-plugin-jest: 27.2.1_4vsywjlpuriuw3tl5oq6zy5a64 + estree-walker: 2.0.2 execa: 4.1.0 jsdom: 21.1.0 lint-staged: 10.5.4 diff --git a/rollup.dts.config.js b/rollup.dts.config.js index b245ed210d6..63906c10d17 100644 --- a/rollup.dts.config.js +++ b/rollup.dts.config.js @@ -1,6 +1,9 @@ // @ts-check +import { parse } from '@babel/parser' import { existsSync, readdirSync, readFileSync } from 'fs' +import MagicString from 'magic-string' import dts from 'rollup-plugin-dts' +import { walk } from 'estree-walker' if (!existsSync('temp/packages')) { console.warn( @@ -31,14 +34,132 @@ export default readdirSync('temp/packages').map(pkg => { }) /** + * Patch the dts generated by rollup-plugin-dts + * 1. remove exports marked as @internal + * 2. 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" + * 3. Append custom agumentations (jsx, macros) * @returns {import('rollup').Plugin} */ function patchTypes(pkg) { return { name: 'patch-types', renderChunk(code) { - // 1. TODO remove entries marked with @private - // 2. append pkg specific types + const s = new MagicString(code) + const ast = parse(code, { + plugins: ['typescript'], + sourceType: 'module' + }) + + /** + * @param {import('@babel/types').Node} node + * @returns {boolean} + */ + function removeInternal(node) { + if ( + node.leadingComments && + node.leadingComments.some(c => { + return c.type === 'CommentBlock' && /@internal\b/.test(c.value) + }) + ) { + /** @type {any} */ + const n = node + let id + if (n.id && n.id.type === 'Identifier') { + id = n.id.name + } else if (n.key && n.key.type === 'Identifier') { + id = n.key.name + } + if (id) { + s.overwrite( + // @ts-ignore + node.leadingComments[0].start, + node.end, + `/* removed internal: ${id} */` + ) + } else { + // @ts-ignore + s.remove(node.leadingComments[0].start, node.end) + } + return true + } + return false + } + + const shouldRemoveExport = new Set() + // pass 1: remove internals + add exports + for (const node of ast.program.body) { + if ( + (node.type === 'TSTypeAliasDeclaration' || + node.type === 'TSInterfaceDeclaration') && + !node.id.name.startsWith(`_`) + ) { + shouldRemoveExport.add(node.id.name) + if (!removeInternal(node)) { + // @ts-ignore + s.prependLeft(node.start, `export `) + // traverse further for internal properties + if (node.type === 'TSInterfaceDeclaration') { + node.body.body.forEach(removeInternal) + } else if (node.type === 'TSTypeAliasDeclaration') { + // @ts-ignore + walk(node.typeAnnotation, { + enter(node) { + // @ts-ignore + if (removeInternal(node)) this.skip() + } + }) + } + } + } else if (removeInternal(node)) { + if (node.type === 'VariableDeclaration') { + // declare const x + for (const decl of node.declarations) { + // @ts-ignore + shouldRemoveExport.add(decl.id.name) + } + } else if ( + node.type === 'TSDeclareFunction' || + node.type === 'TSEnumDeclaration' + ) { + // declare function + // @ts-ignore + shouldRemoveExport.add(node.id.name) + } else { + throw new Error( + `unhandled export type marked as @internal: ${node.type}` + ) + } + } + } + // pass 2: remove exports + 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' && + shouldRemoveExport.has(spec.local.name) + ) { + const next = node.specifiers[i + 1] + if (next) { + // @ts-ignore + s.remove(spec.start, next.start) + } else { + // last one + const prev = node.specifiers[i - 1] + // @ts-ignore + s.remove(prev ? prev.end : spec.start, spec.end) + } + } + } + } + } + code = s.toString() + + // append pkg specific types const additionalTypeDir = `packages/${pkg}/types` if (existsSync(additionalTypeDir)) { code += diff --git a/scripts/const-enum.js b/scripts/const-enum.js index b4dbc1770b9..37924cc64b3 100644 --- a/scripts/const-enum.js +++ b/scripts/const-enum.js @@ -192,15 +192,15 @@ export async function constEnum() { spec.exportKind !== 'type' && knowEnums.has(spec.local.name) ) { - if (i === 0) { - // first - const next = node.specifiers[i + 1] + const next = node.specifiers[i + 1] + if (next) { // @ts-ignore - s.remove(spec.start, next ? next.start : spec.end) + s.remove(spec.start, next.start) } else { - // locate the end of prev + // last one + const prev = node.specifiers[i - 1] // @ts-ignore - s.remove(node.specifiers[i - 1].end, spec.end) + s.remove(prev ? prev.end : spec.start, spec.end) } } }