SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
68d7816 verified
Raw
History Blame Contribute Delete
2.64 kB
import path from 'node:path';
import { Error2, ErrorCodes } from '#/errors';
export interface GithubRef {
readonly kind: 'branch' | 'tag' | 'sha';
readonly value: string;
}
export type ResolvedSource =
| { kind: 'local-path'; path: string }
| { kind: 'zip-url'; path: string }
| { kind: 'github'; owner: string; repo: string; ref?: GithubRef };
export type InstallSource = ResolvedSource;
const SHA_RE = /^[0-9a-f]{7,40}$/;
export function resolveInstallSource(source: string): ResolvedSource {
const trimmed = source.trim();
const github = parseGithubUrl(trimmed);
if (github !== undefined) return github;
if (trimmed.startsWith('http://') || trimmed.startsWith('https://')) {
return { kind: 'zip-url', path: trimmed };
}
if (!path.isAbsolute(trimmed)) {
throw new Error2(
ErrorCodes.VALIDATION_FAILED,
`Plugin root must be an absolute path (got "${source}")`,
{ details: { source } },
);
}
return { kind: 'local-path', path: trimmed };
}
function parseGithubUrl(raw: string): ResolvedSource | undefined {
let url: URL;
try {
url = new URL(raw);
} catch {
return undefined;
}
if (url.protocol !== 'https:') return undefined;
if (url.hostname !== 'github.com' && url.hostname !== 'www.github.com') return undefined;
const segments = url.pathname.split('/').filter((s) => s.length > 0);
const owner = segments[0];
const repoRaw = segments[1];
if (owner === undefined || repoRaw === undefined) return undefined;
const repo = repoRaw.endsWith('.git') ? repoRaw.slice(0, -4) : repoRaw;
const rest = segments.slice(2);
if (rest.length === 0) {
return { kind: 'github', owner, repo };
}
const head = rest[0];
const second = rest[1];
if (head === 'tree' && rest.length >= 2) {
const refValue = decodeRefSegments(rest.slice(1));
const kind: GithubRef['kind'] = SHA_RE.test(refValue) ? 'sha' : 'branch';
return { kind: 'github', owner, repo, ref: { kind, value: refValue } };
}
if (head === 'releases' && second === 'tag' && rest.length >= 3) {
const tag = decodeRefSegments(rest.slice(2));
return { kind: 'github', owner, repo, ref: { kind: 'tag', value: tag } };
}
if (head === 'commit' && rest.length >= 2) {
const sha = decodeRefSegments(rest.slice(1));
return { kind: 'github', owner, repo, ref: { kind: 'sha', value: sha } };
}
return undefined;
}
function decodeRefSegments(segments: readonly string[]): string {
return segments
.map((segment) => {
try {
return decodeURIComponent(segment);
} catch {
return segment;
}
})
.join('/');
}