| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- /**
- * User-owned tsdown configuration wrappers and child-process invocation.
- *
- * @module @deepseek-ai/dsh-scripts/build
- */
- import { createRequire } from 'node:module'
- import { existsSync, readFileSync, readdirSync } from 'node:fs'
- import { dirname, resolve } from 'node:path'
- import type { UserConfig } from 'tsdown'
- import { NodeCommandRunner, type CommandRunner } from '@deepseek-ai/dsh-helper'
- function hasLocalPluginPackages(root: string): boolean {
- const directory = resolve(root, 'plugins')
- return existsSync(directory) && readdirSync(directory, { withFileTypes: true }).some(
- item => item.isDirectory() && existsSync(resolve(directory, item.name, 'package.json')),
- )
- }
- function hasTsdownConfig(root: string): boolean {
- const hasConfigFile = [
- 'tsdown.config.ts', 'tsdown.config.mts', 'tsdown.config.cts',
- 'tsdown.config.js', 'tsdown.config.mjs', 'tsdown.config.cjs',
- 'tsdown.config.json',
- ]
- .some(name => existsSync(resolve(root, name)))
- if (hasConfigFile) return true
- let manifestText: string
- try {
- manifestText = readFileSync(resolve(root, 'package.json'), 'utf8')
- } catch (error) {
- if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false
- throw error
- }
- const manifest: unknown = JSON.parse(manifestText)
- return manifest !== null && !Array.isArray(manifest) && typeof manifest === 'object'
- && Object.hasOwn(manifest, 'tsdown')
- }
- /**
- * Preserve the developer's root config and append a separate workspace pass
- * when generated local plugin packages exist.
- * @param tsdownConfig - developer-owned root tsdown config.
- * @returns root tsdown config and optional local-plugin workspace pass.
- */
- export function ProjectBuild(tsdownConfig: UserConfig): UserConfig[] {
- if (tsdownConfig.workspace !== undefined) {
- throw new Error('ProjectBuild owns workspace discovery; remove config.workspace')
- }
- const root = resolve(tsdownConfig.cwd ?? process.cwd())
- return hasLocalPluginPackages(root)
- ? [{ ...tsdownConfig }, { workspace: { include: ['plugins/*'] } }]
- : [{ ...tsdownConfig }]
- }
- /**
- * Preserve a local plugin package's developer-owned tsdown config.
- * @param tsdownConfig - developer-owned plugin tsdown config.
- * @returns validated tsdown config copy.
- */
- export function PluginBuild(tsdownConfig: UserConfig): UserConfig {
- if (tsdownConfig.workspace !== undefined) throw new Error('PluginBuild does not accept nested workspace config')
- return { ...tsdownConfig }
- }
- function resolveTsdownBin(cwd: string): string {
- const require = createRequire(resolve(cwd, 'package.json'))
- let manifestPath: string
- try {
- manifestPath = require.resolve('tsdown/package.json')
- } catch (error) {
- throw new Error(`dsh-sdk build requires tsdown in this project: ${String(error)}`)
- }
- const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as { bin?: unknown }
- const bin = typeof manifest.bin === 'string'
- ? manifest.bin
- : manifest.bin && typeof manifest.bin === 'object'
- ? (manifest.bin as Record<string, unknown>).tsdown
- : undefined
- if (typeof bin !== 'string') throw new Error('installed tsdown package has no executable')
- return resolve(dirname(manifestPath), bin)
- }
- /** Invoke the project's installed tsdown, forwarding all build arguments. */
- export async function runProjectBuild(
- args: readonly string[],
- cwd: string = process.cwd(),
- runner: CommandRunner = new NodeCommandRunner(),
- ): Promise<void> {
- if (!hasTsdownConfig(cwd)) return
- const result = await runner.run(process.execPath, [resolveTsdownBin(cwd), ...args], resolve(cwd))
- if (result.signal) throw new Error(`tsdown was killed by ${result.signal}`)
- if (result.exitCode !== 0) throw new Error(`tsdown exited with code ${String(result.exitCode)}`)
- }
|