| import { ErrorCodes, Error2 } from '#/errors'; |
| import { getShellPathBridge } from '#/_base/execEnv/shellPathBridge'; |
|
|
| import type { Runtime, RuntimeBinding, RuntimeWorkspaceRoots } from './runtime'; |
|
|
| export type { RuntimeWorkspaceRoots } from './runtime'; |
|
|
| export class RuntimeWorkspaceView { |
| readonly binding: RuntimeBinding; |
| readonly generation: string; |
| readonly workDir: string; |
| readonly additionalDirs: readonly string[]; |
| readonly roots: readonly string[]; |
|
|
| constructor( |
| readonly runtime: Runtime, |
| roots: RuntimeWorkspaceRoots, |
| ) { |
| this.binding = { |
| workspaceId: runtime.identity.workspaceId, |
| runtimeId: runtime.identity.runtimeId, |
| }; |
| this.generation = runtime.identity.generation; |
| const mapped = runtime.workspace.mapRoots(roots); |
| this.workDir = runtime.path.resolve(mapped.workDir); |
| this.additionalDirs = [...new Set((mapped.additionalDirs ?? []).map((root) => runtime.path.resolve(root)))]; |
| this.roots = [this.workDir, ...this.additionalDirs]; |
| } |
|
|
| resolve(path: string, cwd = this.workDir): string { |
| const env = this.runtime.environment; |
| const bridged = env.pathClass === 'win32' ? getShellPathBridge(env).fromShellPath(path) : path; |
| return this.runtime.path.isAbsolute(bridged) |
| ? this.runtime.path.resolve(bridged) |
| : this.runtime.path.resolve(cwd, bridged); |
| } |
|
|
| assertAllowed(path: string): string { |
| const resolved = this.runtime.path.resolve(path); |
| if (this.roots.some((root) => contains(this.runtime, root, resolved))) return resolved; |
| throw new Error2( |
| ErrorCodes.FS_PATH_ESCAPES, |
| `path ${path} is outside runtime workspace ${this.binding.runtimeId}`, |
| { details: { path: resolved } }, |
| ); |
| } |
| } |
|
|
| function contains(runtime: Runtime, root: string, candidate: string): boolean { |
| const relative = runtime.path.relative(root, candidate); |
| if (relative === '') return true; |
| return relative !== '..' && !relative.startsWith(`..${runtime.path.separator}`) && !runtime.path.isAbsolute(relative); |
| } |
|
|