Buckets:
| import path from "path" | |
| import { fileURLToPath } from "url" | |
| import { Schema } from "effect" | |
| type BaseReference = { | |
| readonly host: string | |
| readonly path: string | |
| readonly segments: string[] | |
| readonly owner?: string | |
| readonly repo: string | |
| readonly remote: string | |
| readonly label: string | |
| } | |
| export type RemoteReference = BaseReference & { | |
| readonly protocol?: string | |
| } | |
| export type FileReference = BaseReference & { | |
| readonly host: "file" | |
| readonly protocol: "file:" | |
| } | |
| export type Reference = RemoteReference | FileReference | |
| export class InvalidReferenceError extends Schema.TaggedErrorClass<InvalidReferenceError>()( | |
| "RepositoryInvalidReferenceError", | |
| { | |
| repository: Schema.String, | |
| message: Schema.String, | |
| }, | |
| ) {} | |
| export class UnsupportedLocalRepositoryError extends Schema.TaggedErrorClass<UnsupportedLocalRepositoryError>()( | |
| "RepositoryUnsupportedLocalRepositoryError", | |
| { | |
| repository: Schema.String, | |
| message: Schema.String, | |
| }, | |
| ) {} | |
| export class InvalidBranchError extends Schema.TaggedErrorClass<InvalidBranchError>()("RepositoryInvalidBranchError", { | |
| branch: Schema.String, | |
| message: Schema.String, | |
| }) {} | |
| export type Error = InvalidReferenceError | UnsupportedLocalRepositoryError | InvalidBranchError | |
| export function isError(error: unknown): error is Error { | |
| return ( | |
| error instanceof InvalidReferenceError || | |
| error instanceof UnsupportedLocalRepositoryError || | |
| error instanceof InvalidBranchError | |
| ) | |
| } | |
| export function parse(input: string): Reference | undefined { | |
| const cleaned = normalizeInput(input) | |
| if (!cleaned) return | |
| const githubPrefixed = cleaned.match(/^github:([^/\s]+)\/([^/\s]+)$/) | |
| if (githubPrefixed) return buildRemote({ host: "github.com", segments: [githubPrefixed[1], githubPrefixed[2]] }) | |
| if (!cleaned.includes("://")) { | |
| const scp = cleaned.match(/^(?:[^@/\s]+@)?([^:/\s]+):(.+)$/) | |
| if (scp) return buildRemote({ host: scp[1], segments: parts(scp[2]), remote: cleaned }) | |
| const direct = parts(cleaned) | |
| if (direct.length >= 2 && hostLike(direct[0])) return buildRemote({ host: direct[0], segments: direct.slice(1) }) | |
| if (direct.length === 2) return buildRemote({ host: "github.com", segments: direct }) | |
| } | |
| try { | |
| const url = new URL(cleaned) | |
| if (url.protocol === "file:") return buildFile({ url, remote: cleaned }) | |
| const segments = parts(url.pathname) | |
| return buildRemote({ | |
| host: url.host, | |
| segments, | |
| remote: url.host === "github.com" ? githubRemote(segments.join("/")) : cleaned, | |
| protocol: url.protocol, | |
| }) | |
| } catch { | |
| return | |
| } | |
| } | |
| export function parseRemote(input: string): RemoteReference { | |
| const reference = parse(input) | |
| if (!reference) { | |
| throw new InvalidReferenceError({ | |
| repository: input, | |
| message: "Repository must be a git URL, host/path reference, or GitHub owner/repo shorthand", | |
| }) | |
| } | |
| if (!isRemote(reference)) { | |
| throw new UnsupportedLocalRepositoryError({ | |
| repository: input, | |
| message: "Local file repositories are not supported", | |
| }) | |
| } | |
| return reference | |
| } | |
| export function validateBranch(branch: string): void { | |
| if (/^[A-Za-z0-9/_.-]+$/.test(branch) && !branch.startsWith("-") && !branch.includes("..")) return | |
| throw new InvalidBranchError({ | |
| branch, | |
| message: "Branch must contain only alphanumeric characters, /, _, ., and -, and cannot start with - or contain ..", | |
| }) | |
| } | |
| export function isFile(reference: Reference): reference is FileReference { | |
| return reference.protocol === "file:" | |
| } | |
| export function isRemote(reference: Reference): reference is RemoteReference { | |
| return !isFile(reference) | |
| } | |
| export function cachePath(root: string, reference: Reference): string { | |
| return path.join(root, ...reference.host.split(":"), ...reference.segments) | |
| } | |
| export function cacheIdentity(reference: Reference): string { | |
| return `${reference.host}/${reference.path}` | |
| } | |
| export function same(left: Reference, right: Reference): boolean { | |
| return cacheIdentity(left) === cacheIdentity(right) | |
| } | |
| function normalizeInput(input: string) { | |
| return input | |
| .trim() | |
| .replace(/^git\+/, "") | |
| .replace(/#.*$/, "") | |
| .replace(/\/+$/, "") | |
| } | |
| function trimGitSuffix(input: string) { | |
| return input.replace(/\.git$/, "") | |
| } | |
| function parts(input: string) { | |
| return input | |
| .split("/") | |
| .map((item) => trimGitSuffix(item.trim())) | |
| .filter(Boolean) | |
| } | |
| function safeHost(input: string) { | |
| return Boolean(input) && !input.startsWith("-") && !/[\s/\\]/.test(input) | |
| } | |
| function safeSegment(input: string) { | |
| return input !== "." && input !== ".." && !input.includes(":") && !/[\s/\\]/.test(input) | |
| } | |
| function hostLike(input: string) { | |
| return input.includes(".") || input.includes(":") || input === "localhost" | |
| } | |
| function withSlash(input: string) { | |
| return input.endsWith("/") ? input : `${input}/` | |
| } | |
| function githubRemote(pathname: string) { | |
| const base = process.env.OPENCODE_REPO_CLONE_GITHUB_BASE_URL | |
| if (!base) return `https://github.com/${pathname}.git` | |
| return new URL(`${pathname}.git`, withSlash(base)).href | |
| } | |
| function buildRemote(input: { host: string; segments: string[]; remote?: string; protocol?: string }) { | |
| const segments = input.segments.map(trimGitSuffix).filter(Boolean) | |
| if (!safeHost(input.host) || !segments.length || segments.some((segment) => !safeSegment(segment))) return | |
| const repositoryPath = segments.join("/") | |
| const host = input.host.toLowerCase() | |
| return { | |
| host, | |
| path: repositoryPath, | |
| segments, | |
| owner: segments.length === 2 ? segments[0] : undefined, | |
| repo: segments[segments.length - 1], | |
| remote: | |
| input.remote ?? (host === "github.com" ? githubRemote(repositoryPath) : `https://${host}/${repositoryPath}.git`), | |
| label: host === "github.com" && segments.length === 2 ? repositoryPath : `${host}/${repositoryPath}`, | |
| protocol: input.protocol, | |
| } satisfies RemoteReference | |
| } | |
| function buildFile(input: { url: URL; remote: string }) { | |
| const filePath = path.normalize(fileURLToPath(input.url)) | |
| const segments = filePath.split(/[\\/]+/).filter(Boolean) | |
| if (!segments.length) return | |
| return { | |
| host: "file", | |
| path: filePath, | |
| segments: segments.map((segment) => segment.replace(/:$/, "")), | |
| owner: undefined, | |
| repo: trimGitSuffix(segments[segments.length - 1]), | |
| remote: input.remote, | |
| label: filePath, | |
| protocol: "file:", | |
| } satisfies FileReference | |
| } | |
| export * as Repository from "./repository" | |
Xet Storage Details
- Size:
- 6.44 kB
- Xet hash:
- 3cd1a7b2339cc3cba606181cc86c7c86725bcddaa3cb6da9031c0504a789f0b5
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.