mirror of https://github.com/vuejs/core.git
				
				
				
			
		
			
				
	
	
		
			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)
 | |
|     },
 | |
|   }
 | |
| }
 |