Add RepositoryService with full CRUD, ID resolution helpers, input validation, six SvelteKit API routes (GET/POST /api/v1/libs, GET/PATCH/DELETE /api/v1/libs/:id, POST /api/v1/libs/:id/index), and 37 unit tests covering all service operations. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
43 lines
1.1 KiB
TypeScript
43 lines
1.1 KiB
TypeScript
/**
|
|
* Repository ID generation utilities.
|
|
*/
|
|
|
|
/**
|
|
* Parse a GitHub URL into a canonical repository ID.
|
|
* Supports:
|
|
* https://github.com/facebook/react
|
|
* https://github.com/facebook/react.git
|
|
* github.com/facebook/react
|
|
*/
|
|
export function resolveGitHubId(url: string): string {
|
|
const match = url.match(/github\.com\/([^/]+)\/([^/\s.]+)/);
|
|
if (!match) throw new Error('Invalid GitHub URL — expected github.com/owner/repo');
|
|
return `/${match[1]}/${match[2]}`;
|
|
}
|
|
|
|
/**
|
|
* Generate a local repository ID from an absolute path.
|
|
* Collision-resolves by appending -2, -3, etc.
|
|
*/
|
|
export function resolveLocalId(path: string, existingIds: string[]): string {
|
|
const base = slugify(path.split('/').at(-1) ?? 'repo');
|
|
let id = `/local/${base}`;
|
|
let counter = 2;
|
|
while (existingIds.includes(id)) {
|
|
id = `/local/${base}-${counter++}`;
|
|
}
|
|
return id;
|
|
}
|
|
|
|
/**
|
|
* Slugify a string to be safe for use in IDs.
|
|
*/
|
|
function slugify(str: string): string {
|
|
return str
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9-_]/g, '-')
|
|
.replace(/-+/g, '-')
|
|
.replace(/^-|-$/g, '')
|
|
|| 'repo';
|
|
}
|