65 lines
2.0 KiB
TypeScript
65 lines
2.0 KiB
TypeScript
/**
|
|
* Base abstraction for one file in an SDK project snapshot.
|
|
*
|
|
* @module @deepseek-ai/dsh-helper/documents/project-file
|
|
*/
|
|
|
|
/** Return text with exactly one trailing newline. */
|
|
export function withTrailingNewline(text: string): string {
|
|
return text.replace(/\n*$/, '') + '\n'
|
|
}
|
|
|
|
/** One cloneable, validatable project file. */
|
|
export abstract class ProjectFile {
|
|
/** Project-relative POSIX path. */
|
|
readonly relativePath: string
|
|
|
|
/** Text observed when the document entered the snapshot; absent for a new file. */
|
|
readonly originalText: string | undefined
|
|
|
|
/** Permission bits used only when the file is first created. */
|
|
readonly createMode: number | undefined
|
|
|
|
protected constructor(relativePath: string, originalText?: string, createMode?: number) {
|
|
if (relativePath.startsWith('/') || relativePath.split('/').includes('..')) {
|
|
throw new Error(`project document path must stay inside the project: ${relativePath}`)
|
|
}
|
|
this.relativePath = relativePath
|
|
this.originalText = originalText
|
|
this.createMode = createMode
|
|
}
|
|
|
|
/** Clone the document for an isolated edit session. */
|
|
abstract clone(): ProjectFile
|
|
|
|
/** Validate the document's complete current state. */
|
|
abstract validate(): void
|
|
|
|
/** Serialize the complete current file. */
|
|
abstract serialize(): string
|
|
}
|
|
|
|
/** Immutable complete-text file used by one-shot artifacts. */
|
|
export class TextProjectFile extends ProjectFile {
|
|
private readonly text: string
|
|
|
|
/** Create a complete-text project document. */
|
|
constructor(relativePath: string, text: string, originalText?: string) {
|
|
super(relativePath, originalText)
|
|
this.text = withTrailingNewline(text)
|
|
}
|
|
|
|
/** Clone this immutable document. */
|
|
override clone(): TextProjectFile {
|
|
return new TextProjectFile(this.relativePath, this.text, this.originalText)
|
|
}
|
|
|
|
/** Complete text artifacts have no extra structural validation. */
|
|
override validate(): void {}
|
|
|
|
/** Return the complete artifact text. */
|
|
override serialize(): string {
|
|
return this.text
|
|
}
|
|
}
|