| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- import { existsSync } from 'node:fs'
- import { cp, mkdir, readdir, readFile, rm, stat, writeFile } from 'node:fs/promises'
- import { basename, dirname, join, resolve } from 'node:path'
- import { spawnSync } from 'node:child_process'
- import { fileURLToPath } from 'node:url'
- const scriptDir = dirname(fileURLToPath(import.meta.url))
- const sourceRoot = resolve(scriptDir, '..')
- const args = process.argv.slice(2)
- const readArg = (name, fallback) => {
- const index = args.indexOf(name)
- return index >= 0 ? args[index + 1] : fallback
- }
- const outputRoot = resolve(
- sourceRoot,
- readArg(
- '--out-dir',
- process.env.FILE_VIEWER_COMPONENT_REPO_DIR ||
- process.env.FILE_VIEWER_WRAPPER_REPO_DIR ||
- '.release/component-repos'
- )
- )
- const selectedPackages = new Set(
- args
- .filter(arg => arg.startsWith('--package='))
- .map(arg => arg.slice('--package='.length))
- )
- const selectedIds = new Set(
- args
- .filter(arg => arg.startsWith('--id='))
- .map(arg => arg.slice('--id='.length))
- )
- const keepExisting = args.includes('--keep-existing')
- const readJson = async path => JSON.parse(await readFile(path, 'utf8'))
- const writeJson = async (path, value) => writeFile(path, `${JSON.stringify(value, null, 2)}\n`, 'utf8')
- const rootPackage = await readJson(join(sourceRoot, 'package.json'))
- const ecosystemManifest = await readJson(join(sourceRoot, 'ecosystem', 'wrappers.json'))
- const collectPackageDirs = async workspaceRoot => {
- if (!existsSync(workspaceRoot)) {
- return []
- }
- const entries = await readdir(workspaceRoot, { withFileTypes: true })
- return entries
- .filter(entry => entry.isDirectory())
- .map(entry => join(workspaceRoot, entry.name))
- .filter(packageDir => existsSync(join(packageDir, 'package.json')))
- }
- const workspacePackageDirs = [
- sourceRoot,
- join(sourceRoot, 'packages', 'core'),
- ...(await collectPackageDirs(join(sourceRoot, 'packages', 'compat'))),
- ...(await collectPackageDirs(join(sourceRoot, 'packages', 'components'))),
- ...(await collectPackageDirs(join(sourceRoot, 'packages', 'renderers'))),
- ...(await collectPackageDirs(join(sourceRoot, 'apps')))
- ]
- const workspaceVersions = new Map()
- for (const packageDir of workspacePackageDirs) {
- const packagePath = join(packageDir, 'package.json')
- if (!existsSync(packagePath)) {
- continue
- }
- const packageJson = await readJson(packagePath)
- workspaceVersions.set(packageJson.name, packageJson.version)
- }
- const run = (command, commandArgs) => {
- const result = spawnSync(command, commandArgs, {
- cwd: sourceRoot,
- encoding: 'utf8',
- stdio: 'pipe'
- })
- if (result.status !== 0) {
- throw new Error(`Command failed: ${command} ${commandArgs.join(' ')}\n${result.stderr || result.stdout}`)
- }
- return result.stdout.trim()
- }
- const assertDirectory = async path => {
- if (!existsSync(path)) {
- throw new Error(`Missing directory: ${path}`)
- }
- const info = await stat(path)
- if (!info.isDirectory()) {
- throw new Error(`Not a directory: ${path}`)
- }
- }
- const assertFile = async path => {
- if (!existsSync(path)) {
- throw new Error(`Missing file: ${path}`)
- }
- const info = await stat(path)
- if (!info.isFile()) {
- throw new Error(`Not a file: ${path}`)
- }
- }
- const removePath = path => rm(path, { recursive: true, force: true })
- const shouldCopy = source => {
- const name = basename(source)
- return ![
- '.DS_Store',
- '.git',
- '.vercel',
- 'dist',
- 'node_modules',
- 'tsconfig.tsbuildinfo'
- ].includes(name)
- }
- const copyPackage = async (from, to) => {
- if (!keepExisting) {
- await removePath(to)
- }
- await mkdir(to, { recursive: true })
- await cp(from, to, {
- recursive: true,
- force: true,
- filter: shouldCopy
- })
- }
- const normalizeWorkspaceRange = (dependencyName, range) => {
- if (!range?.startsWith?.('workspace:')) {
- return range
- }
- const workspaceRange = range.slice('workspace:'.length)
- if (workspaceRange === '*' || workspaceRange === '') {
- const version = workspaceVersions.get(dependencyName)
- return version ? `^${version}` : `^${rootPackage.version}`
- }
- return workspaceRange
- }
- const normalizeDependencyBlock = block => {
- if (!block) {
- return
- }
- for (const [dependencyName, range] of Object.entries(block)) {
- block[dependencyName] = normalizeWorkspaceRange(dependencyName, range)
- }
- }
- const normalizePackageJson = async (targetDir, renderer) => {
- const packagePath = join(targetDir, 'package.json')
- const packageJson = await readJson(packagePath)
- packageJson.packageManager = rootPackage.packageManager
- packageJson.private = false
- packageJson.repository = {
- type: 'git',
- url: `git+${renderer.github}.git`
- }
- packageJson.homepage = renderer.github
- packageJson.bugs = {
- url: `${renderer.github}/issues`
- }
- normalizeDependencyBlock(packageJson.dependencies)
- normalizeDependencyBlock(packageJson.devDependencies)
- normalizeDependencyBlock(packageJson.peerDependencies)
- normalizeDependencyBlock(packageJson.optionalDependencies)
- await writeJson(packagePath, packageJson)
- }
- const normalizeStandaloneTsConfig = async targetDir => {
- const tsconfigPath = join(targetDir, 'tsconfig.json')
- if (!existsSync(tsconfigPath)) {
- return
- }
- const tsconfig = await readJson(tsconfigPath)
- if (tsconfig.compilerOptions?.paths) {
- delete tsconfig.compilerOptions.paths
- }
- if (tsconfig.references) {
- delete tsconfig.references
- }
- await writeJson(tsconfigPath, tsconfig)
- }
- const writeGitignore = async targetDir => {
- await writeFile(
- join(targetDir, '.gitignore'),
- [
- 'node_modules/',
- 'dist/',
- '*.tgz',
- '*.tsbuildinfo',
- '.DS_Store',
- '.pnpm-store/',
- '.npm-cache/',
- ''
- ].join('\n'),
- 'utf8'
- )
- }
- const writeStandaloneManifest = async (targetDir, renderer, packageJson) => {
- await writeJson(join(targetDir, 'renderer-repo-manifest.json'), {
- schemaVersion: 1,
- generatedAt: new Date().toISOString(),
- sourceBranch: run('git', ['branch', '--show-current']),
- sourceCommit: run('git', ['rev-parse', '--short', 'HEAD']),
- organization: ecosystemManifest.organization,
- rendererId: renderer.id,
- packageName: renderer.packageName,
- packageVersion: packageJson.version,
- repository: renderer.repository,
- github: renderer.github,
- gitee: renderer.gitee,
- entryFormats: renderer.entryFormats,
- sourcePackageDir: renderer.packageDir,
- publicSource: renderer.publicSource === true
- })
- }
- const assertStandaloneRepo = async (targetDir, renderer) => {
- await assertFile(join(targetDir, 'package.json'))
- await assertFile(join(targetDir, 'README.md'))
- await assertFile(join(targetDir, 'README.en.md'))
- await assertFile(join(targetDir, 'LICENSE'))
- const packageJson = await readJson(join(targetDir, 'package.json'))
- if (packageJson.name !== renderer.packageName) {
- throw new Error(`Package name mismatch in ${targetDir}: ${packageJson.name} !== ${renderer.packageName}`)
- }
- const serialized = JSON.stringify(packageJson)
- if (serialized.includes('workspace:')) {
- throw new Error(`Workspace dependency leaked into standalone renderer repo: ${targetDir}`)
- }
- if (existsSync(join(targetDir, 'node_modules')) || existsSync(join(targetDir, 'dist'))) {
- throw new Error(`Generated dependency/build output leaked into standalone renderer repo: ${targetDir}`)
- }
- }
- const renderers = (ecosystemManifest.renderers || []).filter(renderer => {
- if (selectedPackages.size && !selectedPackages.has(renderer.packageName)) {
- return false
- }
- if (selectedIds.size && !selectedIds.has(renderer.id)) {
- return false
- }
- return true
- })
- if (!renderers.length) {
- throw new Error('No renderer packages selected for export.')
- }
- await mkdir(outputRoot, { recursive: true })
- await assertFile(join(sourceRoot, 'LICENSE'))
- for (const renderer of renderers) {
- const sourcePackageDir = join(sourceRoot, renderer.packageDir)
- await assertDirectory(sourcePackageDir)
- const targetDir = join(outputRoot, renderer.repository)
- await copyPackage(sourcePackageDir, targetDir)
- await cp(join(sourceRoot, 'LICENSE'), join(targetDir, 'LICENSE'), { force: true })
- await writeGitignore(targetDir)
- await normalizePackageJson(targetDir, renderer)
- await normalizeStandaloneTsConfig(targetDir)
- const targetPackageJson = await readJson(join(targetDir, 'package.json'))
- await writeStandaloneManifest(targetDir, renderer, targetPackageJson)
- await assertStandaloneRepo(targetDir, renderer)
- console.log(`Prepared ${renderer.packageName} -> ${targetDir}`)
- }
- console.log(`Prepared ${renderers.length} renderer package repo${renderers.length === 1 ? '' : 's'} in ${outputRoot}`)
|