(params: FetchParams)
| 270 | * converted to rulesync format, and written to the output directory. |
| 271 | */ |
| 272 | export async function fetchFiles(params: FetchParams): Promise<FetchSummary> { |
| 273 | const { source, options = {}, outputRoot = process.cwd(), logger } = params; |
| 274 | |
| 275 | // Parse source |
| 276 | const parsed = parseSource(source); |
| 277 | |
| 278 | // Check if provider is supported |
| 279 | if (parsed.provider === "gitlab") { |
| 280 | throw new Error( |
| 281 | "GitLab is not yet supported. Currently only GitHub repositories are supported.", |
| 282 | ); |
| 283 | } |
| 284 | |
| 285 | // Resolve options |
| 286 | const resolvedRef = options.ref ?? parsed.ref; |
| 287 | // Normalize backslashes to forward slashes for GitHub API compatibility. |
| 288 | const resolvedPath = toPosixPath(options.path ?? parsed.path ?? "."); |
| 289 | const outputDir = options.output ?? RULESYNC_RELATIVE_DIR_PATH; |
| 290 | const conflictStrategy: ConflictStrategy = options.conflict ?? "overwrite"; |
| 291 | const enabledFeatures = resolveFeatures(options.features); |
| 292 | const target: FetchTarget = options.target ?? "rulesync"; |
| 293 | |
| 294 | // Validate output directory to prevent path traversal attacks |
| 295 | checkPathTraversal({ |
| 296 | relativePath: outputDir, |
| 297 | intendedRootDir: outputRoot, |
| 298 | }); |
| 299 | |
| 300 | // Initialize GitHub client |
| 301 | const token = GitHubClient.resolveToken(options.token); |
| 302 | const client = new GitHubClient({ token }); |
| 303 | |
| 304 | // Validate repository |
| 305 | logger.debug(`Validating repository: ${parsed.owner}/${parsed.repo}`); |
| 306 | const isValid = await client.validateRepository(parsed.owner, parsed.repo); |
| 307 | if (!isValid) { |
| 308 | throw new GitHubClientError( |
| 309 | `Repository not found: ${parsed.owner}/${parsed.repo}. Check the repository name and your access permissions.`, |
| 310 | 404, |
| 311 | ); |
| 312 | } |
| 313 | |
| 314 | // Resolve ref to use |
| 315 | const ref = resolvedRef ?? (await client.getDefaultBranch(parsed.owner, parsed.repo)); |
| 316 | logger.debug(`Using ref: ${ref}`); |
| 317 | |
| 318 | // If target is a tool format, use conversion flow |
| 319 | if (isToolTarget(target)) { |
| 320 | return fetchAndConvertToolFiles({ |
| 321 | client, |
| 322 | parsed, |
| 323 | ref, |
| 324 | resolvedPath, |
| 325 | enabledFeatures, |
| 326 | target, |
| 327 | outputDir, |
| 328 | outputRoot, |
| 329 | conflictStrategy, |
no test coverage detected
searching dependent graphs…