feat(dsh-sdk): create <source> — add external plugin as native PM dependency + cordis mount
dsh-sdk create <source> adds a github (github:owner/repo#ref) or npm (pkg@version) plugin as a package-manager-native dependency, then mounts the resolved dependency in cordis.yml through ProjectEditSession. Adds PackageManager.add(spec) and ProjectEditSession.addExternalPlugin(id, packageName). No giget/pacote. Per-file 100% coverage on the new/changed files.
This commit is contained in:
@@ -148,6 +148,25 @@ export abstract class PackageManager {
|
||||
await this.runChecked(runner, this.buildCommand(), cwd, 'build')
|
||||
}
|
||||
|
||||
/**
|
||||
* Build add-dependency command arguments for one already-normalized source spec.
|
||||
* @param spec - a package-manager-native dependency source (`pkg@version` or `github:owner/repo#ref`).
|
||||
* @returns arguments following the manager executable.
|
||||
*/
|
||||
addCommand(spec: string): readonly string[] {
|
||||
return ['add', spec]
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one dependency from a native source spec and fail on non-zero or signalled exit.
|
||||
* @param spec - a package-manager-native dependency source.
|
||||
* @param cwd - project directory.
|
||||
* @param runner - optional subprocess boundary.
|
||||
*/
|
||||
async add(spec: string, cwd: string, runner: CommandRunner = new NodeCommandRunner()): Promise<void> {
|
||||
await this.runChecked(runner, this.addCommand(spec), cwd, 'add')
|
||||
}
|
||||
|
||||
private async runChecked(runner: CommandRunner, args: readonly string[], cwd: string, operation: string): Promise<void> {
|
||||
const result = await runner.run(this.name, args, cwd)
|
||||
if (result.signal !== null) {
|
||||
@@ -184,6 +203,11 @@ export class NpmPackageManager extends PackageManager {
|
||||
override linkSpec(relativePath: string): string {
|
||||
return `file:${relativePath}`
|
||||
}
|
||||
|
||||
/** npm adds a dependency through `install <spec>` rather than an `add` verb. */
|
||||
override addCommand(spec: string): readonly string[] {
|
||||
return ['install', spec]
|
||||
}
|
||||
}
|
||||
|
||||
/** pnpm workspace behavior. */
|
||||
|
||||
@@ -220,6 +220,23 @@ export class ProjectEditSession implements FeatureProjectView {
|
||||
this.addedPlugins.add(entry.id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Mount a Cordis entry for an external dependency the package manager has already
|
||||
* added (github or npm), without generating files or re-adding the dependency.
|
||||
* @param id - stable Cordis config entry id.
|
||||
* @param packageName - the installed dependency's package name.
|
||||
*/
|
||||
addExternalPlugin(id: string, packageName: string): void {
|
||||
this.assertOpen()
|
||||
if (!this.manifest().npmDependency(packageName)) {
|
||||
throw new Error(`external plugin dependency is not installed: ${packageName}`)
|
||||
}
|
||||
const cordis = this.cordis()
|
||||
if (cordis.entry(id)) throw new Error(`Cordis config entry already exists: ${id}`)
|
||||
cordis.addEntry({ id, name: packageName })
|
||||
this.addedPlugins.add(id)
|
||||
}
|
||||
|
||||
/** Enable or disable one custom/manual Cordis config entry by stable id. */
|
||||
setCustomPluginDisabled(id: string, disabled: boolean): void {
|
||||
this.assertOpen()
|
||||
|
||||
Reference in New Issue
Block a user