fix(sdk): address remaining tooling review findings

This commit is contained in:
imccyu
2026-07-15 23:08:06 +08:00
parent d8f6251e3a
commit 394706fa3c
12 changed files with 236 additions and 52 deletions

View File

@@ -135,9 +135,11 @@ export class CordisYamlFile extends ProjectFile {
}
/** Add one new top-level entry, rejecting duplicate ids. */
addEntry(entry: CordisConfigEntry): void {
addEntry(entry: CordisConfigEntry, commentedExample?: string): void {
if (this.entryNode(entry.id)) throw new Error(`Cordis config entry already exists: ${entry.id}`)
this.sequence().items.push(this.document.createNode(entry))
const node = this.document.createNode(entry)
if (commentedExample) node.comment = commentedExample.split('\n').map(line => ` ${line}`).join('\n')
this.sequence().items.push(node)
}
/** Remove an entry by id and report whether it existed. */

View File

@@ -4,73 +4,93 @@
* @module @deepseek-ai/dsh-helper/documents/pnpm-workspace-file
*/
import { parse, stringify } from 'yaml'
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 packages = new Set<string>()
private autoInstallPeers = true
private readonly document: Document.Parsed
private constructor(originalText?: string) {
private constructor(document: Document.Parsed, originalText?: string) {
super('pnpm-workspace.yaml', originalText)
this.document = document
}
/** Create a pnpm workspace document. */
static create(): PnpmWorkspaceFile {
return new PnpmWorkspaceFile()
}
/** Parse the workspace fields the SDK owns. */
static parse(text: string): PnpmWorkspaceFile {
const value: unknown = parse(text)
if (value === null || Array.isArray(value) || typeof value !== 'object') {
throw new Error('pnpm-workspace.yaml root must be an object')
}
const input = value as Record<string, unknown>
if (!Array.isArray(input.packages) || input.packages.some(item => typeof item !== 'string')) {
throw new Error('pnpm-workspace.yaml packages must be an array of strings')
}
const document = new PnpmWorkspaceFile(text)
for (const pattern of input.packages) document.packages.add(pattern as string)
if (input.autoInstallPeers !== undefined && typeof input.autoInstallPeers !== 'boolean') {
throw new Error('pnpm-workspace.yaml autoInstallPeers must be boolean')
}
document.autoInstallPeers = input.autoInstallPeers !== false
const document = new PnpmWorkspaceFile(parseYaml('{}\n'))
document.mapping().set('packages', document.document.createNode([]))
document.mapping().set('allowBuilds', document.document.createNode({ esbuild: true }))
return document
}
/** Clone workspace globs and peer-install policy. */
/** 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 {
const clone = new PnpmWorkspaceFile(this.originalText)
for (const pattern of this.packages) clone.packages.add(pattern)
clone.autoInstallPeers = this.autoInstallPeers
return clone
return new PnpmWorkspaceFile(parseYaml(this.serialize()), this.originalText)
}
/** Add one package workspace glob. */
addPackage(pattern: string): void {
this.packages.add(pattern)
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.autoInstallPeers = false
this.mapping().set('autoInstallPeers', false)
}
/** Validate workspace globs. */
override validate(): void {
for (const pattern of this.packages) {
for (const pattern of this.packageValues()) {
if (pattern.trim().length === 0) throw new Error('pnpm workspace pattern must not be empty')
}
}
/** Serialize pnpm's workspace and peer policy. */
/** Serialize the workspace while retaining unknown settings and comments. */
override serialize(): string {
return withTrailingNewline(stringify({
packages: [...this.packages].sort(),
...this.autoInstallPeers ? {} : { autoInstallPeers: false },
allowBuilds: { esbuild: true },
}, { lineWidth: 0 }))
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)
}
}