UNPKG

@langchain/community

Version:
1 lines 30.8 kB
{"version":3,"file":"github.cjs","names":["binaryExtensions","extname","BaseDocumentLoader","UnknownHandling","AsyncCaller","Document"],"sources":["../../../src/document_loaders/web/github.ts"],"sourcesContent":["import ignore, { Ignore } from \"ignore\";\nimport binaryExtensions from \"binary-extensions\";\n\nimport { Document } from \"@langchain/core/documents\";\nimport { getEnvironmentVariable } from \"@langchain/core/utils/env\";\nimport {\n AsyncCaller,\n AsyncCallerParams,\n} from \"@langchain/core/utils/async_caller\";\nimport { BaseDocumentLoader } from \"@langchain/core/document_loaders/base\";\nimport { UnknownHandling } from \"@langchain/classic/document_loaders/fs/directory\";\nimport { extname } from \"../../utils/extname.js\";\n\nconst extensions = /* #__PURE__ */ new Set(binaryExtensions);\n\n/**\n * A function that checks if a file path is a binary file based on its\n * extension.\n * @param name The file path to check.\n * @returns A boolean indicating whether the file path is a binary file.\n */\nfunction isBinaryPath(name: string) {\n return extensions.has(extname(name).slice(1).toLowerCase());\n}\n\n/**\n * An interface that represents a file in a GitHub repository. It has\n * properties for the file name, path, SHA, size, URLs, type, and links.\n */\nexport interface GithubFile {\n name: string;\n path: string;\n sha: string;\n size: number;\n url: string;\n html_url: string;\n git_url: string;\n download_url: string;\n type: string;\n _links: {\n self: string;\n git: string;\n html: string;\n };\n}\n\n/**\n * An interface that represents the response from fetching the content of\n * a file. It has properties for the file contents and metadata.\n */\ninterface GetContentResponse {\n contents: string;\n metadata: { source: string; repository: string; branch: string };\n}\n\n/**\n * An interface describing the submodules of a Git repository.\n */\ninterface SubmoduleInfo {\n name: string;\n path: string;\n url: string;\n ref: string;\n}\n\n/**\n * An interface that represents the parameters for the GithubRepoLoader\n * class. It extends the AsyncCallerParams interface and adds additional\n * properties specific to the GitHub repository loader.\n */\nexport interface GithubRepoLoaderParams extends AsyncCallerParams {\n /**\n * The base URL of the GitHub instance.\n * To be used when you are not targeting github.com, e.g. a GitHub Enterprise instance.\n */\n baseUrl?: string;\n /**\n * The API endpoint URL of the GitHub instance.\n * To be used when you are not targeting github.com, e.g. a GitHub Enterprise instance.\n */\n apiUrl?: string;\n branch?: string;\n recursive?: boolean;\n /**\n * Set to true to recursively process submodules. Is only effective, when recursive=true.\n */\n processSubmodules?: boolean;\n unknown?: UnknownHandling;\n accessToken?: string;\n ignoreFiles?: (string | RegExp)[];\n ignorePaths?: string[];\n verbose?: boolean;\n /**\n * The maximum number of concurrent calls that can be made. Defaults to 2.\n */\n maxConcurrency?: number;\n /**\n * The maximum number of retries that can be made for a single call,\n * with an exponential backoff between each attempt. Defaults to 2.\n */\n maxRetries?: number;\n}\n\n/**\n * A class that extends the BaseDocumentLoader and implements the\n * GithubRepoLoaderParams interface. It represents a document loader for\n * loading files from a GitHub repository.\n */\nexport class GithubRepoLoader\n extends BaseDocumentLoader\n implements GithubRepoLoaderParams\n{\n public baseUrl: string;\n\n public apiUrl: string;\n\n private readonly owner: string;\n\n private readonly repo: string;\n\n private readonly initialPath: string;\n\n private headers: Record<string, string> = {};\n\n public branch: string;\n\n public recursive: boolean;\n\n public processSubmodules: boolean;\n\n public unknown: UnknownHandling;\n\n public accessToken?: string;\n\n public ignoreFiles: (string | RegExp)[];\n\n public ignore?: Ignore;\n\n public verbose?: boolean;\n\n public maxConcurrency?: number;\n\n public maxRetries?: number;\n\n protected caller: AsyncCaller;\n\n public ignorePaths?: string[];\n\n private submoduleInfos: SubmoduleInfo[];\n\n constructor(\n githubUrl: string,\n {\n accessToken = getEnvironmentVariable(\"GITHUB_ACCESS_TOKEN\"),\n baseUrl = \"https://github.com\",\n apiUrl = \"https://api.github.com\",\n branch = \"main\",\n recursive = true,\n processSubmodules = false,\n unknown = UnknownHandling.Warn,\n ignoreFiles = [],\n ignorePaths,\n verbose = false,\n maxConcurrency = 2,\n maxRetries = 2,\n ...rest\n }: GithubRepoLoaderParams = {}\n ) {\n super();\n this.baseUrl = baseUrl;\n this.apiUrl = apiUrl;\n const { owner, repo, path } = this.extractOwnerAndRepoAndPath(githubUrl);\n this.owner = owner;\n this.repo = repo;\n this.initialPath = path;\n this.branch = branch;\n this.recursive = recursive;\n // processing submodules without processing contents of other directories makes no sense\n if (processSubmodules && !recursive) {\n throw new Error(\n `Input property \"recursive\" must be true if \"processSubmodules\" is true.`\n );\n }\n this.processSubmodules = processSubmodules;\n this.unknown = unknown;\n this.accessToken = accessToken;\n this.ignoreFiles = ignoreFiles;\n this.verbose = verbose;\n this.maxConcurrency = maxConcurrency;\n this.maxRetries = maxRetries;\n this.headers = {\n \"User-Agent\": \"langchain\",\n };\n this.caller = new AsyncCaller({\n maxConcurrency,\n maxRetries,\n ...rest,\n });\n this.ignorePaths = ignorePaths;\n if (ignorePaths) {\n this.ignore = ignore().add(ignorePaths);\n }\n if (this.accessToken) {\n this.headers = {\n ...this.headers,\n Authorization: `Bearer ${this.accessToken}`,\n };\n }\n }\n\n /**\n * Extracts the owner, repository, and path from a GitHub URL.\n * @param url The GitHub URL to extract information from.\n * @returns An object containing the owner, repository, and path extracted from the GitHub URL.\n */\n private extractOwnerAndRepoAndPath(url: string): {\n owner: string;\n repo: string;\n path: string;\n } {\n const match = url.match(\n new RegExp(`${this.baseUrl}/([^/]+)/([^/]+)(/tree/[^/]+/(.+))?`, \"i\")\n );\n\n if (!match) {\n throw new Error(\"Invalid GitHub URL format.\");\n }\n\n return { owner: match[1], repo: match[2], path: match[4] || \"\" };\n }\n\n /**\n * Fetches the files from the GitHub repository and creates Document\n * instances for each file. It also handles error handling based on the\n * unknown handling option.\n * @returns A promise that resolves to an array of Document instances.\n */\n public async load(): Promise<Document[]> {\n this.log(\n `Loading documents from ${this.baseUrl}/${this.owner}/${this.repo}/${this.initialPath}...`\n );\n // process repository without submodules\n const documents: Document[] = (await this.processRepo()).map(\n (fileResponse) =>\n new Document({\n pageContent: fileResponse.contents,\n metadata: fileResponse.metadata,\n })\n );\n if (this.processSubmodules) {\n // process submodules\n await this.getSubmoduleInfo();\n for (const submoduleInfo of this.submoduleInfos) {\n documents.push(...(await this.loadSubmodule(submoduleInfo)));\n }\n }\n return documents;\n }\n\n /**\n * Asynchronously streams documents from the entire GitHub repository.\n * It is suitable for situations where processing large repositories in a memory-efficient manner is required.\n * @yields Yields a Promise that resolves to a Document object for each file or submodule content found in the repository.\n */\n public async *loadAsStream(): AsyncGenerator<Document, void, undefined> {\n this.log(\n `Loading documents from ${this.baseUrl}/${this.owner}/${this.repo}/${this.initialPath}...`\n );\n yield* await this.processRepoAsStream(this.initialPath);\n\n if (!this.processSubmodules) {\n return;\n }\n\n await this.getSubmoduleInfo();\n for (const submoduleInfo of this.submoduleInfos) {\n yield* await this.loadSubmoduleAsStream(submoduleInfo);\n }\n }\n\n /**\n * Loads the information about Git submodules from the repository, if available.\n */\n private async getSubmoduleInfo(): Promise<void> {\n this.log(\"Loading info about submodules...\");\n // we have to fetch the files of the root directory to get the download url of the .gitmodules file\n // however, we cannot reuse the files retrieved in processRepo() as initialPath may be != \"\"\n // so it may be that we end up fetching this file list twice\n const repoFiles = await this.fetchRepoFiles(\"\");\n const gitmodulesFile = repoFiles.filter(\n ({ name }) => name === \".gitmodules\"\n )?.[0];\n if (gitmodulesFile) {\n const gitmodulesContent = await this.fetchFileContent({\n download_url: gitmodulesFile.download_url,\n } as GithubFile);\n this.submoduleInfos = await this.parseGitmodules(gitmodulesContent);\n } else {\n this.submoduleInfos = [];\n }\n this.log(`Found ${this.submoduleInfos.length} submodules:`);\n for (const submoduleInfo of this.submoduleInfos) {\n this.log(JSON.stringify(submoduleInfo));\n }\n }\n\n /**\n * Parses the given content of a .gitmodules file. Furthermore, queries the current SHA ref of all submodules.\n * Returns the submodule information as array.\n * @param gitmodulesContent the content of a .gitmodules file\n */\n private async parseGitmodules(\n gitmodulesContent: string\n ): Promise<SubmoduleInfo[]> {\n let validGitmodulesContent = gitmodulesContent;\n // in case the .gitmodules file does not end with a newline, we add one to make the regex work\n if (!validGitmodulesContent.endsWith(\"\\n\")) {\n validGitmodulesContent += \"\\n\";\n }\n // catches the initial line of submodule entries\n const submodulePattern = /\\[submodule \"(.*?)\"]\\n((\\s+.*?\\s*=\\s*.*?\\n)*)/g;\n // catches the properties of a submodule\n const keyValuePattern = /\\s+(.*?)\\s*=\\s*(.*?)\\s/g;\n\n const submoduleInfos = [];\n for (const [, name, propertyLines] of validGitmodulesContent.matchAll(\n submodulePattern\n )) {\n if (!name || !propertyLines) {\n throw new Error(\"Could not parse submodule entry\");\n }\n const submodulePropertyLines = propertyLines.matchAll(keyValuePattern);\n let path;\n let url;\n for (const [, key, value] of submodulePropertyLines) {\n if (!key || !value) {\n throw new Error(\n `Could not parse key/value pairs for submodule ${name}`\n );\n }\n switch (key) {\n case \"path\":\n path = value;\n break;\n case \"url\":\n url = value;\n if (url.endsWith(\".git\")) {\n url = url.substring(0, url.length - 4);\n }\n break;\n default:\n // ignoring unused keys\n }\n }\n if (!path || !url) {\n throw new Error(`Missing properties for submodule ${name}`);\n }\n // fetch the current ref of the submodule\n const files = await this.fetchRepoFiles(path);\n const submoduleInfo: SubmoduleInfo = {\n name,\n path,\n url,\n ref: files[0].sha,\n };\n submoduleInfos.push(submoduleInfo);\n }\n return submoduleInfos;\n }\n\n /**\n * Loads the documents of the given submodule. Uses the same parameters as for the current repository.\n * External submodules, i.e. submodules pointing to another GitHub instance, are ignored.\n * @param submoduleInfo the info about the submodule to be loaded\n */\n private async loadSubmodule(\n submoduleInfo: SubmoduleInfo\n ): Promise<Document[]> {\n if (!submoduleInfo.url.startsWith(this.baseUrl)) {\n this.log(`Ignoring external submodule ${submoduleInfo.url}.`);\n return [];\n } else if (!submoduleInfo.path.startsWith(this.initialPath)) {\n this.log(\n `Ignoring submodule ${submoduleInfo.url}, as it is not on initial path.`\n );\n return [];\n } else {\n this.log(\n `Accessing submodule ${submoduleInfo.name} (${submoduleInfo.url})...`\n );\n return new GithubRepoLoader(submoduleInfo.url, {\n accessToken: this.accessToken,\n apiUrl: this.apiUrl,\n baseUrl: this.baseUrl,\n branch: submoduleInfo.ref,\n recursive: this.recursive,\n processSubmodules: this.processSubmodules,\n unknown: this.unknown,\n ignoreFiles: this.ignoreFiles,\n ignorePaths: this.ignorePaths,\n verbose: this.verbose,\n maxConcurrency: this.maxConcurrency,\n maxRetries: this.maxRetries,\n }).load();\n }\n }\n\n /**\n * Asynchronously processes and streams the contents of a specified submodule in the GitHub repository.\n * @param submoduleInfo the info about the submodule to be loaded\n * @yields Yields a Promise that resolves to a Document object for each file found in the submodule.\n */\n private async *loadSubmoduleAsStream(\n submoduleInfo: SubmoduleInfo\n ): AsyncGenerator<Document, void, undefined> {\n if (!submoduleInfo.url.startsWith(this.baseUrl)) {\n this.log(`Ignoring external submodule ${submoduleInfo.url}.`);\n yield* [];\n }\n\n if (!submoduleInfo.path.startsWith(this.initialPath)) {\n this.log(\n `Ignoring submodule ${submoduleInfo.url}, as it is not on initial path.`\n );\n yield* [];\n }\n\n this.log(\n `Accessing submodule ${submoduleInfo.name} (${submoduleInfo.url})...`\n );\n const submoduleLoader = new GithubRepoLoader(submoduleInfo.url, {\n accessToken: this.accessToken,\n baseUrl: this.baseUrl,\n apiUrl: this.apiUrl,\n branch: submoduleInfo.ref,\n recursive: this.recursive,\n processSubmodules: this.processSubmodules,\n unknown: this.unknown,\n ignoreFiles: this.ignoreFiles,\n ignorePaths: this.ignorePaths,\n verbose: this.verbose,\n maxConcurrency: this.maxConcurrency,\n maxRetries: this.maxRetries,\n });\n\n yield* await submoduleLoader.processRepoAsStream(submoduleInfo.path);\n }\n\n /**\n * Determines whether a file or directory should be ignored based on its\n * path and type.\n * @param path The path of the file or directory.\n * @param fileType The type of the file or directory.\n * @returns A boolean indicating whether the file or directory should be ignored.\n */\n protected shouldIgnore(path: string, fileType: string): boolean {\n if (fileType !== \"dir\" && isBinaryPath(path)) {\n return true;\n }\n if (this.ignore !== undefined) {\n return this.ignore.ignores(path);\n }\n return (\n fileType !== \"dir\" &&\n this.ignoreFiles.some((pattern) => {\n if (typeof pattern === \"string\") {\n return path === pattern;\n }\n\n try {\n return pattern.test(path);\n } catch {\n throw new Error(`Unknown ignore file pattern: ${pattern}`);\n }\n })\n );\n }\n\n /**\n * Takes the file info and wrap it in a promise that will resolve to the file content and metadata\n * @param file\n * @returns\n */\n private async fetchFileContentWrapper(\n file: GithubFile\n ): Promise<GetContentResponse> {\n const fileContent = await this.fetchFileContent(file).catch((error) => {\n this.handleError(`Failed wrap file content: ${file}, ${error}`);\n });\n return {\n contents: fileContent || \"\",\n metadata: {\n source: file.path,\n repository: `${this.baseUrl}/${this.owner}/${this.repo}`,\n branch: this.branch,\n },\n };\n }\n\n /**\n * Maps a list of files / directories to a list of promises that will fetch the file / directory contents\n */\n private async getCurrentDirectoryFilePromises(\n files: GithubFile[]\n ): Promise<Promise<GetContentResponse>[]> {\n const currentDirectoryFilePromises: Promise<GetContentResponse>[] = [];\n // Directories have nested files / directories, which is why this is a list of promises of promises\n const currentDirectoryDirectoryPromises: Promise<\n Promise<GetContentResponse>[]\n >[] = [];\n\n for (const file of files) {\n if (file.type !== \"dir\" && this.shouldIgnore(file.path, file.type)) {\n continue;\n }\n if (file.type === \"file\" && file.size === 0) {\n // this is a submodule. ignoring for the moment. submodule processing is done separately\n continue;\n }\n if (file.type !== \"dir\") {\n try {\n currentDirectoryFilePromises.push(this.fetchFileContentWrapper(file));\n } catch (e) {\n this.handleError(`Failed to fetch file content: ${file.path}, ${e}`);\n }\n } else if (this.recursive) {\n currentDirectoryDirectoryPromises.push(\n this.processDirectory(file.path)\n );\n }\n }\n\n const curDirDirectories: Promise<GetContentResponse>[][] =\n await Promise.all(currentDirectoryDirectoryPromises);\n\n return [...currentDirectoryFilePromises, ...curDirDirectories.flat()];\n }\n\n /**\n * Begins the process of fetching the contents of the repository\n */\n private async processRepo(): Promise<GetContentResponse[]> {\n try {\n // Get the list of file / directory names in the root directory\n const files = await this.fetchRepoFiles(this.initialPath);\n // Map the file / directory paths to promises that will fetch the file / directory contents\n const currentDirectoryFilePromises =\n await this.getCurrentDirectoryFilePromises(files);\n return Promise.all(currentDirectoryFilePromises);\n } catch (error) {\n this.handleError(\n `Failed to process directory: ${this.initialPath}, ${error}`\n );\n return Promise.reject(error);\n }\n }\n\n /**\n * Asynchronously processes the contents of the entire GitHub repository,\n * streaming each file as a Document object.\n * @param path The path of the directory to process.\n * @yields Yields a Promise that resolves to a Document object for each file found in the repository.\n */\n private async *processRepoAsStream(\n path: string\n ): AsyncGenerator<Document, void, undefined> {\n const files = await this.fetchRepoFiles(path);\n for (const file of files) {\n if (file.type !== \"dir\" && this.shouldIgnore(file.path, file.type)) {\n continue;\n }\n\n if (file.type === \"file\") {\n try {\n const fileResponse = await this.fetchFileContentWrapper(file);\n\n yield new Document({\n pageContent: fileResponse.contents,\n metadata: fileResponse.metadata,\n });\n } catch (error) {\n this.handleError(\n `Failed to fetch file content: ${file.path}, ${error}`\n );\n }\n } else if (this.recursive) {\n yield* await this.processDirectoryAsStream(file.path);\n }\n }\n }\n\n /**\n * Fetches the contents of a directory and maps the file / directory paths\n * to promises that will fetch the file / directory contents.\n * @param path The path of the directory to process.\n * @returns A promise that resolves to an array of promises that will fetch the file / directory contents.\n */\n private async processDirectory(\n path: string\n ): Promise<Promise<GetContentResponse>[]> {\n try {\n const files = await this.fetchRepoFiles(path);\n return this.getCurrentDirectoryFilePromises(files);\n } catch (error) {\n this.handleError(`Failed to process directory: ${path}, ${error}`);\n return Promise.reject(error);\n }\n }\n\n /**\n * Asynchronously processes the contents of a given directory in the GitHub repository,\n * streaming each file as a Document object.\n * @param path The path of the directory to process.\n * @yields Yields a Promise that resolves to a Document object for each file in the directory.\n */\n private async *processDirectoryAsStream(\n path: string\n ): AsyncGenerator<Document, void, undefined> {\n const files = await this.fetchRepoFiles(path);\n\n for (const file of files) {\n if (file.type !== \"dir\" && this.shouldIgnore(file.path, file.type)) {\n continue;\n }\n\n if (file.type === \"file\") {\n try {\n const fileResponse = await this.fetchFileContentWrapper(file);\n\n yield new Document({\n pageContent: fileResponse.contents,\n metadata: fileResponse.metadata,\n });\n } catch {\n this.handleError(`Failed to fetch file content: ${file.path}`);\n }\n } else if (this.recursive) {\n yield* await this.processDirectoryAsStream(file.path);\n }\n }\n }\n\n /**\n * Fetches the files from a GitHub repository.\n * If the path denotes a single file, the resulting array contains only one element.\n * @param path The path of the repository to fetch the files from.\n * @returns A promise that resolves to an array of GithubFile instances.\n */\n private async fetchRepoFiles(path: string): Promise<GithubFile[]> {\n const url = `${this.apiUrl}/repos/${this.owner}/${\n this.repo\n }/contents/${encodeURIComponent(path)}?ref=${this.branch}`;\n return this.caller.call(async () => {\n this.log(`Fetching ${url}`);\n const response = await fetch(url, { headers: this.headers });\n const data = await response.json();\n if (!response.ok) {\n throw new Error(\n `Unable to fetch repository files: ${\n response.status\n } ${JSON.stringify(data)}`\n );\n }\n\n if (Array.isArray(data)) {\n return data as GithubFile[];\n } else {\n return [data as GithubFile];\n }\n });\n }\n\n /**\n * Fetches the content of a file from a GitHub repository.\n * @param file The file to fetch the content from.\n * @returns A promise that resolves to the content of the file.\n */\n private async fetchFileContent(file: GithubFile): Promise<string> {\n return this.caller.call(async () => {\n this.log(`Fetching ${file.download_url}`);\n const response = await fetch(file.download_url, {\n headers: this.headers,\n });\n return response.text();\n });\n }\n\n /**\n * Handles errors based on the unknown handling option.\n * @param message The error message.\n * @returns void\n */\n private handleError(message: string): void {\n switch (this.unknown) {\n case UnknownHandling.Ignore:\n break;\n case UnknownHandling.Warn:\n console.warn(message);\n break;\n case UnknownHandling.Error:\n throw new Error(message);\n default:\n throw new Error(`Unknown unknown handling: ${this.unknown}`);\n }\n }\n\n /**\n * Logs the given message to the console, if parameter 'verbose' is set to true.\n * @param message the message to be logged.\n */\n private log(message: string): void {\n if (this.verbose) {\n console.log(message);\n }\n }\n}\n"],"mappings":"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"}