UNPKG

@langchain/community

Version:
243 lines (242 loc) 8.28 kB
import { __exportAll } from "../../_virtual/_rolldown/runtime.js"; import { Document } from "@langchain/core/documents"; import { BaseDocumentLoader } from "@langchain/core/document_loaders/base"; //#region src/document_loaders/web/jira.ts var jira_exports = /* @__PURE__ */ __exportAll({ JiraDocumentConverter: () => JiraDocumentConverter, JiraProjectLoader: () => JiraProjectLoader, adfToText: () => adfToText, formatJiraDescriptionAsJSON: () => formatJiraDescriptionAsJSON, formatJiraDescriptionAsText: () => formatJiraDescriptionAsText }); function adfToText(adf) { if (!adf || !adf.content) return ""; const recur = (node) => { if (node.text) return node.text; if (node.content) return node.content.map(recur).join(""); return ""; }; return recur(adf).trim(); } const formatJiraDescriptionAsJSON = (adfContent) => { if (!adfContent) return null; const traverseNode = (node) => { if (typeof node === "string") return { type: "text", text: node }; const result = { type: node.type || "unknown" }; if (node.text) result.text = node.text; if (node.attrs) result.attrs = node.attrs; if (node.content) result.content = node.content.map(traverseNode); return result; }; return traverseNode(adfContent); }; const formatJiraDescriptionAsText = (adfContent) => { if (!adfContent) return ""; const traverseNode = (node) => { if (node.text) return node.text; if (node.content) return node.content.map(traverseNode).join(""); return ""; }; return traverseNode(adfContent).trim(); }; /** * Class responsible for converting Jira issues to Document objects */ var JiraDocumentConverter = class { host; projectKey; formatter; constructor({ host, projectKey, formatter }) { this.host = host; this.projectKey = projectKey; this.formatter = formatter ?? formatJiraDescriptionAsText; } convertToDocuments(issues) { return issues.map((issue) => this.documentFromIssue(issue)); } documentFromIssue(issue) { return new Document({ pageContent: this.formatIssueInfo({ issue, host: this.host }), metadata: { id: issue.id, host: this.host, projectKey: this.projectKey, created: issue.fields.created } }); } formatIssueInfo({ issue, host }) { let text = `Issue: ${this.formatMainIssueInfoText({ issue, host })}\n`; text += `Project: ${issue.fields.project.name} (${issue.fields.project.key}, ID ${issue.fields.project.id})\n`; text += `Status: ${issue.fields.status.name}\n`; text += `Priority: ${issue.fields.priority.name}\n`; text += `Type: ${issue.fields.issuetype.name}\n`; text += `Creator: ${issue.fields.creator?.displayName}\n`; if (issue.fields.labels && issue.fields.labels.length > 0) text += `Labels: ${issue.fields.labels.join(", ")}\n`; text += `Created: ${issue.fields.created}\n`; text += `Updated: ${issue.fields.updated}\n`; if (issue.fields.reporter) text += `Reporter: ${issue.fields.reporter.displayName}\n`; text += `Assignee: ${issue.fields.assignee?.displayName ?? "Unassigned"}\n`; if (issue.fields.duedate) text += `Due Date: ${issue.fields.duedate}\n`; if (issue.fields.timeestimate) text += `Time Estimate: ${issue.fields.timeestimate}\n`; if (issue.fields.timespent) text += `Time Spent: ${issue.fields.timespent}\n`; if (issue.fields.resolutiondate) text += `Resolution Date: ${issue.fields.resolutiondate}\n`; if (issue.fields.description) { const formattedDescription = this.formatter(issue.fields.description, issue); const descText = typeof formattedDescription === "string" ? formattedDescription : JSON.stringify(formattedDescription, null, 2); text += `Description: ${descText}\n`; } if (issue.fields.progress?.percent) text += `Progress: ${issue.fields.progress.percent}%\n`; if (issue.fields.parent) text += `Parent Issue: ${this.formatMainIssueInfoText({ issue: issue.fields.parent, host })}\n`; if (issue.fields.subtasks?.length > 0) { text += `Subtasks:\n`; issue.fields.subtasks.forEach((subtask) => { text += ` - ${this.formatMainIssueInfoText({ issue: subtask, host })}\n`; }); } if (issue.fields.issuelinks?.length > 0) { text += `Issue Links:\n`; issue.fields.issuelinks.forEach((link) => { text += ` - ${link.type.name}\n`; if (link.inwardIssue) text += ` - ${this.formatMainIssueInfoText({ issue: link.inwardIssue, host })}\n`; if (link.outwardIssue) text += ` - ${this.formatMainIssueInfoText({ issue: link.outwardIssue, host })}\n`; }); } return text; } getLinkToIssue({ issueKey, host }) { return `${host}/browse/${issueKey}`; } formatMainIssueInfoText({ issue, host }) { const link = this.getLinkToIssue({ issueKey: issue.key, host }); return `${issue.key} (ID ${issue.id}) - ${issue.fields.summary} (${link})`; } }; /** * Class representing a document loader for loading issues from Jira. */ var JiraProjectLoader = class extends BaseDocumentLoader { accessToken; host; projectKey; username; limitPerRequest; createdAfter; filterFn; documentConverter; personalAccessToken; jql; maxTotal; constructor({ host, projectKey, username, accessToken, limitPerRequest = 100, createdAfter, personalAccessToken, filterFn, descriptionFormatter: formatter, jql, maxTotal }) { super(); this.host = host; this.projectKey = projectKey; this.username = username; this.accessToken = accessToken; this.limitPerRequest = limitPerRequest; this.createdAfter = createdAfter; this.documentConverter = new JiraDocumentConverter({ host, projectKey, formatter }); this.personalAccessToken = personalAccessToken; this.filterFn = filterFn; this.jql = jql; this.maxTotal = maxTotal; } buildAuthorizationHeader() { if (this.personalAccessToken) return `Bearer ${this.personalAccessToken}`; return `Basic ${Buffer.from(`${this.username}:${this.accessToken}`).toString("base64")}`; } async load() { const filtered = (await this.loadAsIssues()).filter((issue) => { if (this.filterFn) return this.filterFn(issue); return true; }); return this.documentConverter.convertToDocuments(filtered); } async loadAsIssues() { const allIssues = []; for await (const issues of this.fetchIssues()) { allIssues.push(...issues); if (this.maxTotal && allIssues.length >= this.maxTotal) return allIssues.slice(0, this.maxTotal); } return allIssues; } toJiraDateString(date) { if (!date) return; return `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, "0")}-${String(date.getUTCDate()).padStart(2, "0")}`; } buildJql() { if (this.jql) return this.jql; const createdAfterAsString = this.toJiraDateString(this.createdAfter); return `${[`project = ${this.projectKey}`, ...createdAfterAsString ? [`created >= "${createdAfterAsString}"`] : []].join(" AND ")} ORDER BY created ASC, key ASC`; } async *fetchIssues() { const authorizationHeader = this.buildAuthorizationHeader(); const url = `${this.host}/rest/api/3/search/jql`; const jql = this.buildJql(); let nextPageToken; let totalFetched = 0; while (true) { let pageSize = this.limitPerRequest; if (this.maxTotal) { const remaining = this.maxTotal - totalFetched; if (remaining <= 0) break; pageSize = Math.min(pageSize, remaining); } const body = { jql, maxResults: pageSize, fields: ["*all"] }; if (nextPageToken) body.nextPageToken = nextPageToken; const response = await fetch(url, { method: "POST", headers: { Authorization: authorizationHeader, Accept: "application/json", "Content-Type": "application/json" }, body: JSON.stringify(body) }); const data = await response.json(); if (!response.ok) throw new Error(`Jira API request failed with status ${response.status}: ${JSON.stringify(data)}`); if (data.issues?.length) { yield data.issues; totalFetched += data.issues.length; } if (data.isLast === true) break; if (!data.nextPageToken) throw new Error("Expected nextPageToken but none returned"); nextPageToken = data.nextPageToken; } } }; //#endregion export { JiraDocumentConverter, JiraProjectLoader, adfToText, formatJiraDescriptionAsJSON, formatJiraDescriptionAsText, jira_exports }; //# sourceMappingURL=jira.js.map