UNPKG

@langchain/community

Version:
1 lines • 17.4 kB
{"version":3,"file":"jira.cjs","names":["adf: ADFNode | null | undefined","node: ADFNode","issues: JiraIssue[]","issue: JiraIssue","Document","BaseDocumentLoader","allIssues: JiraIssue[]","date: Date | undefined","data: JiraAPIResponse"],"sources":["../../../src/document_loaders/web/jira.ts"],"sourcesContent":["import { Document } from \"@langchain/core/documents\";\nimport { BaseDocumentLoader } from \"@langchain/core/document_loaders/base\";\n\nexport type JiraStatusCategory = {\n self: string;\n id: number;\n key: string;\n colorName: string;\n name: string;\n};\n\nexport type JiraStatus = {\n self: string;\n description: string;\n iconUrl: string;\n name: string;\n id: string;\n statusCategory: JiraStatusCategory;\n};\n\nexport type JiraUser = {\n accountId: string;\n accountType: string;\n active: boolean;\n avatarUrls: {\n \"16x16\": string;\n \"24x24\": string;\n \"32x32\": string;\n \"48x48\": string;\n };\n displayName: string;\n emailAddress: string;\n self: string;\n timeZone: string;\n};\n\nexport type JiraIssueType = {\n avatarId: number;\n description: string;\n entityId: string;\n hierarchyLevel: number;\n iconUrl: string;\n id: string;\n name: string;\n self: string;\n subtask: boolean;\n};\n\nexport type JiraPriority = {\n iconUrl: string;\n id: string;\n name: string;\n self: string;\n};\n\nexport type JiraProgress = {\n progress: number;\n total: number;\n percent?: number;\n};\n\nexport type JiraProject = {\n avatarUrls: {\n \"16x16\": string;\n \"24x24\": string;\n \"32x32\": string;\n \"48x48\": string;\n };\n id: string;\n key: string;\n name: string;\n projectTypeKey: string;\n self: string;\n simplified: boolean;\n};\n\nexport type JiraSubTask = {\n id: string;\n key: string;\n self: string;\n fields: {\n issuetype: JiraIssueType;\n priority: JiraPriority;\n status: JiraStatus;\n summary: string;\n };\n};\n\nexport type JiraIssueLinkType = {\n id: string;\n name: string;\n inward: string;\n outward: string;\n self: string;\n};\n\nexport type JiraBriefIssue = {\n id: string;\n key: string;\n self: string;\n fields: {\n summary: string;\n status: JiraStatus;\n priority: JiraPriority;\n issuetype: JiraIssueType;\n };\n};\n\nexport type JiraIssueLink = {\n id: string;\n self: string;\n type: JiraIssueLinkType;\n inwardIssue?: JiraBriefIssue;\n outwardIssue?: JiraBriefIssue;\n};\n\nexport type JiraIssue = {\n expand: string;\n id: string;\n self: string;\n key: string;\n fields: {\n assignee?: JiraUser;\n created: string;\n description: ADFNode;\n issuelinks: JiraIssueLink[];\n issuetype: JiraIssueType;\n labels?: string[];\n priority: JiraPriority;\n progress: JiraProgress;\n project: JiraProject;\n reporter?: JiraUser;\n creator: JiraUser;\n resolutiondate?: string;\n status: JiraStatus;\n subtasks: JiraSubTask[];\n summary: string;\n timeestimate?: number;\n timespent?: number;\n updated: string;\n duedate?: string;\n parent?: JiraBriefIssue;\n };\n};\n\nexport type JiraAPIResponse = {\n expand: string;\n startAt: number;\n maxResults: number;\n total: number;\n issues: JiraIssue[];\n};\n\nexport interface ADFNode {\n type: string;\n text?: string;\n content?: ADFNode[];\n}\n\nexport interface ADFDocument extends ADFNode {\n type: \"doc\";\n version: number;\n content: ADFNode[];\n}\n\nexport function adfToText(adf: ADFNode | null | undefined): string {\n if (!adf || !adf.content) return \"\";\n const recur = (node: ADFNode): string => {\n if (node.text) return node.text;\n if (node.content) return node.content.map(recur).join(\"\");\n return \"\";\n };\n return recur(adf).trim();\n}\n\n/**\n * Interface representing the parameters for configuring the\n * JiraDocumentConverter.\n */\nexport interface JiraDocumentConverterParams {\n host: string;\n projectKey: string;\n}\n\n/**\n * Class responsible for converting Jira issues to Document objects\n */\nexport class JiraDocumentConverter {\n public readonly host: string;\n\n public readonly projectKey: string;\n\n constructor({ host, projectKey }: JiraDocumentConverterParams) {\n this.host = host;\n this.projectKey = projectKey;\n }\n\n public convertToDocuments(issues: JiraIssue[]): Document[] {\n return issues.map((issue) => this.documentFromIssue(issue));\n }\n\n private documentFromIssue(issue: JiraIssue): Document {\n return new Document({\n pageContent: this.formatIssueInfo({\n issue,\n host: this.host,\n }),\n metadata: {\n id: issue.id,\n host: this.host,\n projectKey: this.projectKey,\n },\n });\n }\n\n private formatIssueInfo({\n issue,\n host,\n }: {\n issue: JiraIssue;\n host: string;\n }): string {\n let text = `Issue: ${this.formatMainIssueInfoText({ issue, host })}\\n`;\n text += `Project: ${issue.fields.project.name} (${issue.fields.project.key}, ID ${issue.fields.project.id})\\n`;\n text += `Status: ${issue.fields.status.name}\\n`;\n text += `Priority: ${issue.fields.priority.name}\\n`;\n text += `Type: ${issue.fields.issuetype.name}\\n`;\n text += `Creator: ${issue.fields.creator?.displayName}\\n`;\n\n if (issue.fields.labels && issue.fields.labels.length > 0) {\n text += `Labels: ${issue.fields.labels.join(\", \")}\\n`;\n }\n\n text += `Created: ${issue.fields.created}\\n`;\n text += `Updated: ${issue.fields.updated}\\n`;\n\n if (issue.fields.reporter) {\n text += `Reporter: ${issue.fields.reporter.displayName}\\n`;\n }\n\n text += `Assignee: ${issue.fields.assignee?.displayName ?? \"Unassigned\"}\\n`;\n\n if (issue.fields.duedate) {\n text += `Due Date: ${issue.fields.duedate}\\n`;\n }\n\n if (issue.fields.timeestimate) {\n text += `Time Estimate: ${issue.fields.timeestimate}\\n`;\n }\n\n if (issue.fields.timespent) {\n text += `Time Spent: ${issue.fields.timespent}\\n`;\n }\n\n if (issue.fields.resolutiondate) {\n text += `Resolution Date: ${issue.fields.resolutiondate}\\n`;\n }\n\n if (issue.fields.description) {\n text += `Description: ${issue.fields.description}\\n`;\n }\n\n if (issue.fields.progress?.percent) {\n text += `Progress: ${issue.fields.progress.percent}%\\n`;\n }\n\n if (issue.fields.parent) {\n text += `Parent Issue: ${this.formatMainIssueInfoText({\n issue: issue.fields.parent,\n host,\n })}\\n`;\n }\n\n if (issue.fields.subtasks?.length > 0) {\n text += `Subtasks:\\n`;\n issue.fields.subtasks.forEach((subtask) => {\n text += ` - ${this.formatMainIssueInfoText({\n issue: subtask,\n host,\n })}\\n`;\n });\n }\n\n if (issue.fields.issuelinks?.length > 0) {\n text += `Issue Links:\\n`;\n issue.fields.issuelinks.forEach((link) => {\n text += ` - ${link.type.name}\\n`;\n if (link.inwardIssue) {\n text += ` - ${this.formatMainIssueInfoText({\n issue: link.inwardIssue,\n host,\n })}\\n`;\n }\n if (link.outwardIssue) {\n text += ` - ${this.formatMainIssueInfoText({\n issue: link.outwardIssue,\n host,\n })}\\n`;\n }\n });\n }\n\n return text;\n }\n\n private getLinkToIssue({\n issueKey,\n host,\n }: {\n issueKey: string;\n host: string;\n }): string {\n return `${host}/browse/${issueKey}`;\n }\n\n private formatMainIssueInfoText({\n issue,\n host,\n }: {\n issue: JiraIssue | JiraBriefIssue;\n host: string;\n }): string {\n const link = this.getLinkToIssue({\n issueKey: issue.key,\n host,\n });\n\n const text = `${issue.key} (ID ${issue.id}) - ${issue.fields.summary} (${link})`;\n\n return text;\n }\n}\n\n/**\n * Interface representing the parameters for configuring the\n * JiraProjectLoader.\n */\nexport interface JiraProjectLoaderParams {\n host: string;\n projectKey: string;\n username?: string;\n accessToken?: string;\n personalAccessToken?: string;\n limitPerRequest?: number;\n createdAfter?: Date;\n filterFn?: (issue: JiraIssue) => boolean;\n}\n\nconst API_ENDPOINTS = {\n SEARCH: \"/rest/api/3/search/jql\",\n};\n\n/**\n * Class representing a document loader for loading pages from Confluence.\n */\nexport class JiraProjectLoader extends BaseDocumentLoader {\n private readonly accessToken?: string;\n\n public readonly host: string;\n\n public readonly projectKey: string;\n\n public readonly username?: string;\n\n public readonly limitPerRequest: number;\n\n private readonly createdAfter?: Date;\n\n private readonly filterFn?: (issue: JiraIssue) => boolean;\n\n private readonly documentConverter: JiraDocumentConverter;\n\n private readonly personalAccessToken?: string;\n\n constructor({\n host,\n projectKey,\n username,\n accessToken,\n limitPerRequest = 100,\n createdAfter,\n personalAccessToken,\n filterFn,\n }: JiraProjectLoaderParams) {\n super();\n this.host = host;\n this.projectKey = projectKey;\n this.username = username;\n this.accessToken = accessToken;\n this.limitPerRequest = limitPerRequest;\n this.createdAfter = createdAfter;\n this.documentConverter = new JiraDocumentConverter({ host, projectKey });\n this.personalAccessToken = personalAccessToken;\n this.filterFn = filterFn;\n }\n\n private buildAuthorizationHeader(): string {\n if (this.personalAccessToken) {\n return `Bearer ${this.personalAccessToken}`;\n }\n return `Basic ${Buffer.from(\n `${this.username}:${this.accessToken}`\n ).toString(\"base64\")}`;\n }\n\n public async load(): Promise<Document[]> {\n try {\n const allJiraIssues = await this.loadAsIssues();\n const filtered = allJiraIssues.filter((issue) => {\n if (this.filterFn) {\n return this.filterFn(issue);\n }\n return true;\n });\n return this.documentConverter.convertToDocuments(filtered);\n } catch (error) {\n console.error(\"Error:\", error);\n return [];\n }\n }\n\n public async loadAsIssues(): Promise<JiraIssue[]> {\n const allIssues: JiraIssue[] = [];\n\n for await (const issues of this.fetchIssues()) {\n allIssues.push(...issues);\n }\n\n return allIssues;\n }\n\n protected toJiraDateString(date: Date | undefined): string | undefined {\n if (!date) {\n return undefined;\n }\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const dayOfMonth = String(date.getDate()).padStart(2, \"0\");\n return `${year}-${month}-${dayOfMonth}`;\n }\n\n protected async *fetchIssues(): AsyncIterable<JiraIssue[]> {\n const authorizationHeader = this.buildAuthorizationHeader();\n const url = `${this.host}${API_ENDPOINTS.SEARCH}`;\n const createdAfterAsString = this.toJiraDateString(this.createdAfter);\n let startAt = 0;\n\n while (true) {\n try {\n const jqlProps = [\n `project=${this.projectKey}`,\n ...(createdAfterAsString\n ? [`created>= \"${createdAfterAsString}\"`]\n : []),\n ];\n const jql = `${jqlProps.join(\" AND \")} ORDER BY created ASC, key ASC`;\n\n const params = new URLSearchParams({\n jql,\n startAt: `${startAt}`,\n maxResults: `${this.limitPerRequest}`,\n fields: \"*all\",\n });\n const pageUrl = `${url}?${params}`;\n\n const options = {\n method: \"GET\",\n headers: {\n Authorization: authorizationHeader,\n Accept: \"application/json\",\n },\n };\n\n const response = await fetch(pageUrl, options);\n const data: JiraAPIResponse = await response.json();\n\n if (!data.issues || data.issues.length === 0) break;\n\n const allIssues = [];\n for (const issue of data.issues) {\n allIssues.push(issue);\n }\n\n if (allIssues.length > 0) yield allIssues;\n\n startAt += this.limitPerRequest;\n\n if (data.issues.length < this.limitPerRequest) break;\n } catch (error) {\n console.error(\"Error fetching Jira issues:\", error);\n yield [];\n break;\n }\n }\n }\n}\n"],"mappings":"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"}