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${pkg === 'vue' ? '-with-vapor' : ''}.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)
 | 
						|
    },
 | 
						|
  }
 | 
						|
}
 |