git mv per the regrouping RFC: the five human-collaboration seams and tui join packages/interaction/, app-boot becomes packages/boot/, and jsonrpc joins the renamed scaffold/ (formerly sdk/) as its server half beside client/protocol/create-sdk/helper/scripts/telemetry, whose folders drop the legacy sdk- prefix. Three new group README triplets replace the ui/ and sdk/ ones; tsconfig references/paths/globs, knip keys, vitest globs, gate scripts, catalogs, docs, and the lockfile follow. Adds the four settled FIXME rename markers (dsh-sdk-server, dsh-sdk-telemetry, dsh-sdk-helper, dsh-sdk-scripts). The scaffold folders diverge from their npm names until those renames land, so tsconfig.base.json maps the three affected names explicitly beside the group wildcard. Also repairs two pre-existing stale-path classes the strengthened sweep surfaced: docs/web-styling.md's retired web-ui host package and type-model spec fixture-literal joins. app-boot's three Loader-composition specs time out at the default 5s under full-suite parallel load on this filesystem (pre-existing; pass isolated with --testTimeout=30000); interaction/scaffold/boot suites otherwise green (687 passed).
97 lines
3.5 KiB
TypeScript
97 lines
3.5 KiB
TypeScript
/**
|
|
* Structured pnpm workspace configuration for generated SDK projects.
|
|
*
|
|
* @module @deepseek-ai/dsh-helper/documents/pnpm-workspace-file
|
|
*/
|
|
|
|
import {
|
|
isMap, isScalar, isSeq, parseDocument,
|
|
type Document, type Scalar, type YAMLMap, type YAMLSeq,
|
|
} from 'yaml'
|
|
import { ProjectFile, withTrailingNewline } from './project-file.ts'
|
|
|
|
function parseYaml(text: string): Document.Parsed {
|
|
const document = parseDocument(text, { keepSourceTokens: true, prettyErrors: true })
|
|
if (document.errors.length > 0) {
|
|
throw new Error(`invalid pnpm-workspace.yaml: ${document.errors.map(error => error.message).join('; ')}`)
|
|
}
|
|
if (!isMap(document.contents)) throw new Error('pnpm-workspace.yaml root must be an object')
|
|
return document
|
|
}
|
|
|
|
/** Generated pnpm-workspace.yaml model. */
|
|
export class PnpmWorkspaceFile extends ProjectFile {
|
|
private readonly document: Document.Parsed
|
|
|
|
private constructor(document: Document.Parsed, originalText?: string) {
|
|
super('pnpm-workspace.yaml', originalText)
|
|
this.document = document
|
|
}
|
|
|
|
/** Create a pnpm workspace document. */
|
|
static create(): PnpmWorkspaceFile {
|
|
const document = new PnpmWorkspaceFile(parseYaml('{}\n'))
|
|
document.mapping().set('packages', document.document.createNode([]))
|
|
document.mapping().set('allowBuilds', document.document.createNode({ esbuild: true }))
|
|
return document
|
|
}
|
|
|
|
/** Parse the workspace fields the SDK owns while retaining all other YAML. */
|
|
static parse(text: string): PnpmWorkspaceFile {
|
|
const document = new PnpmWorkspaceFile(parseYaml(text), text)
|
|
document.packageSequence()
|
|
const autoInstallPeers = document.mapping().get('autoInstallPeers')
|
|
if (autoInstallPeers !== undefined && typeof autoInstallPeers !== 'boolean') {
|
|
throw new Error('pnpm-workspace.yaml autoInstallPeers must be boolean')
|
|
}
|
|
return document
|
|
}
|
|
|
|
/** Clone the complete comment-preserving workspace document. */
|
|
override clone(): PnpmWorkspaceFile {
|
|
return new PnpmWorkspaceFile(parseYaml(this.serialize()), this.originalText)
|
|
}
|
|
|
|
/** Add one package workspace glob. */
|
|
addPackage(pattern: string): void {
|
|
const packages = this.packageSequence()
|
|
if (packages.items.some(item => item.value === pattern)) return
|
|
packages.add(this.document.createNode(pattern))
|
|
}
|
|
|
|
/** Disable registry peer auto-installation for live-link projects. */
|
|
disableAutoInstallPeers(): void {
|
|
this.mapping().set('autoInstallPeers', false)
|
|
}
|
|
|
|
/** Validate workspace globs. */
|
|
override validate(): void {
|
|
for (const pattern of this.packageValues()) {
|
|
if (pattern.trim().length === 0) throw new Error('pnpm workspace pattern must not be empty')
|
|
}
|
|
}
|
|
|
|
/** Serialize the workspace while retaining unknown settings and comments. */
|
|
override serialize(): string {
|
|
return withTrailingNewline(this.document.toString({ lineWidth: 0 }))
|
|
}
|
|
|
|
private mapping(): YAMLMap {
|
|
/* v8 ignore next -- parseYaml and create both establish a mapping root */
|
|
if (!isMap(this.document.contents)) throw new Error('pnpm-workspace.yaml root must be an object')
|
|
return this.document.contents
|
|
}
|
|
|
|
private packageSequence(): YAMLSeq<Scalar<string>> {
|
|
const packages = this.mapping().get('packages', true)
|
|
if (!isSeq(packages) || packages.items.some(item => !isScalar(item) || typeof item.value !== 'string')) {
|
|
throw new Error('pnpm-workspace.yaml packages must be an array of strings')
|
|
}
|
|
return packages as YAMLSeq<Scalar<string>>
|
|
}
|
|
|
|
private packageValues(): string[] {
|
|
return this.packageSequence().items.map(item => item.value)
|
|
}
|
|
}
|