feat(sdk): add developer project tooling
docs(rfc): propose SDK developer project tooling feat: rename / docs ci: fix windows gates docs: revert
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* 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 {
|
||||
return ['tsdown.config.ts', 'tsdown.config.js', 'tsdown.config.mjs', 'tsdown.config.mts']
|
||||
.some(name => existsSync(resolve(root, name)))
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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)}`)
|
||||
}
|
||||
Reference in New Issue
Block a user