@langchain/community
Version:
Third-party integrations for LangChain.js
207 lines (205 loc) • 6.81 kB
JavaScript
import { __export } 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 = {};
__export(jira_exports, {
JiraDocumentConverter: () => JiraDocumentConverter,
JiraProjectLoader: () => JiraProjectLoader,
adfToText: () => adfToText
});
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();
}
/**
* Class responsible for converting Jira issues to Document objects
*/
var JiraDocumentConverter = class {
host;
projectKey;
constructor({ host, projectKey }) {
this.host = host;
this.projectKey = projectKey;
}
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
}
});
}
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) text += `Description: ${issue.fields.description}\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
});
const text = `${issue.key} (ID ${issue.id}) - ${issue.fields.summary} (${link})`;
return text;
}
};
const API_ENDPOINTS = { SEARCH: "/rest/api/3/search/jql" };
/**
* Class representing a document loader for loading pages from Confluence.
*/
var JiraProjectLoader = class extends BaseDocumentLoader {
accessToken;
host;
projectKey;
username;
limitPerRequest;
createdAfter;
filterFn;
documentConverter;
personalAccessToken;
constructor({ host, projectKey, username, accessToken, limitPerRequest = 100, createdAfter, personalAccessToken, filterFn }) {
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
});
this.personalAccessToken = personalAccessToken;
this.filterFn = filterFn;
}
buildAuthorizationHeader() {
if (this.personalAccessToken) return `Bearer ${this.personalAccessToken}`;
return `Basic ${Buffer.from(`${this.username}:${this.accessToken}`).toString("base64")}`;
}
async load() {
try {
const allJiraIssues = await this.loadAsIssues();
const filtered = allJiraIssues.filter((issue) => {
if (this.filterFn) return this.filterFn(issue);
return true;
});
return this.documentConverter.convertToDocuments(filtered);
} catch (error) {
console.error("Error:", error);
return [];
}
}
async loadAsIssues() {
const allIssues = [];
for await (const issues of this.fetchIssues()) allIssues.push(...issues);
return allIssues;
}
toJiraDateString(date) {
if (!date) return void 0;
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const dayOfMonth = String(date.getDate()).padStart(2, "0");
return `${year}-${month}-${dayOfMonth}`;
}
async *fetchIssues() {
const authorizationHeader = this.buildAuthorizationHeader();
const url = `${this.host}${API_ENDPOINTS.SEARCH}`;
const createdAfterAsString = this.toJiraDateString(this.createdAfter);
let startAt = 0;
while (true) try {
const jqlProps = [`project=${this.projectKey}`, ...createdAfterAsString ? [`created>= "${createdAfterAsString}"`] : []];
const jql = `${jqlProps.join(" AND ")} ORDER BY created ASC, key ASC`;
const params = new URLSearchParams({
jql,
startAt: `${startAt}`,
maxResults: `${this.limitPerRequest}`,
fields: "*all"
});
const pageUrl = `${url}?${params}`;
const options = {
method: "GET",
headers: {
Authorization: authorizationHeader,
Accept: "application/json"
}
};
const response = await fetch(pageUrl, options);
const data = await response.json();
if (!data.issues || data.issues.length === 0) break;
const allIssues = [];
for (const issue of data.issues) allIssues.push(issue);
if (allIssues.length > 0) yield allIssues;
startAt += this.limitPerRequest;
if (data.issues.length < this.limitPerRequest) break;
} catch (error) {
console.error("Error fetching Jira issues:", error);
yield [];
break;
}
}
};
//#endregion
export { JiraDocumentConverter, JiraProjectLoader, adfToText, jira_exports };
//# sourceMappingURL=jira.js.map