mirror of
https://github.com/alamion/obsidian-jira-sync.git
synced 2026-07-22 05:43:04 +00:00
settings rework:
- collapsable sections in settings - separation of auth variants - field mapping validation small fix - added raw issue viewer - added test field mapping (for testing js expressions with rawissue viewer data)
This commit is contained in:
parent
f98a4bc1ff
commit
fbf8649c1a
23 changed files with 2626 additions and 602 deletions
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "jira-sync",
|
||||
"name": "Jira Issue Manager",
|
||||
"version": "1.1.7",
|
||||
"version": "1.1.8",
|
||||
"minAppVersion": "1.7.7",
|
||||
"description": "Get Jira issues, create and update them. Issue status and worklog management.",
|
||||
"author": "Alamion",
|
||||
|
|
|
|||
47
package-lock.json
generated
47
package-lock.json
generated
|
|
@ -1,25 +1,26 @@
|
|||
{
|
||||
"name": "obsidian-sample-plugin",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.8",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "obsidian-sample-plugin",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.8",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/turndown": "^5.0.5",
|
||||
"acorn": "^8.14.1",
|
||||
"turndown": "^7.2.0",
|
||||
"highlight.js": "^11.11.1",
|
||||
"yaml": "^2.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.17.16",
|
||||
"@types/node": "^16.11.6",
|
||||
"@typescript-eslint/eslint-plugin": "5.29.0",
|
||||
"@typescript-eslint/parser": "5.29.0",
|
||||
"builtin-modules": "3.3.0",
|
||||
"esbuild": "0.25.0",
|
||||
"lodash": "^4.17.21",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.4"
|
||||
|
|
@ -185,11 +186,6 @@
|
|||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@mixmark-io/domino": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz",
|
||||
"integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw=="
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
|
|
@ -252,6 +248,12 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.17.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz",
|
||||
"integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "16.18.121",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.121.tgz",
|
||||
|
|
@ -269,11 +271,6 @@
|
|||
"@types/estree": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/turndown": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/turndown/-/turndown-5.0.5.tgz",
|
||||
"integrity": "sha512-TL2IgGgc7B5j78rIccBtlYAnkuv8nUQqhQc+DSYV5j9Be9XOcm/SKOVRuA47xAVI3680Tk9B1d8flK2GWT2+4w=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.29.0.tgz",
|
||||
|
|
@ -1251,6 +1248,14 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/highlight.js": {
|
||||
"version": "11.11.1",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz",
|
||||
"integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
|
|
@ -1431,6 +1436,12 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
|
|
@ -1897,14 +1908,6 @@
|
|||
"dev": true,
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/turndown": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.0.tgz",
|
||||
"integrity": "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==",
|
||||
"dependencies": {
|
||||
"@mixmark-io/domino": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "obsidian-sample-plugin",
|
||||
"version": "1.1.7",
|
||||
"version": "1.1.8",
|
||||
"description": "This is a sample plugin for Obsidian (https://obsidian.md)",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
@ -13,17 +13,20 @@
|
|||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.17.16",
|
||||
"@types/node": "^16.11.6",
|
||||
"@typescript-eslint/eslint-plugin": "5.29.0",
|
||||
"@typescript-eslint/parser": "5.29.0",
|
||||
"builtin-modules": "3.3.0",
|
||||
"esbuild": "0.25.0",
|
||||
"lodash": "^4.17.21",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn": "^8.14.1",
|
||||
"highlight.js": "^11.11.1",
|
||||
"yaml": "^2.7.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,24 +49,56 @@ export function validateSettings(plugin: JiraPlugin): boolean {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Helper function to create Basic Auth header
|
||||
function createBasicAuthHeader(email: string, token: string): string {
|
||||
const credentials = `${email}:${token}`;
|
||||
// Convert to base64
|
||||
const base64Credentials = btoa(credentials);
|
||||
return `Basic ${base64Credentials}`;
|
||||
}
|
||||
|
||||
export async function getAuthHeaders(plugin: JiraPlugin): Promise<Record<string, string>> {
|
||||
const pat = plugin.settings.apiToken;
|
||||
if (pat) {
|
||||
return {
|
||||
Authorization: `Bearer ${pat}`,
|
||||
"Content-type": "application/json",
|
||||
Origin: plugin.settings.jiraUrl,
|
||||
};
|
||||
}
|
||||
let cookie = localStorage.getItem(getSessionCookieKey(plugin));
|
||||
if (!cookie) {
|
||||
await authenticate(plugin);
|
||||
cookie = localStorage.getItem(getSessionCookieKey(plugin));
|
||||
}
|
||||
return {
|
||||
Cookie: `${plugin.settings.sessionCookieName}=${cookie}`,
|
||||
// Common headers
|
||||
const commonHeaders = {
|
||||
"Content-type": "application/json",
|
||||
Origin: plugin.settings.jiraUrl,
|
||||
};
|
||||
|
||||
// Personal Access Token
|
||||
const pat = plugin.settings.apiToken?.trim() || "";
|
||||
|
||||
// Option 1: Bearer token (PAT)
|
||||
if (plugin.settings.authMethod === "bearer" || !plugin.settings.authMethod) {
|
||||
return {
|
||||
...commonHeaders,
|
||||
Authorization: `Bearer ${pat}`,
|
||||
};
|
||||
}
|
||||
|
||||
// Option 2: Basic Auth with API token
|
||||
else if (plugin.settings.authMethod === "basic") {
|
||||
return {
|
||||
...commonHeaders,
|
||||
Authorization: createBasicAuthHeader(plugin.settings.email || "", pat),
|
||||
};
|
||||
}
|
||||
|
||||
else if (plugin.settings.authMethod === "session") {
|
||||
// Option 3: Session cookie
|
||||
let cookie = localStorage.getItem(getSessionCookieKey(plugin));
|
||||
if (!cookie) {
|
||||
await authenticate(plugin);
|
||||
cookie = localStorage.getItem(getSessionCookieKey(plugin));
|
||||
}
|
||||
|
||||
if (cookie) {
|
||||
return {
|
||||
...commonHeaders,
|
||||
Cookie: `${plugin.settings.sessionCookieName}=${cookie}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// No valid auth method found
|
||||
throw new Error("No valid authentication method available");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +1,38 @@
|
|||
import JiraPlugin from "../main";
|
||||
import {requestUrl} from "obsidian";
|
||||
import {getAuthHeaders} from "./auth";
|
||||
import {authenticate, getAuthHeaders, getSessionCookieKey} from "./auth";
|
||||
import {debugLog} from "../tools/debugLogging";
|
||||
|
||||
export async function baseRequest(
|
||||
plugin: JiraPlugin,
|
||||
method: string,
|
||||
additional_url_path: string,
|
||||
body?: string
|
||||
body?: string,
|
||||
retries: number = 1
|
||||
): Promise<any> {
|
||||
const response = await requestUrl({
|
||||
const requestParams = {
|
||||
url: `${plugin.settings.jiraUrl}/rest/api/2${additional_url_path}`,
|
||||
method: method,
|
||||
headers: await getAuthHeaders(plugin),
|
||||
contentType: "application/json",
|
||||
throw: false,
|
||||
body
|
||||
});
|
||||
}
|
||||
debugLog(requestParams)
|
||||
const response = await requestUrl(requestParams);
|
||||
debugLog(response);
|
||||
if (response.status < 200 || response.status >= 300) {
|
||||
const error = new Error(`Error updating issue:
|
||||
if (response.status === 401 && retries > 0) {
|
||||
await authenticate(plugin);
|
||||
return await baseRequest(plugin, method, additional_url_path, body, retries-1);
|
||||
}
|
||||
// console.error(error);
|
||||
throw new Error(`
|
||||
${response.text || "Unknown error"}
|
||||
${body && '\nbody:' + body || ""}`);
|
||||
console.error(error);
|
||||
throw error;
|
||||
}
|
||||
debugLog({"url": `${plugin.settings.jiraUrl}/rest/api/2${additional_url_path}`,
|
||||
"method": method, "body": body});
|
||||
debugLog(response);
|
||||
return response.status === 204 ? null : response.json;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,11 +37,6 @@ function openIssueModal(plugin: JiraPlugin): void {
|
|||
}
|
||||
|
||||
export async function fetchAndOpenIssue(plugin: JiraPlugin, file: TFile | null, issueKey: string): Promise<void> {
|
||||
try {
|
||||
const issue = await fetchIssue(plugin, issueKey);
|
||||
await createOrUpdateIssueNote(plugin, issue, file?.path);
|
||||
} catch (error) {
|
||||
new Notice("Error retrieving issue: " + (error.message || "Unknown error"));
|
||||
console.error(error);
|
||||
}
|
||||
const issue = await fetchIssue(plugin, issueKey);
|
||||
await createOrUpdateIssueNote(plugin, issue, file?.path);
|
||||
}
|
||||
|
|
|
|||
405
src/constants/defaultIssue.ts
Normal file
405
src/constants/defaultIssue.ts
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
export const defaultIssue = {
|
||||
"expand": "",
|
||||
"id": "",
|
||||
"self": "",
|
||||
"key": "",
|
||||
"fields": {
|
||||
"issuetype": {
|
||||
"self": "",
|
||||
"id": "",
|
||||
"description": "",
|
||||
"iconUrl": "",
|
||||
"name": "",
|
||||
"subtask": 0,
|
||||
"avatarId": 0
|
||||
},
|
||||
"timespent": 0,
|
||||
"project": {
|
||||
"self": "",
|
||||
"id": "",
|
||||
"key": "",
|
||||
"name": "",
|
||||
"projectTypeKey": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
}
|
||||
},
|
||||
"fixVersions": [],
|
||||
"aggregatetimespent": 0,
|
||||
"resolution": null,
|
||||
"resolutiondate": null,
|
||||
"workratio": 0,
|
||||
"lastViewed": "",
|
||||
"watches": {
|
||||
"self": "",
|
||||
"watchCount": 0,
|
||||
"isWatching": 0
|
||||
},
|
||||
"created": "",
|
||||
"priority": {
|
||||
"self": "",
|
||||
"iconUrl": "",
|
||||
"name": "",
|
||||
"id": ""
|
||||
},
|
||||
"labels": [],
|
||||
"timeestimate": 0,
|
||||
"aggregatetimeoriginalestimate": null,
|
||||
"versions": [],
|
||||
"issuelinks": [],
|
||||
"assignee": {
|
||||
"self": "",
|
||||
"name": "",
|
||||
"key": "",
|
||||
"emailAddress": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
},
|
||||
"displayName": "",
|
||||
"active": 0,
|
||||
"timeZone": ""
|
||||
},
|
||||
"updated": "",
|
||||
"status": {
|
||||
"self": "",
|
||||
"description": "",
|
||||
"iconUrl": "",
|
||||
"name": "",
|
||||
"id": "",
|
||||
"statusCategory": {
|
||||
"self": "",
|
||||
"id": 0,
|
||||
"key": "",
|
||||
"colorName": "",
|
||||
"name": ""
|
||||
}
|
||||
},
|
||||
"components": [],
|
||||
"timeoriginalestimate": null,
|
||||
"description": "",
|
||||
"archiveddate": null,
|
||||
"timetracking": {
|
||||
"remainingEstimate": "",
|
||||
"timeSpent": "",
|
||||
"remainingEstimateSeconds": 0,
|
||||
"timeSpentSeconds": 0
|
||||
},
|
||||
"attachment": [],
|
||||
"aggregatetimeestimate": 0,
|
||||
"summary": "",
|
||||
"creator": {
|
||||
"self": "",
|
||||
"name": "",
|
||||
"key": "",
|
||||
"emailAddress": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
},
|
||||
"displayName": "",
|
||||
"active": 0,
|
||||
"timeZone": ""
|
||||
},
|
||||
"subtasks": [],
|
||||
"reporter": {
|
||||
"self": "",
|
||||
"name": "",
|
||||
"key": "",
|
||||
"emailAddress": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
},
|
||||
"displayName": "",
|
||||
"active": 0,
|
||||
"timeZone": ""
|
||||
},
|
||||
"aggregateprogress": {
|
||||
"progress": 0,
|
||||
"total": 0,
|
||||
"percent": 0
|
||||
},
|
||||
"environment": null,
|
||||
"duedate": null,
|
||||
"progress": {
|
||||
"progress": 0,
|
||||
"total": 0,
|
||||
"percent": 0
|
||||
},
|
||||
"comment": {
|
||||
"comments": [],
|
||||
"maxResults": 0,
|
||||
"total": 0,
|
||||
"startAt": 0
|
||||
},
|
||||
"votes": {
|
||||
"self": "",
|
||||
"votes": 0,
|
||||
"hasVoted": 0
|
||||
},
|
||||
"worklog": {
|
||||
"startAt": 0,
|
||||
"maxResults": 0,
|
||||
"total": 0,
|
||||
"worklogs": [
|
||||
{
|
||||
"self": "",
|
||||
"author": {
|
||||
"self": "",
|
||||
"name": "",
|
||||
"key": "",
|
||||
"emailAddress": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
},
|
||||
"displayName": "",
|
||||
"active": 0,
|
||||
"timeZone": ""
|
||||
},
|
||||
"updateAuthor": {
|
||||
"self": "",
|
||||
"name": "",
|
||||
"key": "",
|
||||
"emailAddress": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
},
|
||||
"displayName": "",
|
||||
"active": 0,
|
||||
"timeZone": ""
|
||||
},
|
||||
"comment": "",
|
||||
"created": "",
|
||||
"updated": "",
|
||||
"started": "",
|
||||
"timeSpent": "",
|
||||
"timeSpentSeconds": 0,
|
||||
"id": "",
|
||||
"issueId": ""
|
||||
},
|
||||
{
|
||||
"self": "",
|
||||
"author": {
|
||||
"self": "",
|
||||
"name": "",
|
||||
"key": "",
|
||||
"emailAddress": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
},
|
||||
"displayName": "",
|
||||
"active": 0,
|
||||
"timeZone": ""
|
||||
},
|
||||
"updateAuthor": {
|
||||
"self": "",
|
||||
"name": "",
|
||||
"key": "",
|
||||
"emailAddress": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
},
|
||||
"displayName": "",
|
||||
"active": 0,
|
||||
"timeZone": ""
|
||||
},
|
||||
"comment": "",
|
||||
"created": "",
|
||||
"updated": "",
|
||||
"started": "",
|
||||
"timeSpent": "",
|
||||
"timeSpentSeconds": 0,
|
||||
"id": "",
|
||||
"issueId": ""
|
||||
},
|
||||
{
|
||||
"self": "",
|
||||
"author": {
|
||||
"self": "",
|
||||
"name": "",
|
||||
"key": "",
|
||||
"emailAddress": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
},
|
||||
"displayName": "",
|
||||
"active": 0,
|
||||
"timeZone": ""
|
||||
},
|
||||
"updateAuthor": {
|
||||
"self": "",
|
||||
"name": "",
|
||||
"key": "",
|
||||
"emailAddress": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
},
|
||||
"displayName": "",
|
||||
"active": 0,
|
||||
"timeZone": ""
|
||||
},
|
||||
"comment": "",
|
||||
"created": "",
|
||||
"updated": "",
|
||||
"started": "",
|
||||
"timeSpent": "",
|
||||
"timeSpentSeconds": 0,
|
||||
"id": "",
|
||||
"issueId": ""
|
||||
},
|
||||
{
|
||||
"self": "",
|
||||
"author": {
|
||||
"self": "",
|
||||
"name": "",
|
||||
"key": "",
|
||||
"emailAddress": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
},
|
||||
"displayName": "",
|
||||
"active": 0,
|
||||
"timeZone": ""
|
||||
},
|
||||
"updateAuthor": {
|
||||
"self": "",
|
||||
"name": "",
|
||||
"key": "",
|
||||
"emailAddress": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
},
|
||||
"displayName": "",
|
||||
"active": 0,
|
||||
"timeZone": ""
|
||||
},
|
||||
"comment": "",
|
||||
"created": "",
|
||||
"updated": "",
|
||||
"started": "",
|
||||
"timeSpent": "",
|
||||
"timeSpentSeconds": 0,
|
||||
"id": "",
|
||||
"issueId": ""
|
||||
},
|
||||
{
|
||||
"self": "",
|
||||
"author": {
|
||||
"self": "",
|
||||
"name": "",
|
||||
"key": "",
|
||||
"emailAddress": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
},
|
||||
"displayName": "",
|
||||
"active": 0,
|
||||
"timeZone": ""
|
||||
},
|
||||
"updateAuthor": {
|
||||
"self": "",
|
||||
"name": "",
|
||||
"key": "",
|
||||
"emailAddress": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
},
|
||||
"displayName": "",
|
||||
"active": 0,
|
||||
"timeZone": ""
|
||||
},
|
||||
"comment": "",
|
||||
"created": "",
|
||||
"updated": "",
|
||||
"started": "",
|
||||
"timeSpent": "",
|
||||
"timeSpentSeconds": 0,
|
||||
"id": "",
|
||||
"issueId": ""
|
||||
},
|
||||
{
|
||||
"self": "",
|
||||
"author": {
|
||||
"self": "",
|
||||
"name": "",
|
||||
"key": "",
|
||||
"emailAddress": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
},
|
||||
"displayName": "",
|
||||
"active": 0,
|
||||
"timeZone": ""
|
||||
},
|
||||
"updateAuthor": {
|
||||
"self": "",
|
||||
"name": "",
|
||||
"key": "",
|
||||
"emailAddress": "",
|
||||
"avatarUrls": {
|
||||
"48x48": "",
|
||||
"24x24": "",
|
||||
"16x16": "",
|
||||
"32x32": ""
|
||||
},
|
||||
"displayName": "",
|
||||
"active": 0,
|
||||
"timeZone": ""
|
||||
},
|
||||
"comment": "",
|
||||
"created": "",
|
||||
"updated": "",
|
||||
"started": "",
|
||||
"timeSpent": "",
|
||||
"timeSpentSeconds": 0,
|
||||
"id": "",
|
||||
"issueId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
"archivedby": null
|
||||
}
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@ export async function createOrUpdateIssueNote(plugin: JiraPlugin, issue: JiraIss
|
|||
new Notice(`Issue ${issue.key} imported successfully`);
|
||||
} catch (error) {
|
||||
new Notice("Error creating issue note: " + (error.message || "Unknown error"));
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
59
src/interfaces/settingsTypes.ts
Normal file
59
src/interfaces/settingsTypes.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import { App } from "obsidian";
|
||||
import JiraPlugin from "../main";
|
||||
|
||||
/**
|
||||
* Function type for field mappings
|
||||
*/
|
||||
export type JiraFieldMappingFunction = (...args: any[]) => any;
|
||||
|
||||
/**
|
||||
* Interface for field mappings between Obsidian and Jira
|
||||
*/
|
||||
export interface JiraFieldMapping {
|
||||
toJira: JiraFieldMappingFunction;
|
||||
fromJira: JiraFieldMappingFunction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for string representation of field mappings
|
||||
*/
|
||||
export interface JiraFieldMappingString {
|
||||
toJira: string;
|
||||
fromJira: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base interface for settings components
|
||||
*/
|
||||
export interface SettingsComponent {
|
||||
render(containerEl: HTMLElement): void;
|
||||
hide?(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Props for settings components
|
||||
*/
|
||||
export interface SettingsComponentProps {
|
||||
app: App;
|
||||
plugin: JiraPlugin;
|
||||
onSettingsChange?: () => Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation result interface
|
||||
*/
|
||||
export interface ValidationResult {
|
||||
isValid: boolean;
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for collapsed sections
|
||||
*/
|
||||
export interface CollapsedSections {
|
||||
connection: boolean;
|
||||
general: boolean;
|
||||
fieldMappings: boolean;
|
||||
rawIssueViewer: boolean;
|
||||
testFieldMappings: boolean;
|
||||
}
|
||||
98
src/settings/CollapsibleSection.ts
Normal file
98
src/settings/CollapsibleSection.ts
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
import { ButtonComponent } from "obsidian";
|
||||
import JiraPlugin from "../main";
|
||||
import { SettingsComponent } from "../interfaces/settingsTypes";
|
||||
import { debugLog } from "../tools/debugLogging";
|
||||
|
||||
export class CollapsibleSection {
|
||||
private containerEl: HTMLDivElement;
|
||||
private contentEl: HTMLElement;
|
||||
private child: SettingsComponent;
|
||||
private isOpen = false;
|
||||
private headerText: string;
|
||||
private saveStateKey?: string;
|
||||
private plugin: JiraPlugin;
|
||||
private toggleBtn: ButtonComponent;
|
||||
|
||||
constructor(
|
||||
plugin: JiraPlugin,
|
||||
parentEl: HTMLElement,
|
||||
child: SettingsComponent,
|
||||
headerText: string,
|
||||
isOpenByDefault = false,
|
||||
saveStateKey?: string
|
||||
) {
|
||||
this.plugin = plugin;
|
||||
this.child = child;
|
||||
this.headerText = headerText;
|
||||
this.isOpen = isOpenByDefault;
|
||||
this.saveStateKey = saveStateKey;
|
||||
|
||||
// Create the container div for the entire collapsible section
|
||||
this.containerEl = parentEl.createDiv({
|
||||
cls: "jira-collapsible-section",
|
||||
});
|
||||
|
||||
// Create the header element
|
||||
const headerEl = this.containerEl.createDiv({
|
||||
cls: "jira-collapsible-header",
|
||||
text: headerText,
|
||||
});
|
||||
headerEl.style.cursor = "pointer";
|
||||
headerEl.addEventListener("click", async () => {
|
||||
await this.toggle();
|
||||
});
|
||||
|
||||
// Add toggle button to the header
|
||||
this.toggleBtn = new ButtonComponent(headerEl as any);
|
||||
this.toggleBtn.setIcon(this.isOpen ? "chevron-down" : "chevron-right")
|
||||
.setTooltip(this.isOpen ? "Collapse" : "Expand")
|
||||
|
||||
// Content wrapper
|
||||
this.contentEl = this.containerEl.createDiv({
|
||||
cls: "jira-collapsible-content",
|
||||
});
|
||||
|
||||
this.child.render(this.contentEl);
|
||||
|
||||
if (!this.isOpen) {
|
||||
this.contentEl.hide();
|
||||
}
|
||||
|
||||
// Optional: restore saved state
|
||||
// if (this.saveStateKey && this.plugin.settings.collapsedSections[this.saveStateKey] !== undefined) {
|
||||
// this.isOpen = !this.plugin.settings.collapsedSections[this.saveStateKey];
|
||||
// if (!this.isOpen) {
|
||||
// this.contentEl.hide();
|
||||
// }
|
||||
// }
|
||||
|
||||
debugLog("Rendered", this.saveStateKey || this.headerText, "as", this.isOpen);
|
||||
}
|
||||
|
||||
public getContentContainer(): HTMLElement {
|
||||
return this.contentEl;
|
||||
}
|
||||
|
||||
private async toggle() {
|
||||
this.isOpen = !this.isOpen;
|
||||
debugLog("Toggled", this.saveStateKey || this.headerText, "to", this.isOpen);
|
||||
|
||||
const icon = this.isOpen ? "chevron-down" : "chevron-right";
|
||||
const tooltip = this.isOpen ? "Collapse" : "Expand";
|
||||
|
||||
// Rebuild or update the toggle button if needed
|
||||
// Or store a reference to the button and just update its properties
|
||||
|
||||
if (this.isOpen) {
|
||||
this.contentEl.show();
|
||||
} else {
|
||||
this.contentEl.hide();
|
||||
}
|
||||
this.toggleBtn.setIcon(icon).setTooltip(tooltip);
|
||||
|
||||
if (this.saveStateKey && this.plugin) {
|
||||
this.plugin.settings.collapsedSections[this.saveStateKey] = this.isOpen;
|
||||
await this.plugin.saveSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,446 +1,94 @@
|
|||
import {App, normalizePath, Notice, PluginSettingTab, setIcon, Setting} from "obsidian";
|
||||
import { App, PluginSettingTab } from "obsidian";
|
||||
import JiraPlugin from "../main";
|
||||
import {obsidianJiraFieldMappings} from "../constants/obsidianJiraFieldsMapping";
|
||||
import {
|
||||
jiraFunctionToString, transform_string_to_functions_mappings, validateFunctionString
|
||||
} from "../tools/convertFunctionString";
|
||||
import {debugLog} from "../tools/debugLogging";
|
||||
import { SettingsComponentProps } from "../interfaces/settingsTypes";
|
||||
import { ConnectionSettingsComponent } from "./components/ConnectionSettingsComponent";
|
||||
import { GeneralSettingsComponent } from "./components/GeneralSettingsComponent";
|
||||
import { FieldMappingsComponent } from "./components/FieldMappingsComponent";
|
||||
import { RawIssueViewerComponent } from "./components/RawIssueViewerComponent";
|
||||
import { TestFieldMappingsComponent } from "./components/TestFieldMappingsComponent";
|
||||
import { debugLog } from "../tools/debugLogging";
|
||||
import { CollapsibleSection } from "./CollapsibleSection";
|
||||
|
||||
/**
|
||||
* Settings tab for the plugin
|
||||
* Settings tab for the Jira plugin
|
||||
* Orchestrates all components and manages the overall settings UI
|
||||
*/
|
||||
export class JiraSettingTab extends PluginSettingTab {
|
||||
private plugin: JiraPlugin;
|
||||
private connectionSettings: ConnectionSettingsComponent;
|
||||
private generalSettings: GeneralSettingsComponent;
|
||||
private fieldMappingsSettings: FieldMappingsComponent;
|
||||
private rawIssueViewer: RawIssueViewerComponent;
|
||||
private testFieldMappings: TestFieldMappingsComponent;
|
||||
|
||||
constructor(app: App, plugin: JiraPlugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
|
||||
// Create shared props for all components
|
||||
const componentProps: SettingsComponentProps = {
|
||||
app,
|
||||
plugin,
|
||||
onSettingsChange: this.handleSettingsChange.bind(this)
|
||||
};
|
||||
|
||||
// Initialize all settings components
|
||||
this.connectionSettings = new ConnectionSettingsComponent(componentProps);
|
||||
this.generalSettings = new GeneralSettingsComponent(componentProps);
|
||||
this.fieldMappingsSettings = new FieldMappingsComponent(componentProps);
|
||||
this.rawIssueViewer = new RawIssueViewerComponent(componentProps);
|
||||
this.testFieldMappings = new TestFieldMappingsComponent({ ...componentProps, getCurrentIssue: () => this.rawIssueViewer.getCurrentIssue() });
|
||||
this.rawIssueViewer.onIssueDataChange = () => this.testFieldMappings.setCurrentIssue(this.rawIssueViewer.getCurrentIssue());
|
||||
}
|
||||
|
||||
// Function to save all field mappings
|
||||
async saveStringFieldMappings (element: HTMLDivElement) {
|
||||
debugLog(`From strings ${JSON.stringify(this.plugin.settings.fieldMappingsStrings)}\nand funcs ${JSON.stringify(this.plugin.settings.fieldMappings)}`)
|
||||
const mappings: Record<string, { toJira: string; fromJira: string }> = {};
|
||||
const fieldItems = element.querySelectorAll(".field-mapping-item");
|
||||
|
||||
fieldItems.forEach(item => {
|
||||
const fieldNameInput = item.querySelector(".field-name-input");
|
||||
const toJiraInput = item.querySelector(".to-jira-input");
|
||||
const fromJiraInput = item.querySelector(".from-jira-input");
|
||||
if (!fieldNameInput || !toJiraInput || !fromJiraInput) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fieldName = (fieldNameInput as any).value.trim();
|
||||
const toJira = (toJiraInput as any).value.trim();
|
||||
const fromJira = (fromJiraInput as any).value.trim();
|
||||
|
||||
// Only save valid mappings with all fields filled
|
||||
if (fieldName) {
|
||||
mappings[fieldName] = {
|
||||
toJira: toJira,
|
||||
fromJira: fromJira
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
debugLog(`Mappings: ${JSON.stringify(mappings)}`)
|
||||
|
||||
this.plugin.settings.fieldMappingsStrings = mappings;
|
||||
this.plugin.settings.fieldMappings = await transform_string_to_functions_mappings(mappings,
|
||||
this.plugin.settings.enableFieldValidation);
|
||||
|
||||
// Save the functional mappings
|
||||
debugLog(`To strings ${JSON.stringify(this.plugin.settings.fieldMappingsStrings)}\nand funcs ${JSON.stringify(this.plugin.settings.fieldMappings)}`)
|
||||
/**
|
||||
* Handle settings changes from any component
|
||||
* This can be used for cross-component updates or validation
|
||||
*/
|
||||
private async handleSettingsChange(): Promise<void> {
|
||||
debugLog("Settings changed, handling updates");
|
||||
await this.plugin.saveSettings();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the settings UI
|
||||
*/
|
||||
display(): void {
|
||||
const { containerEl } = this;
|
||||
|
||||
containerEl.empty();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Jira URL")
|
||||
.setDesc("Your Jira instance URL (e.g., https://yourcompany.atlassian.net)")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("URL")
|
||||
.setValue(this.plugin.settings.jiraUrl)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.jiraUrl = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
new CollapsibleSection(this.plugin, containerEl, this.connectionSettings, "Connection settings",
|
||||
this.plugin.settings.collapsedSections.connection, "connection").getContentContainer();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Jira PAT")
|
||||
.setDesc("Personal Access Token (preferred over username+password authentication)")
|
||||
.addText((text) => {
|
||||
text.inputEl.type = "password";
|
||||
text
|
||||
.setPlaceholder("NjM5MDI5MzQ0NT...")
|
||||
.setValue(this.plugin.settings.apiToken)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.apiToken = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
});
|
||||
new CollapsibleSection(this.plugin, containerEl, this.generalSettings, "General settings",
|
||||
this.plugin.settings.collapsedSections.general, "general").getContentContainer();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Jira username")
|
||||
.setDesc("Your Jira username or email")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("admin")
|
||||
.setValue(this.plugin.settings.username)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.username = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
new CollapsibleSection(this.plugin, containerEl, this.fieldMappingsSettings, "Field mappings",
|
||||
this.plugin.settings.collapsedSections.fieldMappings, "fieldMappings").getContentContainer();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Jira password")
|
||||
.setDesc("Your Jira password or API token")
|
||||
.addText((text) => {
|
||||
text.inputEl.type = "password";
|
||||
text
|
||||
.setPlaceholder("qwerty")
|
||||
.setValue(this.plugin.settings.password)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.password = value;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
new CollapsibleSection(this.plugin, containerEl, this.rawIssueViewer, "Raw issue viewer",
|
||||
this.plugin.settings.collapsedSections.rawIssueViewer, "rawIssueViewer").getContentContainer();
|
||||
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Session cookie name")
|
||||
.setDesc("Only needed for username+password authentication")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("JSESSIONID")
|
||||
.setValue(this.plugin.settings.sessionCookieName)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.sessionCookieName = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Issues folder")
|
||||
.setDesc("Folder where Jira issues will be stored")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("jira-issues")
|
||||
.setValue(this.plugin.settings.issuesFolder)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.issuesFolder = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Template path")
|
||||
.setDesc("The path of used template for creating Jira tasks (with or without .md extension)")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("templates/template1")
|
||||
.setValue(this.plugin.settings.templatePath)
|
||||
.onChange(async (value) => {
|
||||
value = normalizePath(value);
|
||||
this.plugin.settings.templatePath = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
// Add Jira-Obsidian Mapping setting
|
||||
new Setting(containerEl).setName("Jira-Obsidian field mapping").setHeading();
|
||||
|
||||
// Create Field Mappings UI
|
||||
const mappingSection = containerEl.createDiv({ cls: "jira-field-mappings" });
|
||||
|
||||
// Add field mapping explanation
|
||||
mappingSection.createEl("p", {
|
||||
text: "Configure how fields are mapped between Obsidian and Jira. Each field requires both a toJira and fromJira transformation function."
|
||||
});
|
||||
|
||||
new Setting(mappingSection)
|
||||
.setName('Enable Field validation')
|
||||
.setDesc('Check fields before saving as functions')
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.enableFieldValidation)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.enableFieldValidation = value;
|
||||
await this.plugin.saveSettings();
|
||||
const fieldItems = fieldsList.querySelectorAll(".field-mapping-item");
|
||||
|
||||
fieldItems.forEach(async item => {
|
||||
const fieldNameInput = item.querySelector(".field-name-input");
|
||||
const toJiraInput = item.querySelector(".to-jira-input");
|
||||
const fromJiraInput = item.querySelector(".from-jira-input");
|
||||
if (fieldNameInput) await fieldValidation(fieldNameInput as HTMLInputElement, value, 'string');
|
||||
if (fieldNameInput) await fieldValidation(toJiraInput as HTMLTextAreaElement, value, 'function', ['value']);
|
||||
if (fieldNameInput) await fieldValidation(fromJiraInput as HTMLTextAreaElement, value, 'function', ['issue', 'data_source']);
|
||||
});
|
||||
}));
|
||||
|
||||
// Add change listeners to update settings
|
||||
const pointInvalidField = (validation: { isValid: boolean; errorMessage?: string }, element: HTMLInputElement | HTMLTextAreaElement, console_output: boolean) => {
|
||||
if (!validation.isValid) {
|
||||
element.classList.add("invalid");
|
||||
if (console_output) {
|
||||
console.warn(`${validation.errorMessage}`);
|
||||
new Notice(`${validation.errorMessage}`);
|
||||
}
|
||||
} else {
|
||||
element.classList.remove("invalid");
|
||||
}
|
||||
}
|
||||
|
||||
async function fieldValidation(input: HTMLInputElement | HTMLTextAreaElement, requireValidating: boolean = true, type: string = 'string', validateParams: Array<string> = []) {
|
||||
const validatorFunction = async (event?: Event)=> {
|
||||
const console_output = !!event;
|
||||
let validation;
|
||||
switch(type) {
|
||||
case 'string':
|
||||
validation = input.value.length === 0? { isValid: false, errorMessage: "Field name cannot be empty" } : { isValid: true };
|
||||
break;
|
||||
case 'function':
|
||||
validation = await validateFunctionString(input.value, validateParams);
|
||||
break;
|
||||
default:
|
||||
validation = { isValid: true };
|
||||
break;
|
||||
}
|
||||
pointInvalidField(validation, input, console_output);
|
||||
}
|
||||
if (!input.hasOwnProperty('_validatorFunction')) {
|
||||
Object.defineProperty(input, '_validatorFunction', {
|
||||
value: validatorFunction,
|
||||
writable: true,
|
||||
configurable: true
|
||||
});
|
||||
} else {
|
||||
input.removeEventListener("change", (input as any)._validatorFunction);
|
||||
(input as any)._validatorFunction = validatorFunction;
|
||||
}
|
||||
|
||||
if (requireValidating) {
|
||||
input.addEventListener("change", (input as any)._validatorFunction);
|
||||
await validatorFunction(); // Run initial validation
|
||||
} else {
|
||||
input.removeEventListener("change", (input as any)._validatorFunction);
|
||||
pointInvalidField({ isValid: true}, input, false); // Clear any validation errors
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Create a list container for field mappings
|
||||
const fieldsList = mappingSection.createDiv({ cls: "field-mappings-list" });
|
||||
|
||||
// Function to add a new field mapping UI
|
||||
const addFieldMapping = async (fieldName = "", toJira = "", fromJira = "") => {
|
||||
const fieldContainer = fieldsList.createDiv({ cls: "field-mapping-item" });
|
||||
|
||||
// Field name input
|
||||
const fieldNameContainer = fieldContainer.createDiv({ cls: "field-name-container" });
|
||||
fieldNameContainer.createEl("span", { text: "Field Name:", cls: "field-mapping-label" });
|
||||
const fieldNameInput = fieldNameContainer.createEl("input", {
|
||||
type: "text",
|
||||
value: fieldName,
|
||||
cls: "field-name-input"
|
||||
});
|
||||
|
||||
// toJira function input
|
||||
const toJiraContainer = fieldContainer.createDiv({ cls: "to-jira-container" });
|
||||
toJiraContainer.createEl("span", { text: "to Jira:", cls: "field-mapping-label" });
|
||||
const toJiraInput = toJiraContainer.createEl("textarea", {
|
||||
cls: "to-jira-input"
|
||||
});
|
||||
toJiraInput.placeholder = "(value) => null";
|
||||
toJiraInput.value = toJira;
|
||||
toJiraInput.rows = 1;
|
||||
|
||||
// fromJira function input
|
||||
const fromJiraContainer = fieldContainer.createDiv({ cls: "from-jira-container" });
|
||||
fromJiraContainer.createEl("span", { text: "from Jira:", cls: "field-mapping-label" });
|
||||
const fromJiraInput = fromJiraContainer.createEl("textarea", {
|
||||
cls: "from-jira-input"
|
||||
});
|
||||
fromJiraInput.value = fromJira;
|
||||
fromJiraInput.placeholder = "(issue, data_source) => null";
|
||||
fromJiraInput.rows = 1;
|
||||
|
||||
// Add remove button
|
||||
const removeBtn = fieldContainer.createEl("button", {
|
||||
text: "✕",
|
||||
cls: "remove-field-btn"
|
||||
});
|
||||
|
||||
// Handle field removal
|
||||
removeBtn.addEventListener("click", () => {
|
||||
fieldContainer.remove();
|
||||
// saveFieldMappings();
|
||||
});
|
||||
|
||||
await fieldValidation(fieldNameInput, this.plugin.settings.enableFieldValidation, 'string');
|
||||
await fieldValidation(toJiraInput, this.plugin.settings.enableFieldValidation, 'function', ['value']);
|
||||
await fieldValidation(fromJiraInput, this.plugin.settings.enableFieldValidation, 'function', ['issue', 'data_source']);
|
||||
|
||||
return { fieldNameInput, toJiraInput, fromJiraInput, container: fieldContainer };
|
||||
};
|
||||
|
||||
const buttonView = mappingSection.createDiv({ cls: "button-view" });
|
||||
|
||||
// Add button to add new field mapping
|
||||
const addFieldBtn = buttonView.createEl("button", {
|
||||
text: "",
|
||||
cls: "add-field-mapping-btn"
|
||||
});
|
||||
setIcon(addFieldBtn, "circle-plus")
|
||||
|
||||
addFieldBtn.addEventListener("click", async () => {
|
||||
await addFieldMapping();
|
||||
});
|
||||
|
||||
const resetBtn = buttonView.createEl("button", {
|
||||
text: "",
|
||||
cls: "reset-field-mappings-btn"
|
||||
})
|
||||
setIcon(resetBtn, "refresh-cw")
|
||||
resetBtn.addEventListener("click", async () => {
|
||||
this.plugin.settings.fieldMappings = {};
|
||||
this.plugin.settings.fieldMappingsStrings = {};
|
||||
await loadExistingMappings();
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
|
||||
const reloadBtn = buttonView.createEl("button", {
|
||||
text: "",
|
||||
cls: "reload-field-mappings-btn"
|
||||
})
|
||||
setIcon(reloadBtn, "list-restart")
|
||||
reloadBtn.addEventListener("click", async () => {
|
||||
this.plugin.settings.fieldMappings = obsidianJiraFieldMappings;
|
||||
|
||||
// Also reset the string representations with default values
|
||||
const defaultMappingsStrings: Record<string, { toJira: string; fromJira: string }> = {};
|
||||
for (const [fieldName, mapping] of Object.entries(obsidianJiraFieldMappings)) {
|
||||
defaultMappingsStrings[fieldName] = {
|
||||
toJira: jiraFunctionToString(mapping.toJira, false),
|
||||
fromJira: jiraFunctionToString(mapping.fromJira, true)
|
||||
};
|
||||
}
|
||||
this.plugin.settings.fieldMappingsStrings = defaultMappingsStrings;
|
||||
|
||||
await loadExistingMappings();
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
|
||||
// Load existing mappings if available
|
||||
const loadExistingMappings = async () => {
|
||||
debugLog(`Loading mapping settings`)
|
||||
// Clear existing field list
|
||||
fieldsList.empty();
|
||||
|
||||
// If we have string representations stored, use those
|
||||
if (this.plugin.settings.fieldMappingsStrings &&
|
||||
Object.keys(this.plugin.settings.fieldMappingsStrings).length > 0) {
|
||||
debugLog('Current mapping (string) is: ',this.plugin.settings.fieldMappingsStrings)
|
||||
|
||||
const savedMappings = this.plugin.settings.fieldMappingsStrings;
|
||||
for (const [fieldName, mapping] of Object.entries(savedMappings)) {
|
||||
if (mapping && typeof mapping === 'object' && 'toJira' in mapping && 'fromJira' in mapping) {
|
||||
await addFieldMapping(
|
||||
fieldName,
|
||||
mapping.toJira,
|
||||
mapping.fromJira
|
||||
);
|
||||
}
|
||||
}
|
||||
this.plugin.settings.fieldMappings = await transform_string_to_functions_mappings(
|
||||
this.plugin.settings.fieldMappingsStrings, this.plugin.settings.enableFieldValidation);
|
||||
}
|
||||
// Otherwise, try to use the function mappings and convert them to strings
|
||||
else if (this.plugin.settings.fieldMappings &&
|
||||
Object.keys(this.plugin.settings.fieldMappings).length > 0) {
|
||||
debugLog('Current mapping is: ',this.plugin.settings.fieldMappings)
|
||||
|
||||
const existingMappings = this.plugin.settings.fieldMappings;
|
||||
for (const [fieldName, mapping] of Object.entries(existingMappings)) {
|
||||
if (mapping && typeof mapping === 'object' && 'toJira' in mapping && 'fromJira' in mapping) {
|
||||
await addFieldMapping(
|
||||
fieldName,
|
||||
jiraFunctionToString(mapping.toJira, false),
|
||||
jiraFunctionToString(mapping.fromJira, true)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the string representations for future use
|
||||
await this.saveStringFieldMappings(fieldsList);
|
||||
}
|
||||
};
|
||||
|
||||
// Make sure to call this function after it's defined
|
||||
loadExistingMappings();
|
||||
|
||||
// Add example mappings section
|
||||
const examplesSection = mappingSection.createDiv({ cls: "mapping-examples" });
|
||||
examplesSection.createEl("h4", { text: "Example field mappings" });
|
||||
|
||||
const examplesList = examplesSection.createEl("ul");
|
||||
|
||||
[
|
||||
{
|
||||
name: "summary",
|
||||
toJira: "value",
|
||||
fromJira: "issue.fields.summary"
|
||||
},
|
||||
{
|
||||
name: "reporter",
|
||||
toJira: "null",
|
||||
fromJira: "issue.fields.reporter.name"
|
||||
},
|
||||
{
|
||||
name: "project",
|
||||
toJira: "({ key: value })",
|
||||
fromJira: "issue.fields.project ? issue.fields.project.key : \"\""
|
||||
}
|
||||
].forEach(example => {
|
||||
const item = examplesList.createEl("li");
|
||||
item.createEl("strong", { text: example.name });
|
||||
// Add button to use this example
|
||||
const useBtn = item.createEl("button", {
|
||||
text: "Use",
|
||||
cls: "use-example-btn"
|
||||
});
|
||||
item.createEl("br");
|
||||
item.createSpan({ text: `toJira: ${example.toJira}` });
|
||||
item.createEl("br");
|
||||
item.createSpan({ text: `fromJira: ${example.fromJira}` });
|
||||
|
||||
|
||||
useBtn.addEventListener("click", async () => {
|
||||
await addFieldMapping(example.name, example.toJira, example.fromJira);
|
||||
});
|
||||
});
|
||||
|
||||
// Add security notice
|
||||
const securityNote = containerEl.createEl("div", { cls: "setting-item-description" });
|
||||
securityNote.createEl("strong", { text: "⚠️ Security Note: " });
|
||||
securityNote.createSpan({ text: "Field mapping uses JavaScript function strings. Validate any shared mappings to prevent security issues." });
|
||||
new CollapsibleSection(this.plugin, containerEl, this.testFieldMappings, "Test field mappings",
|
||||
this.plugin.settings.collapsedSections.testFieldMappings, "testFieldMappings").getContentContainer();
|
||||
}
|
||||
|
||||
hide() {
|
||||
const fieldsList = this.containerEl.querySelector(".field-mappings-list");
|
||||
if (fieldsList) {
|
||||
this.saveStringFieldMappings(fieldsList as HTMLDivElement);
|
||||
/**
|
||||
* Called when the settings tab is hidden
|
||||
*/
|
||||
hide(): void {
|
||||
// Call hide on components that need cleanup
|
||||
if (this.fieldMappingsSettings.hide) {
|
||||
this.fieldMappingsSettings.hide();
|
||||
}
|
||||
if (this.rawIssueViewer.hide) {
|
||||
this.rawIssueViewer.hide();
|
||||
}
|
||||
if (this.testFieldMappings.hide) {
|
||||
this.testFieldMappings.hide();
|
||||
}
|
||||
|
||||
super.hide();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
187
src/settings/components/ConnectionSettingsComponent.ts
Normal file
187
src/settings/components/ConnectionSettingsComponent.ts
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
import { Setting } from "obsidian";
|
||||
import { SettingsComponent, SettingsComponentProps } from "../../interfaces/settingsTypes";
|
||||
|
||||
/**
|
||||
* Component for Jira connection settings
|
||||
*/
|
||||
export class ConnectionSettingsComponent implements SettingsComponent {
|
||||
private props: SettingsComponentProps;
|
||||
private currentAuthMethod: "bearer" | "basic" | "session";
|
||||
private settingElements: Map<string, HTMLElement> = new Map();
|
||||
|
||||
constructor(props: SettingsComponentProps) {
|
||||
this.props = props;
|
||||
this.currentAuthMethod = props.plugin.settings.authMethod || "bearer";
|
||||
}
|
||||
|
||||
render(containerEl: HTMLElement): void {
|
||||
const { plugin } = this.props;
|
||||
|
||||
// Always show: Jira URL
|
||||
new Setting(containerEl)
|
||||
.setName("Jira URL")
|
||||
.setDesc("Your Jira instance URL")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("https://yourcompany.atlassian.net")
|
||||
.setValue(plugin.settings.jiraUrl)
|
||||
.onChange(async (value) => {
|
||||
plugin.settings.jiraUrl = value;
|
||||
await plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
// Auth Method Select
|
||||
const authMethodSetting = new Setting(containerEl)
|
||||
.setName("Authentication method")
|
||||
.setDesc("Choose how to authenticate with Jira")
|
||||
.addDropdown((cb) =>
|
||||
cb
|
||||
.addOption("bearer", "Bearer Token (PAT)")
|
||||
.addOption("basic", "Basic Auth (Username + PAT)")
|
||||
.addOption("session", "Session Cookie (Username + Password)")
|
||||
.setValue(this.currentAuthMethod)
|
||||
.onChange(async (value: "bearer" | "basic" | "session") => {
|
||||
plugin.settings.authMethod = value;
|
||||
await plugin.saveSettings();
|
||||
this.currentAuthMethod = value;
|
||||
this.updateVisibility();
|
||||
})
|
||||
);
|
||||
|
||||
// // Store reference for dynamic visibility control
|
||||
// this.settingElements.set("authMethod", authMethodSetting.settingEl);
|
||||
|
||||
// Jira PAT
|
||||
const patSetting = new Setting(containerEl)
|
||||
.setName("Jira PAT")
|
||||
.setDesc("Personal Access Token")
|
||||
.addText((text) => {
|
||||
text.inputEl.type = "password";
|
||||
text
|
||||
.setPlaceholder("NjM5MDI5MzQ0NT...")
|
||||
.setValue(plugin.settings.apiToken)
|
||||
.onChange(async (value) => {
|
||||
plugin.settings.apiToken = value;
|
||||
await plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
this.settingElements.set("pat", patSetting.settingEl);
|
||||
|
||||
// Jira username
|
||||
const usernameSetting = new Setting(containerEl)
|
||||
.setName("Jira username")
|
||||
.setDesc("Your Jira username")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("admin")
|
||||
.setValue(plugin.settings.username)
|
||||
.onChange(async (value) => {
|
||||
plugin.settings.username = value;
|
||||
await plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
this.settingElements.set("username", usernameSetting.settingEl);
|
||||
|
||||
// Jira username
|
||||
const emailSetting = new Setting(containerEl)
|
||||
.setName("Jira email")
|
||||
.setDesc("Your Jira email")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("admin@gmail.com")
|
||||
.setValue(plugin.settings.email)
|
||||
.onChange(async (value) => {
|
||||
plugin.settings.email = value;
|
||||
await plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
this.settingElements.set("email", emailSetting.settingEl);
|
||||
|
||||
// Jira password
|
||||
const passwordSetting = new Setting(containerEl)
|
||||
.setName("Jira password")
|
||||
.setDesc("Your Jira password")
|
||||
.addText((text) => {
|
||||
text.inputEl.type = "password";
|
||||
text
|
||||
.setPlaceholder("qwerty")
|
||||
.setValue(plugin.settings.password)
|
||||
.onChange(async (value) => {
|
||||
plugin.settings.password = value;
|
||||
await plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
this.settingElements.set("password", passwordSetting.settingEl);
|
||||
|
||||
// // Session cookie name
|
||||
// const sessionCookieSetting = new Setting(containerEl)
|
||||
// .setName("Session cookie name")
|
||||
// .setDesc("Only needed for username+password authentication")
|
||||
// .addText((text) =>
|
||||
// text
|
||||
// .setPlaceholder("JSESSIONID")
|
||||
// .setValue(plugin.settings.sessionCookieName)
|
||||
// .onChange(async (value) => {
|
||||
// plugin.settings.sessionCookieName = value;
|
||||
// await plugin.saveSettings();
|
||||
// })
|
||||
// );
|
||||
// this.settingElements.set("sessionCookie", sessionCookieSetting.settingEl);
|
||||
|
||||
// Initial visibility
|
||||
this.updateVisibility();
|
||||
}
|
||||
|
||||
private updateVisibility(): void {
|
||||
const method = this.currentAuthMethod;
|
||||
|
||||
// // Show always
|
||||
// this.showElement("authMethod");
|
||||
|
||||
// Show PAT if bearer or basic
|
||||
if (method === "bearer" || method === "basic") {
|
||||
this.showElement("pat");
|
||||
} else {
|
||||
this.hideElement("pat");
|
||||
}
|
||||
|
||||
// Show username if basic or session
|
||||
if (method === "session") {
|
||||
this.showElement("username");
|
||||
} else {
|
||||
this.hideElement("username");
|
||||
}
|
||||
|
||||
// Show email if basic or session
|
||||
if (method === "basic") {
|
||||
this.showElement("email");
|
||||
} else {
|
||||
this.hideElement("email");
|
||||
}
|
||||
|
||||
// Show password only if session
|
||||
if (method === "session") {
|
||||
this.showElement("password");
|
||||
} else {
|
||||
this.hideElement("password");
|
||||
}
|
||||
|
||||
// // Show session cookie only if session
|
||||
// if (method === "session") {
|
||||
// this.showElement("sessionCookie");
|
||||
// } else {
|
||||
// this.hideElement("sessionCookie");
|
||||
// }
|
||||
}
|
||||
|
||||
private showElement(key: string): void {
|
||||
const el = this.settingElements.get(key);
|
||||
if (el) el.style.display = "";
|
||||
}
|
||||
|
||||
private hideElement(key: string): void {
|
||||
const el = this.settingElements.get(key);
|
||||
if (el) el.style.display = "none";
|
||||
}
|
||||
}
|
||||
110
src/settings/components/FieldMappingItem.ts
Normal file
110
src/settings/components/FieldMappingItem.ts
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
import { validateField } from "../tools/fieldValidation";
|
||||
|
||||
/**
|
||||
* Interface for field mapping item props
|
||||
*/
|
||||
export interface FieldMappingItemProps {
|
||||
container: HTMLElement;
|
||||
fieldName?: string;
|
||||
toJira?: string;
|
||||
fromJira?: string;
|
||||
enableValidation: boolean;
|
||||
onRemove: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing a single field mapping row
|
||||
*/
|
||||
export class FieldMappingItem {
|
||||
private props: FieldMappingItemProps;
|
||||
private fieldContainer: HTMLDivElement;
|
||||
private fieldNameInput: HTMLInputElement;
|
||||
private toJiraInput: HTMLTextAreaElement;
|
||||
private fromJiraInput: HTMLTextAreaElement;
|
||||
|
||||
constructor(props: FieldMappingItemProps) {
|
||||
this.props = props;
|
||||
this.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current field values
|
||||
*/
|
||||
getValues() {
|
||||
return {
|
||||
fieldName: this.fieldNameInput.value.trim(),
|
||||
toJira: this.toJiraInput.value.trim(),
|
||||
fromJira: this.fromJiraInput.value.trim()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the field mapping item
|
||||
*/
|
||||
private render() {
|
||||
const { container, fieldName = "", toJira = "", fromJira = "", enableValidation } = this.props;
|
||||
|
||||
// Create the field container
|
||||
this.fieldContainer = container.createDiv({ cls: "field-mapping-item" });
|
||||
|
||||
// Create field name input
|
||||
const fieldNameContainer = this.fieldContainer.createDiv({ cls: "field-name-container" });
|
||||
fieldNameContainer.createEl("span", { text: "Field Name:", cls: "field-mapping-label" });
|
||||
this.fieldNameInput = fieldNameContainer.createEl("input", {
|
||||
type: "text",
|
||||
value: fieldName,
|
||||
cls: "field-name-input"
|
||||
});
|
||||
|
||||
// Create toJira function input
|
||||
const toJiraContainer = this.fieldContainer.createDiv({ cls: "to-jira-container" });
|
||||
toJiraContainer.createEl("span", { text: "to Jira:", cls: "field-mapping-label" });
|
||||
this.toJiraInput = toJiraContainer.createEl("textarea", {
|
||||
cls: "to-jira-input"
|
||||
});
|
||||
this.toJiraInput.placeholder = "(value) => null";
|
||||
this.toJiraInput.value = toJira;
|
||||
this.toJiraInput.rows = 1;
|
||||
|
||||
// Create fromJira function input
|
||||
const fromJiraContainer = this.fieldContainer.createDiv({ cls: "from-jira-container" });
|
||||
fromJiraContainer.createEl("span", { text: "from Jira:", cls: "field-mapping-label" });
|
||||
this.fromJiraInput = fromJiraContainer.createEl("textarea", {
|
||||
cls: "from-jira-input"
|
||||
});
|
||||
this.fromJiraInput.value = fromJira;
|
||||
this.fromJiraInput.placeholder = "(issue, data_source) => null";
|
||||
this.fromJiraInput.rows = 1;
|
||||
|
||||
// Add remove button
|
||||
const removeBtn = this.fieldContainer.createEl("button", {
|
||||
text: "✕",
|
||||
cls: "remove-field-btn"
|
||||
});
|
||||
|
||||
// Handle field removal
|
||||
removeBtn.addEventListener("click", () => {
|
||||
this.fieldContainer.remove();
|
||||
this.props.onRemove();
|
||||
});
|
||||
|
||||
// Setup validation
|
||||
this.setupValidation(enableValidation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up validation for inputs
|
||||
*/
|
||||
async setupValidation(enableValidation: boolean) {
|
||||
await validateField(this.fieldNameInput, enableValidation, 'string');
|
||||
await validateField(this.toJiraInput, enableValidation, 'function', ['value']);
|
||||
await validateField(this.fromJiraInput, enableValidation, 'function', ['issue', 'data_source']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update validation state
|
||||
*/
|
||||
async updateValidation(enableValidation: boolean) {
|
||||
await this.setupValidation(enableValidation);
|
||||
}
|
||||
}
|
||||
275
src/settings/components/FieldMappingsComponent.ts
Normal file
275
src/settings/components/FieldMappingsComponent.ts
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
import { Setting, setIcon } from "obsidian";
|
||||
import { SettingsComponent, SettingsComponentProps } from "../../interfaces/settingsTypes";
|
||||
import { FieldMappingItem } from "./FieldMappingItem";
|
||||
import { collectFieldMappingsFromUI, processMappings } from "../tools/mappingTransformers";
|
||||
import {jiraFunctionToString, transform_string_to_functions_mappings} from "../../tools/convertFunctionString";
|
||||
import { obsidianJiraFieldMappings } from "../../constants/obsidianJiraFieldsMapping";
|
||||
import { debugLog } from "../../tools/debugLogging";
|
||||
|
||||
/**
|
||||
* Component for field mappings section
|
||||
*/
|
||||
export class FieldMappingsComponent implements SettingsComponent {
|
||||
private props: SettingsComponentProps;
|
||||
private fieldsList: HTMLDivElement;
|
||||
private mappingItems: FieldMappingItem[] = [];
|
||||
|
||||
constructor(props: SettingsComponentProps) {
|
||||
this.props = props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the field mappings component
|
||||
*/
|
||||
render(containerEl: HTMLElement): void {
|
||||
const { plugin } = this.props;
|
||||
|
||||
// Create the mapping section
|
||||
const mappingSection = containerEl.createDiv({ cls: "jira-field-mappings" });
|
||||
|
||||
// Add explanation
|
||||
mappingSection.createEl("p", {
|
||||
text: "Configure how fields are mapped between Obsidian and Jira. Each field requires both a toJira and fromJira transformation function."
|
||||
});
|
||||
|
||||
// Add validation toggle
|
||||
new Setting(mappingSection)
|
||||
.setName('Enable field validation')
|
||||
.setDesc('Check fields before saving as functions')
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(plugin.settings.enableFieldValidation)
|
||||
.onChange(async (value) => {
|
||||
plugin.settings.enableFieldValidation = value;
|
||||
await plugin.saveSettings();
|
||||
|
||||
// Update validation for all mapping items
|
||||
this.mappingItems.forEach(item => {
|
||||
item.updateValidation(value);
|
||||
});
|
||||
}));
|
||||
|
||||
// Create list container for field mappings
|
||||
this.fieldsList = mappingSection.createDiv({ cls: "field-mappings-list" });
|
||||
|
||||
// Create button container
|
||||
const buttonView = mappingSection.createDiv({ cls: "button-view" });
|
||||
|
||||
// Add button to add new field mapping
|
||||
const addFieldBtn = buttonView.createEl("button", {
|
||||
text: "",
|
||||
cls: "add-field-mapping-btn"
|
||||
});
|
||||
setIcon(addFieldBtn, "circle-plus");
|
||||
|
||||
addFieldBtn.addEventListener("click", () => {
|
||||
this.addFieldMapping();
|
||||
});
|
||||
|
||||
// Reset button
|
||||
const resetBtn = buttonView.createEl("button", {
|
||||
text: "",
|
||||
cls: "reset-field-mappings-btn"
|
||||
});
|
||||
setIcon(resetBtn, "refresh-cw");
|
||||
|
||||
resetBtn.addEventListener("click", async () => {
|
||||
plugin.settings.fieldMappings = {};
|
||||
plugin.settings.fieldMappingsStrings = {};
|
||||
await this.loadExistingMappings();
|
||||
await plugin.saveSettings();
|
||||
});
|
||||
|
||||
// Reload default mappings button
|
||||
const reloadBtn = buttonView.createEl("button", {
|
||||
text: "",
|
||||
cls: "reload-field-mappings-btn"
|
||||
});
|
||||
setIcon(reloadBtn, "list-restart");
|
||||
|
||||
reloadBtn.addEventListener("click", async () => {
|
||||
plugin.settings.fieldMappings = obsidianJiraFieldMappings;
|
||||
|
||||
// Also reset the string representations with default values
|
||||
const defaultMappingsStrings: Record<string, { toJira: string; fromJira: string }> = {};
|
||||
for (const [fieldName, mapping] of Object.entries(obsidianJiraFieldMappings)) {
|
||||
defaultMappingsStrings[fieldName] = {
|
||||
toJira: jiraFunctionToString(mapping.toJira, false),
|
||||
fromJira: jiraFunctionToString(mapping.fromJira, true)
|
||||
};
|
||||
}
|
||||
plugin.settings.fieldMappingsStrings = defaultMappingsStrings;
|
||||
|
||||
await this.loadExistingMappings();
|
||||
await plugin.saveSettings();
|
||||
});
|
||||
|
||||
// Load existing mappings
|
||||
this.loadExistingMappings();
|
||||
|
||||
// Add examples section
|
||||
this.renderExamples(mappingSection);
|
||||
|
||||
// Add security notice
|
||||
const securityNote = containerEl.createEl("div", { cls: "setting-item-description" });
|
||||
securityNote.createEl("strong", { text: "⚠️ Security note: " });
|
||||
securityNote.createSpan({
|
||||
text: "Field mapping uses JavaScript function strings. Validate any shared mappings to prevent security issues."
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new field mapping item
|
||||
*/
|
||||
addFieldMapping(fieldName = "", toJira = "", fromJira = ""): FieldMappingItem {
|
||||
const item = new FieldMappingItem({
|
||||
container: this.fieldsList,
|
||||
fieldName,
|
||||
toJira,
|
||||
fromJira,
|
||||
enableValidation: this.props.plugin.settings.enableFieldValidation,
|
||||
onRemove: () => {
|
||||
// Remove from array when item is removed
|
||||
const index = this.mappingItems.indexOf(item);
|
||||
if (index !== -1) {
|
||||
this.mappingItems.splice(index, 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.mappingItems.push(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load existing mappings
|
||||
*/
|
||||
async loadExistingMappings(): Promise<void> {
|
||||
const { plugin } = this.props;
|
||||
|
||||
// Clear existing field list and items array
|
||||
this.fieldsList.empty();
|
||||
this.mappingItems = [];
|
||||
|
||||
debugLog(`Loading mapping settings`);
|
||||
|
||||
// If we have string representations stored, use those
|
||||
if (plugin.settings.fieldMappingsStrings &&
|
||||
Object.keys(plugin.settings.fieldMappingsStrings).length > 0) {
|
||||
debugLog('Current mapping (string) is: ', plugin.settings.fieldMappingsStrings);
|
||||
|
||||
const savedMappings = plugin.settings.fieldMappingsStrings;
|
||||
for (const [fieldName, mapping] of Object.entries(savedMappings)) {
|
||||
if (mapping && typeof mapping === 'object' && 'toJira' in mapping && 'fromJira' in mapping) {
|
||||
this.addFieldMapping(
|
||||
fieldName,
|
||||
mapping.toJira,
|
||||
mapping.fromJira
|
||||
);
|
||||
}
|
||||
}
|
||||
plugin.settings.fieldMappings = await transform_string_to_functions_mappings(
|
||||
plugin.settings.fieldMappingsStrings,
|
||||
plugin.settings.enableFieldValidation
|
||||
);
|
||||
}
|
||||
// Otherwise, try to use the function mappings and convert them to strings
|
||||
else if (plugin.settings.fieldMappings &&
|
||||
Object.keys(plugin.settings.fieldMappings).length > 0) {
|
||||
debugLog('Current mapping is: ', plugin.settings.fieldMappings);
|
||||
|
||||
const existingMappings = plugin.settings.fieldMappings;
|
||||
for (const [fieldName, mapping] of Object.entries(existingMappings)) {
|
||||
if (mapping && typeof mapping === 'object' && 'toJira' in mapping && 'fromJira' in mapping) {
|
||||
this.addFieldMapping(
|
||||
fieldName,
|
||||
jiraFunctionToString(mapping.toJira, false),
|
||||
jiraFunctionToString(mapping.fromJira, true)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the string representations for future use
|
||||
await this.saveFieldMappings();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save current field mappings
|
||||
*/
|
||||
async saveFieldMappings(): Promise<void> {
|
||||
const { plugin } = this.props;
|
||||
|
||||
debugLog(`From strings ${JSON.stringify(plugin.settings.fieldMappingsStrings)}\nand funcs ${JSON.stringify(plugin.settings.fieldMappings)}`);
|
||||
|
||||
// Collect mappings from UI
|
||||
const stringMappings = await collectFieldMappingsFromUI(this.fieldsList);
|
||||
|
||||
// Process mappings
|
||||
const { stringMappings: newStringMappings, functionMappings } = await processMappings(
|
||||
stringMappings,
|
||||
plugin.settings.enableFieldValidation
|
||||
);
|
||||
|
||||
// Update settings
|
||||
plugin.settings.fieldMappingsStrings = newStringMappings;
|
||||
plugin.settings.fieldMappings = functionMappings;
|
||||
|
||||
debugLog(`To strings ${JSON.stringify(plugin.settings.fieldMappingsStrings)}\nand funcs ${JSON.stringify(plugin.settings.fieldMappings)}`);
|
||||
await plugin.saveSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render example mappings
|
||||
*/
|
||||
private renderExamples(containerEl: HTMLElement): void {
|
||||
const examplesSection = containerEl.createDiv({ cls: "mapping-examples" });
|
||||
examplesSection.createEl("h4", { text: "Example field mappings" });
|
||||
|
||||
const examplesList = examplesSection.createEl("ul");
|
||||
|
||||
const examples = [
|
||||
{
|
||||
name: "summary",
|
||||
toJira: "value",
|
||||
fromJira: "issue.fields.summary"
|
||||
},
|
||||
{
|
||||
name: "reporter",
|
||||
toJira: "null",
|
||||
fromJira: "issue.fields.reporter.name"
|
||||
},
|
||||
{
|
||||
name: "project",
|
||||
toJira: "({ key: value })",
|
||||
fromJira: "issue.fields.project ? issue.fields.project.key : \"\""
|
||||
}
|
||||
];
|
||||
|
||||
examples.forEach(example => {
|
||||
const item = examplesList.createEl("li");
|
||||
item.createEl("strong", { text: example.name });
|
||||
|
||||
// Add button to use this example
|
||||
const useBtn = item.createEl("button", {
|
||||
text: "Use",
|
||||
cls: "use-example-btn"
|
||||
});
|
||||
|
||||
item.createEl("br");
|
||||
item.createSpan({ text: `toJira: ${example.toJira}` });
|
||||
item.createEl("br");
|
||||
item.createSpan({ text: `fromJira: ${example.fromJira}` });
|
||||
|
||||
useBtn.addEventListener("click", () => {
|
||||
this.addFieldMapping(example.name, example.toJira, example.fromJira);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the component is hidden
|
||||
*/
|
||||
hide(): void {
|
||||
this.saveFieldMappings();
|
||||
}
|
||||
}
|
||||
46
src/settings/components/GeneralSettingsComponent.ts
Normal file
46
src/settings/components/GeneralSettingsComponent.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { normalizePath, Setting } from "obsidian";
|
||||
import { SettingsComponent, SettingsComponentProps } from "../../interfaces/settingsTypes";
|
||||
|
||||
/**
|
||||
* Component for general plugin settings
|
||||
*/
|
||||
export class GeneralSettingsComponent implements SettingsComponent {
|
||||
private props: SettingsComponentProps;
|
||||
|
||||
constructor(props: SettingsComponentProps) {
|
||||
this.props = props;
|
||||
}
|
||||
|
||||
render(containerEl: HTMLElement): void {
|
||||
const { plugin } = this.props;
|
||||
|
||||
// Issues folder setting
|
||||
new Setting(containerEl)
|
||||
.setName("Issues folder")
|
||||
.setDesc("Folder where Jira issues will be stored")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("jira-issues")
|
||||
.setValue(plugin.settings.issuesFolder)
|
||||
.onChange(async (value) => {
|
||||
plugin.settings.issuesFolder = value;
|
||||
await plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
// Template path setting
|
||||
new Setting(containerEl)
|
||||
.setName("Template path")
|
||||
.setDesc("The path of used template for creating Jira tasks (with or without .md extension)")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("templates/template1")
|
||||
.setValue(plugin.settings.templatePath)
|
||||
.onChange(async (value) => {
|
||||
value = normalizePath(value);
|
||||
plugin.settings.templatePath = value;
|
||||
await plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
95
src/settings/components/RawIssueViewerComponent.ts
Normal file
95
src/settings/components/RawIssueViewerComponent.ts
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import { Setting, Notice } from "obsidian";
|
||||
import { SettingsComponent, SettingsComponentProps } from "../../interfaces/settingsTypes";
|
||||
import { fetchIssue } from "../../api";
|
||||
import debounce from "lodash/debounce";
|
||||
import hljs from "highlight.js";
|
||||
|
||||
/**
|
||||
* Component for viewing raw Jira issue data
|
||||
*/
|
||||
export class RawIssueViewerComponent implements SettingsComponent {
|
||||
private props: SettingsComponentProps;
|
||||
private issueDataContainer: HTMLElement | null = null;
|
||||
private debouncedFetch: ReturnType<typeof debounce>;
|
||||
private currentIssueData: any = null;
|
||||
public onIssueDataChange?: () => void;
|
||||
|
||||
constructor(props: SettingsComponentProps) {
|
||||
this.props = props;
|
||||
this.debouncedFetch = debounce(this.fetchIssueData.bind(this), 500);
|
||||
}
|
||||
|
||||
render(containerEl: HTMLElement): void {
|
||||
// Add input field for issue key
|
||||
new Setting(containerEl)
|
||||
.setName("View raw issue data")
|
||||
.setDesc("Enter a Jira issue key to view its raw data from the API")
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("PROJ-123")
|
||||
.onChange((value) => {
|
||||
if (value) {
|
||||
this.debouncedFetch(value);
|
||||
} else {
|
||||
this.clearIssueData();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// Create container for issue data
|
||||
this.issueDataContainer = containerEl.createDiv({
|
||||
cls: "jira-raw-issue-container"
|
||||
});
|
||||
}
|
||||
|
||||
public getCurrentIssue(): any {
|
||||
return this.currentIssueData;
|
||||
}
|
||||
|
||||
private async fetchIssueData(value: string): Promise<void> {
|
||||
try {
|
||||
const issueData = await fetchIssue(this.props.plugin, value);
|
||||
this.currentIssueData = issueData;
|
||||
this.displayIssueData(issueData);
|
||||
} catch (error) {
|
||||
new Notice(`Failed to fetch issue: ${error.message}`);
|
||||
this.clearIssueData();
|
||||
}
|
||||
if (this.onIssueDataChange) {
|
||||
this.onIssueDataChange();
|
||||
}
|
||||
}
|
||||
|
||||
private displayIssueData(issueData: any): void {
|
||||
if (!this.issueDataContainer) return;
|
||||
|
||||
this.issueDataContainer.empty();
|
||||
|
||||
const pre = this.issueDataContainer.createEl("pre", {
|
||||
cls: "jira-raw-issue-data",
|
||||
attr: {
|
||||
style: "user-select: text; -webkit-user-select: text; -moz-user-select: text; -ms-user-select: text;"
|
||||
}
|
||||
});
|
||||
|
||||
const code = pre.createEl("code", {
|
||||
cls: "language-json"
|
||||
});
|
||||
|
||||
const jsonString = JSON.stringify(issueData, null, 2);
|
||||
code.setText(jsonString);
|
||||
hljs.highlightElement(code);
|
||||
}
|
||||
|
||||
private clearIssueData(): void {
|
||||
if (this.issueDataContainer) {
|
||||
this.issueDataContainer.empty();
|
||||
}
|
||||
this.currentIssueData = null;
|
||||
}
|
||||
|
||||
hide(): void {
|
||||
this.clearIssueData();
|
||||
this.debouncedFetch.cancel();
|
||||
}
|
||||
}
|
||||
126
src/settings/components/TestFieldMappingsComponent.ts
Normal file
126
src/settings/components/TestFieldMappingsComponent.ts
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
import { SettingsComponent, SettingsComponentProps } from "../../interfaces/settingsTypes";
|
||||
import debounce from "lodash/debounce";
|
||||
import { safeStringToFunction } from "../../tools/convertFunctionString";
|
||||
|
||||
export class TestFieldMappingsComponent implements SettingsComponent {
|
||||
private props: SettingsComponentProps;
|
||||
private testMappingsContainer: HTMLElement | null = null;
|
||||
private currentIssueData: any = null;
|
||||
private getCurrentIssue: (() => any) | null = null;
|
||||
|
||||
constructor(props: SettingsComponentProps & { getCurrentIssue?: () => any }) {
|
||||
this.props = props;
|
||||
if (props.getCurrentIssue) {
|
||||
this.getCurrentIssue = props.getCurrentIssue;
|
||||
}
|
||||
}
|
||||
|
||||
render(containerEl: HTMLElement): void {
|
||||
// Add section header
|
||||
this.testMappingsContainer = containerEl.createDiv({
|
||||
cls: "jira-test-mappings-container"
|
||||
});
|
||||
|
||||
this.testMappingsContainer.createEl("h3", {
|
||||
text: "Test field mappings",
|
||||
cls: "test-mappings-header"
|
||||
});
|
||||
|
||||
this.testMappingsContainer.createEl("p", {
|
||||
text: "Test your field mappings against the current issue data from Raw issue viewer. Enter a fromJira expression to see the result.",
|
||||
cls: "test-mappings-desc"
|
||||
});
|
||||
|
||||
// Container for all test mapping items
|
||||
const itemsContainer = this.testMappingsContainer.createDiv({ cls: "test-mapping-items-list" });
|
||||
(this as any)._testMappingItemsContainer = itemsContainer; // store for later use
|
||||
|
||||
// Add first test mapping item
|
||||
this.addTestMappingItem();
|
||||
|
||||
// Add new mapping button (only once, at the bottom)
|
||||
const addBtn = this.testMappingsContainer.createEl("button", {
|
||||
text: "+ Add test mapping",
|
||||
cls: "add-test-mapping-btn"
|
||||
});
|
||||
addBtn.addEventListener("click", () => {
|
||||
this.addTestMappingItem();
|
||||
});
|
||||
}
|
||||
|
||||
private addTestMappingItem(): void {
|
||||
// Use the dedicated items container
|
||||
const itemsContainer = (this as any)._testMappingItemsContainer as HTMLElement;
|
||||
if (!itemsContainer) return;
|
||||
|
||||
const itemContainer = itemsContainer.createDiv({
|
||||
cls: "test-mapping-item"
|
||||
});
|
||||
|
||||
// From Jira expression input
|
||||
const fromJiraContainer = itemContainer.createDiv({ cls: "from-jira-container" });
|
||||
fromJiraContainer.createEl("span", { text: "from Jira:", cls: "field-mapping-label" });
|
||||
|
||||
const fromJiraInput = fromJiraContainer.createEl("textarea", {
|
||||
cls: "from-jira-input"
|
||||
});
|
||||
fromJiraInput.rows = 1;
|
||||
fromJiraInput.placeholder = "(issue) => null";
|
||||
|
||||
// Value display
|
||||
const valueContainer = itemContainer.createDiv({ cls: "value-container" });
|
||||
valueContainer.createEl("span", { text: "Value:", cls: "field-mapping-label" });
|
||||
const valueDisplay = valueContainer.createEl("div", {
|
||||
cls: "value-display",
|
||||
attr: {
|
||||
style: "user-select: text; -webkit-user-select: text; -moz-user-select: text; -ms-user-select: text;"
|
||||
}
|
||||
});
|
||||
|
||||
// Debounced evaluation function
|
||||
const debouncedEvaluate = debounce(async () => {
|
||||
const issueData = this.getCurrentIssue ? this.getCurrentIssue() : this.currentIssueData;
|
||||
if (!issueData) {
|
||||
valueDisplay.setText("No issue data available");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const fromJiraFn = await safeStringToFunction(fromJiraInput.value, 'fromJira', false);
|
||||
if (fromJiraFn) {
|
||||
const result = fromJiraFn(issueData, null);
|
||||
valueDisplay.setText(JSON.stringify(result, null, 2));
|
||||
} else {
|
||||
valueDisplay.setText("Invalid expression");
|
||||
}
|
||||
} catch (error) {
|
||||
valueDisplay.setText(`Error: ${error.message}`);
|
||||
}
|
||||
}, 500);
|
||||
|
||||
// Add event listeners
|
||||
fromJiraInput.addEventListener("input", debouncedEvaluate);
|
||||
|
||||
// Add remove button
|
||||
const removeBtn = itemContainer.createEl("button", {
|
||||
text: "✕",
|
||||
cls: "remove-field-btn"
|
||||
});
|
||||
removeBtn.addEventListener("click", () => {
|
||||
itemContainer.remove();
|
||||
});
|
||||
}
|
||||
|
||||
// Optionally, allow setting the current issue externally
|
||||
setCurrentIssue(issue: any) {
|
||||
this.currentIssueData = issue;
|
||||
// Trigger re-evaluation of all test mappings
|
||||
this.testMappingsContainer?.querySelectorAll(".from-jira-input").forEach((input: HTMLTextAreaElement) => {
|
||||
input.dispatchEvent(new Event("input"));
|
||||
});
|
||||
}
|
||||
|
||||
hide(): void {
|
||||
// No persistent state to clear
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,15 @@
|
|||
import {FieldMapping} from "../constants/obsidianJiraFieldsMapping";
|
||||
|
||||
export interface JiraSettings {
|
||||
collapsedSections: Record<string, boolean>;
|
||||
|
||||
authMethod: "bearer" | "basic" | "session";
|
||||
apiToken: string;
|
||||
username: string;
|
||||
email: string;
|
||||
password: string;
|
||||
jiraUrl: string;
|
||||
|
||||
issuesFolder: string;
|
||||
sessionCookieName: string;
|
||||
templatePath: string;
|
||||
|
|
@ -14,10 +19,18 @@ export interface JiraSettings {
|
|||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: JiraSettings = {
|
||||
collapsedSections: {
|
||||
connection: true,
|
||||
general: true,
|
||||
fieldMappings: false
|
||||
},
|
||||
authMethod: "bearer",
|
||||
apiToken: "",
|
||||
username: "",
|
||||
email: "",
|
||||
password: "",
|
||||
jiraUrl: "",
|
||||
|
||||
issuesFolder: "jira-issues",
|
||||
sessionCookieName: "JSESSIONID",
|
||||
templatePath: "",
|
||||
|
|
|
|||
89
src/settings/tools/fieldValidation.ts
Normal file
89
src/settings/tools/fieldValidation.ts
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
import { Notice } from "obsidian";
|
||||
import { ValidationResult } from "../../interfaces/settingsTypes";
|
||||
import { validateFunctionString } from "../../tools/convertFunctionString";
|
||||
import { debugLog } from "../../tools/debugLogging";
|
||||
|
||||
/**
|
||||
* Validate a field and update its visual state
|
||||
*/
|
||||
export async function validateField(
|
||||
input: HTMLInputElement | HTMLTextAreaElement,
|
||||
requireValidating: boolean = true,
|
||||
type: string = 'string',
|
||||
validateParams: Array<string> = []
|
||||
): Promise<void> {
|
||||
const validatorFunction = async (event?: Event) => {
|
||||
const consoleOutput = !!event;
|
||||
const validation = await getValidationResult(input.value, type, validateParams);
|
||||
updateFieldAppearance(validation, input, consoleOutput);
|
||||
};
|
||||
|
||||
// Store the validator function on the element to allow for removal
|
||||
setupValidatorProperty(input, validatorFunction);
|
||||
|
||||
if (requireValidating) {
|
||||
input.addEventListener("change", (input as any)._validatorFunction);
|
||||
await validatorFunction(); // Run initial validation
|
||||
} else {
|
||||
input.removeEventListener("change", (input as any)._validatorFunction);
|
||||
updateFieldAppearance({ isValid: true }, input, false); // Clear any validation errors
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get validation result based on type and value
|
||||
*/
|
||||
async function getValidationResult(
|
||||
value: string,
|
||||
type: string = 'string',
|
||||
validateParams: Array<string> = []
|
||||
): Promise<ValidationResult> {
|
||||
switch(type) {
|
||||
case 'string':
|
||||
return value.length === 0
|
||||
? { isValid: false, errorMessage: "Field name cannot be empty" }
|
||||
: { isValid: true };
|
||||
case 'function':
|
||||
return await validateFunctionString(value, validateParams);
|
||||
default:
|
||||
return { isValid: true };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the field appearance based on validation result
|
||||
*/
|
||||
export function updateFieldAppearance(
|
||||
validation: ValidationResult,
|
||||
element: HTMLInputElement | HTMLTextAreaElement,
|
||||
consoleOutput: boolean
|
||||
): void {
|
||||
if (!validation.isValid) {
|
||||
element.classList.add("invalid");
|
||||
if (consoleOutput && validation.errorMessage) {
|
||||
debugLog(validation.errorMessage);
|
||||
new Notice(validation.errorMessage);
|
||||
}
|
||||
} else {
|
||||
element.classList.remove("invalid");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup validator property on input element
|
||||
*/
|
||||
function setupValidatorProperty(
|
||||
input: HTMLInputElement | HTMLTextAreaElement,
|
||||
validatorFunction: (event?: Event) => Promise<void>
|
||||
): void {
|
||||
if (!input.hasOwnProperty('_validatorFunction')) {
|
||||
Object.defineProperty(input, '_validatorFunction', {
|
||||
value: validatorFunction,
|
||||
writable: true,
|
||||
configurable: true
|
||||
});
|
||||
} else {
|
||||
input.removeEventListener("change", (input as any)._validatorFunction);
|
||||
(input as any)._validatorFunction = validatorFunction;
|
||||
}
|
||||
}
|
||||
85
src/settings/tools/mappingTransformers.ts
Normal file
85
src/settings/tools/mappingTransformers.ts
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import { JiraFieldMapping, JiraFieldMappingString } from "../../interfaces/settingsTypes";
|
||||
import {
|
||||
jiraFunctionToString,
|
||||
transform_string_to_functions_mappings,
|
||||
// validateFunctionString
|
||||
} from "../../tools/convertFunctionString";
|
||||
import { debugLog } from "../../tools/debugLogging";
|
||||
|
||||
/**
|
||||
* Convert function mappings to their string representation
|
||||
*/
|
||||
export function convertFunctionMappingsToStrings(
|
||||
mappings: Record<string, JiraFieldMapping>
|
||||
): Record<string, JiraFieldMappingString> {
|
||||
const result: Record<string, JiraFieldMappingString> = {};
|
||||
|
||||
for (const [fieldName, mapping] of Object.entries(mappings)) {
|
||||
if (mapping && typeof mapping === 'object' && 'toJira' in mapping && 'fromJira' in mapping) {
|
||||
result[fieldName] = {
|
||||
toJira: jiraFunctionToString(mapping.toJira, false),
|
||||
fromJira: jiraFunctionToString(mapping.fromJira, true)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect field mappings from the UI
|
||||
*/
|
||||
export async function collectFieldMappingsFromUI(
|
||||
element: HTMLElement,
|
||||
// enableValidation: boolean
|
||||
): Promise<Record<string, JiraFieldMappingString>> {
|
||||
const mappings: Record<string, JiraFieldMappingString> = {};
|
||||
const fieldItems = element.querySelectorAll(".field-mapping-item");
|
||||
|
||||
fieldItems.forEach(item => {
|
||||
const fieldNameInput = item.querySelector(".field-name-input");
|
||||
const toJiraInput = item.querySelector(".to-jira-input");
|
||||
const fromJiraInput = item.querySelector(".from-jira-input");
|
||||
|
||||
if (!fieldNameInput || !toJiraInput || !fromJiraInput) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fieldName = (fieldNameInput as HTMLInputElement).value.trim();
|
||||
const toJira = (toJiraInput as HTMLTextAreaElement).value.trim();
|
||||
const fromJira = (fromJiraInput as HTMLTextAreaElement).value.trim();
|
||||
|
||||
// Only save valid mappings with field name filled
|
||||
if (fieldName) {
|
||||
mappings[fieldName] = {
|
||||
toJira: toJira,
|
||||
fromJira: fromJira
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
debugLog(`Collected mappings: ${JSON.stringify(mappings)}`);
|
||||
return mappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process string mappings to function mappings
|
||||
*/
|
||||
export async function processMappings(
|
||||
stringMappings: Record<string, JiraFieldMappingString>,
|
||||
enableValidation: boolean
|
||||
): Promise<{
|
||||
stringMappings: Record<string, JiraFieldMappingString>,
|
||||
functionMappings: Record<string, JiraFieldMapping>
|
||||
}> {
|
||||
// Convert string mappings to function mappings
|
||||
const functionMappings = await transform_string_to_functions_mappings(
|
||||
stringMappings,
|
||||
enableValidation
|
||||
);
|
||||
|
||||
return {
|
||||
stringMappings,
|
||||
functionMappings
|
||||
};
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ import { JiraIssue } from "../interfaces";
|
|||
import { parse } from "acorn";
|
||||
import {debugLog} from "./debugLogging";
|
||||
import {FieldMapping} from "../constants/obsidianJiraFieldsMapping";
|
||||
import {defaultIssue} from "../constants/defaultIssue";
|
||||
|
||||
// Constants for validation and error messages
|
||||
const FORBIDDEN_PATTERNS = ["document", "window", "eval", "Function", "fetch", "setTimeout"]; // Prevent unsafe code execution
|
||||
|
|
@ -23,7 +24,7 @@ export function validateFunctionStringBrowser(fnString: string, approved_vars: s
|
|||
|
||||
try {
|
||||
if (isSimpleExpression(fnString) || (fnString.startsWith("{") && fnString.endsWith("}") && !fnString.includes("return"))) {
|
||||
fnString = `(${approved_vars.map(varName => varName==='issue'?`${varName} = {fields: {}}`:`${varName} = {}`).join(', ')}) => ${fnString}`;
|
||||
fnString = `(${approved_vars.map(varName => varName==='issue'?`${varName} = ${JSON.stringify(defaultIssue)}`:`${varName} = {}`).join(', ')}) => ${fnString}`;
|
||||
}
|
||||
debugLog(`checking function: ${fnString}`);
|
||||
let func = (iframeWindow as any).eval(fnString);
|
||||
|
|
|
|||
240
styles.css
240
styles.css
|
|
@ -1,3 +1,118 @@
|
|||
.jira-collapsible-section {
|
||||
padding: 8px;
|
||||
border-left: 2px solid var(--background-modifier-border);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.jira-collapsible-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.jira-collapsible-content {
|
||||
margin-top: 20px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.jira-test-mappings-container {
|
||||
margin-top: 2em;
|
||||
padding: 1em 0;
|
||||
}
|
||||
|
||||
.test-mappings-header {
|
||||
margin-bottom: 0.2em;
|
||||
}
|
||||
|
||||
.test-mappings-desc {
|
||||
margin-bottom: 1em;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.test-mapping-items-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.2em;
|
||||
}
|
||||
|
||||
.test-mapping-item {
|
||||
background: var(--background-secondary-alt);
|
||||
border-radius: 8px;
|
||||
padding: 1em 1em 1em 1.2em;
|
||||
position: relative;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
.value-container {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.value-display {
|
||||
background: var(--background-primary-alt);
|
||||
border-radius: 4px;
|
||||
padding: 0.5em 0.8em;
|
||||
font-family: var(--font-monospace);
|
||||
font-size: 0.98em;
|
||||
margin-top: 0.2em;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
|
||||
.test-mapping-item .from-jira-container {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.test-mapping-item .from-jira-input {
|
||||
width: 100%;
|
||||
min-height: 2.2em;
|
||||
font-family: var(--font-monospace);
|
||||
font-size: 1em;
|
||||
margin-top: 0.2em;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
background: var(--background-primary-alt);
|
||||
color: var(--text-normal);
|
||||
padding: 0.3em 0.5em;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.remove-field-btn {
|
||||
position: absolute;
|
||||
top: 0.5em;
|
||||
right: 0.7em;
|
||||
background: var(--background-modifier-error);
|
||||
color: var(--text-on-accent);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 1.1em;
|
||||
padding: 0.1em 0.5em;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.remove-field-btn:hover {
|
||||
background: var(--background-modifier-error-hover);
|
||||
}
|
||||
|
||||
.add-test-mapping-btn {
|
||||
display: block;
|
||||
margin: 1.5em auto 0 auto;
|
||||
padding: 0.5em 1.5em;
|
||||
background: var(--interactive-accent);
|
||||
color: var(--text-on-accent);
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 1em;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.add-test-mapping-btn:hover {
|
||||
background: var(--interactive-accent-hover);
|
||||
}
|
||||
|
||||
.jira-field-mappings {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
|
@ -91,3 +206,128 @@
|
|||
.button-view button {
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
|
||||
/*hljs.css*/
|
||||
pre code.hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 1em
|
||||
}
|
||||
code.hljs {
|
||||
padding: 3px 5px
|
||||
}
|
||||
/*!
|
||||
Theme: GitHub
|
||||
Description: Light theme as seen on github.com
|
||||
Author: github.com
|
||||
Maintainer: @Hirse
|
||||
Updated: 2021-05-15
|
||||
|
||||
Outdated base version: https://github.com/primer/github-syntax-light
|
||||
Current colors taken from GitHub's CSS
|
||||
*/
|
||||
.hljs {
|
||||
color: #24292e;
|
||||
background: #ffffff
|
||||
}
|
||||
.hljs-doctag,
|
||||
.hljs-keyword,
|
||||
.hljs-meta .hljs-keyword,
|
||||
.hljs-template-tag,
|
||||
.hljs-template-variable,
|
||||
.hljs-type,
|
||||
.hljs-variable.language_ {
|
||||
/* prettylights-syntax-keyword */
|
||||
color: #f6cc42
|
||||
}
|
||||
.hljs-title,
|
||||
.hljs-title.class_,
|
||||
.hljs-title.class_.inherited__,
|
||||
.hljs-title.function_ {
|
||||
/* prettylights-syntax-entity */
|
||||
color: #6f42c1
|
||||
}
|
||||
.hljs-attr,
|
||||
.hljs-attribute,
|
||||
.hljs-literal,
|
||||
.hljs-meta,
|
||||
|
||||
.hljs-operator,
|
||||
.hljs-variable,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-id {
|
||||
/* prettylights-syntax-constant */
|
||||
color: #6ecbfa
|
||||
}
|
||||
.hljs-number {
|
||||
/* prettylights-syntax-numeric-literal */
|
||||
color: #93cda7
|
||||
}
|
||||
.hljs-regexp,
|
||||
.hljs-string,
|
||||
.hljs-meta .hljs-string {
|
||||
/* prettylights-syntax-string */
|
||||
color: #cd905c
|
||||
}
|
||||
.hljs-built_in,
|
||||
.hljs-symbol {
|
||||
/* prettylights-syntax-variable */
|
||||
color: #e36209
|
||||
}
|
||||
.hljs-comment,
|
||||
.hljs-code,
|
||||
.hljs-formula {
|
||||
/* prettylights-syntax-comment */
|
||||
color: #6a737d
|
||||
}
|
||||
.hljs-name,
|
||||
.hljs-quote,
|
||||
.hljs-selector-tag,
|
||||
.hljs-selector-pseudo {
|
||||
/* prettylights-syntax-entity-tag */
|
||||
color: #22863a
|
||||
}
|
||||
.hljs-subst {
|
||||
/* prettylights-syntax-storage-modifier-import */
|
||||
color: #24292e
|
||||
}
|
||||
.hljs-section {
|
||||
/* prettylights-syntax-markup-heading */
|
||||
color: #005cc5;
|
||||
font-weight: bold
|
||||
}
|
||||
.hljs-bullet {
|
||||
/* prettylights-syntax-markup-list */
|
||||
color: #735c0f
|
||||
}
|
||||
.hljs-emphasis {
|
||||
/* prettylights-syntax-markup-italic */
|
||||
color: #24292e;
|
||||
font-style: italic
|
||||
}
|
||||
.hljs-strong {
|
||||
/* prettylights-syntax-markup-bold */
|
||||
color: #24292e;
|
||||
font-weight: bold
|
||||
}
|
||||
.hljs-addition {
|
||||
/* prettylights-syntax-markup-inserted */
|
||||
color: #22863a;
|
||||
background-color: #f0fff4
|
||||
}
|
||||
.hljs-deletion {
|
||||
/* prettylights-syntax-markup-deleted */
|
||||
color: #b31d28;
|
||||
background-color: #ffeef0
|
||||
}
|
||||
.hljs-char.escape_,
|
||||
.hljs-link,
|
||||
.hljs-params,
|
||||
.hljs-property,
|
||||
.hljs-punctuation,
|
||||
.hljs-tag {
|
||||
/* purposely ignored */
|
||||
|
||||
}
|
||||
|
|
|
|||
767
yarn.lock
767
yarn.lock
|
|
@ -2,131 +2,83 @@
|
|||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@esbuild/aix-ppc64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz#499600c5e1757a524990d5d92601f0ac3ce87f64"
|
||||
integrity sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==
|
||||
"@codemirror/state@^6.0.0", "@codemirror/state@^6.5.0":
|
||||
version "6.5.2"
|
||||
resolved "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz"
|
||||
integrity sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==
|
||||
dependencies:
|
||||
"@marijn/find-cluster-break" "^1.0.0"
|
||||
|
||||
"@esbuild/android-arm64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz#b9b8231561a1dfb94eb31f4ee056b92a985c324f"
|
||||
integrity sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==
|
||||
|
||||
"@esbuild/android-arm@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.0.tgz#ca6e7888942505f13e88ac9f5f7d2a72f9facd2b"
|
||||
integrity sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==
|
||||
|
||||
"@esbuild/android-x64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.0.tgz#e765ea753bac442dfc9cb53652ce8bd39d33e163"
|
||||
integrity sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==
|
||||
|
||||
"@esbuild/darwin-arm64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz#fa394164b0d89d4fdc3a8a21989af70ef579fa2c"
|
||||
integrity sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==
|
||||
|
||||
"@esbuild/darwin-x64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz#91979d98d30ba6e7d69b22c617cc82bdad60e47a"
|
||||
integrity sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==
|
||||
|
||||
"@esbuild/freebsd-arm64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz#b97e97073310736b430a07b099d837084b85e9ce"
|
||||
integrity sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==
|
||||
|
||||
"@esbuild/freebsd-x64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz#f3b694d0da61d9910ec7deff794d444cfbf3b6e7"
|
||||
integrity sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==
|
||||
|
||||
"@esbuild/linux-arm64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz#f921f699f162f332036d5657cad9036f7a993f73"
|
||||
integrity sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==
|
||||
|
||||
"@esbuild/linux-arm@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz#cc49305b3c6da317c900688995a4050e6cc91ca3"
|
||||
integrity sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==
|
||||
|
||||
"@esbuild/linux-ia32@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz#3e0736fcfab16cff042dec806247e2c76e109e19"
|
||||
integrity sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==
|
||||
|
||||
"@esbuild/linux-loong64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz#ea2bf730883cddb9dfb85124232b5a875b8020c7"
|
||||
integrity sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==
|
||||
|
||||
"@esbuild/linux-mips64el@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz#4cababb14eede09248980a2d2d8b966464294ff1"
|
||||
integrity sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==
|
||||
|
||||
"@esbuild/linux-ppc64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz#8860a4609914c065373a77242e985179658e1951"
|
||||
integrity sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==
|
||||
|
||||
"@esbuild/linux-riscv64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz#baf26e20bb2d38cfb86ee282dff840c04f4ed987"
|
||||
integrity sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==
|
||||
|
||||
"@esbuild/linux-s390x@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz#8323afc0d6cb1b6dc6e9fd21efd9e1542c3640a4"
|
||||
integrity sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==
|
||||
|
||||
"@esbuild/linux-x64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz#08fcf60cb400ed2382e9f8e0f5590bac8810469a"
|
||||
integrity sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==
|
||||
|
||||
"@esbuild/netbsd-arm64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz#935c6c74e20f7224918fbe2e6c6fe865b6c6ea5b"
|
||||
integrity sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==
|
||||
|
||||
"@esbuild/netbsd-x64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz#414677cef66d16c5a4d210751eb2881bb9c1b62b"
|
||||
integrity sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==
|
||||
|
||||
"@esbuild/openbsd-arm64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz#8fd55a4d08d25cdc572844f13c88d678c84d13f7"
|
||||
integrity sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==
|
||||
|
||||
"@esbuild/openbsd-x64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz#0c48ddb1494bbc2d6bcbaa1429a7f465fa1dedde"
|
||||
integrity sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==
|
||||
|
||||
"@esbuild/sunos-x64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz#86ff9075d77962b60dd26203d7352f92684c8c92"
|
||||
integrity sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==
|
||||
|
||||
"@esbuild/win32-arm64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz#849c62327c3229467f5b5cd681bf50588442e96c"
|
||||
integrity sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==
|
||||
|
||||
"@esbuild/win32-ia32@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz#f62eb480cd7cca088cb65bb46a6db25b725dc079"
|
||||
integrity sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==
|
||||
"@codemirror/view@^6.0.0":
|
||||
version "6.36.4"
|
||||
resolved "https://registry.npmjs.org/@codemirror/view/-/view-6.36.4.tgz"
|
||||
integrity sha512-ZQ0V5ovw/miKEXTvjgzRyjnrk9TwriUB1k4R5p7uNnHR9Hus+D1SXHGdJshijEzPFjU25xea/7nhIeSqYFKdbA==
|
||||
dependencies:
|
||||
"@codemirror/state" "^6.5.0"
|
||||
style-mod "^4.1.0"
|
||||
w3c-keyname "^2.2.4"
|
||||
|
||||
"@esbuild/win32-x64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz"
|
||||
integrity sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==
|
||||
|
||||
"@eslint-community/eslint-utils@^4.2.0":
|
||||
version "4.5.1"
|
||||
resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz"
|
||||
integrity sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==
|
||||
dependencies:
|
||||
eslint-visitor-keys "^3.4.3"
|
||||
|
||||
"@eslint-community/regexpp@^4.6.1":
|
||||
version "4.12.1"
|
||||
resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz"
|
||||
integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==
|
||||
|
||||
"@eslint/eslintrc@^2.1.4":
|
||||
version "2.1.4"
|
||||
resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz"
|
||||
integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==
|
||||
dependencies:
|
||||
ajv "^6.12.4"
|
||||
debug "^4.3.2"
|
||||
espree "^9.6.0"
|
||||
globals "^13.19.0"
|
||||
ignore "^5.2.0"
|
||||
import-fresh "^3.2.1"
|
||||
js-yaml "^4.1.0"
|
||||
minimatch "^3.1.2"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@eslint/js@8.57.1":
|
||||
version "8.57.1"
|
||||
resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz"
|
||||
integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==
|
||||
|
||||
"@humanwhocodes/config-array@^0.13.0":
|
||||
version "0.13.0"
|
||||
resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz"
|
||||
integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==
|
||||
dependencies:
|
||||
"@humanwhocodes/object-schema" "^2.0.3"
|
||||
debug "^4.3.1"
|
||||
minimatch "^3.0.5"
|
||||
|
||||
"@humanwhocodes/module-importer@^1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz"
|
||||
integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
|
||||
|
||||
"@humanwhocodes/object-schema@^2.0.3":
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz"
|
||||
integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
|
||||
|
||||
"@marijn/find-cluster-break@^1.0.0":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz"
|
||||
integrity sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
|
||||
|
|
@ -135,12 +87,12 @@
|
|||
"@nodelib/fs.stat" "2.0.5"
|
||||
run-parallel "^1.1.9"
|
||||
|
||||
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
|
||||
"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
|
||||
version "2.0.5"
|
||||
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
|
||||
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
||||
|
||||
"@nodelib/fs.walk@^1.2.3":
|
||||
"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8":
|
||||
version "1.2.8"
|
||||
resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz"
|
||||
integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
|
||||
|
|
@ -165,6 +117,11 @@
|
|||
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz"
|
||||
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
||||
|
||||
"@types/lodash@^4.17.16":
|
||||
version "4.17.16"
|
||||
resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz"
|
||||
integrity sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==
|
||||
|
||||
"@types/node@^16.11.6":
|
||||
version "16.18.121"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-16.18.121.tgz"
|
||||
|
|
@ -192,7 +149,7 @@
|
|||
semver "^7.3.7"
|
||||
tsutils "^3.21.0"
|
||||
|
||||
"@typescript-eslint/parser@5.29.0":
|
||||
"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@5.29.0":
|
||||
version "5.29.0"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.29.0.tgz"
|
||||
integrity sha512-ruKWTv+x0OOxbzIw9nW5oWlUopvP/IQDjB5ZqmTglLIoDTctLlAJpAQFpNPJP/ZI7hTT9sARBosEfaKbcFuECw==
|
||||
|
|
@ -257,16 +214,66 @@
|
|||
"@typescript-eslint/types" "5.29.0"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
acorn@^8.14.1:
|
||||
"@ungap/structured-clone@^1.2.0":
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz"
|
||||
integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==
|
||||
|
||||
acorn-jsx@^5.3.2:
|
||||
version "5.3.2"
|
||||
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
|
||||
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
||||
|
||||
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.14.1, acorn@^8.9.0:
|
||||
version "8.14.1"
|
||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz"
|
||||
integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==
|
||||
|
||||
ajv@^6.12.4:
|
||||
version "6.12.6"
|
||||
resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
|
||||
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.1"
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
json-schema-traverse "^0.4.1"
|
||||
uri-js "^4.2.2"
|
||||
|
||||
ansi-regex@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz"
|
||||
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
|
||||
|
||||
ansi-styles@^4.1.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
|
||||
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
|
||||
dependencies:
|
||||
color-convert "^2.0.1"
|
||||
|
||||
argparse@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz"
|
||||
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
|
||||
|
||||
array-union@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz"
|
||||
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
|
||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz"
|
||||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
braces@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz"
|
||||
|
|
@ -279,13 +286,57 @@ builtin-modules@3.3.0:
|
|||
resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz"
|
||||
integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
|
||||
|
||||
debug@^4.3.4:
|
||||
callsites@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz"
|
||||
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
|
||||
|
||||
chalk@^4.0.0:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
|
||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
||||
dependencies:
|
||||
ansi-styles "^4.1.0"
|
||||
supports-color "^7.1.0"
|
||||
|
||||
color-convert@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
|
||||
integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
|
||||
dependencies:
|
||||
color-name "~1.1.4"
|
||||
|
||||
color-name@~1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
|
||||
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
||||
|
||||
cross-spawn@^7.0.2:
|
||||
version "7.0.6"
|
||||
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz"
|
||||
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
|
||||
dependencies:
|
||||
path-key "^3.1.0"
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
|
||||
version "4.3.7"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz"
|
||||
integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==
|
||||
dependencies:
|
||||
ms "^2.1.3"
|
||||
|
||||
deep-is@^0.1.3:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
|
||||
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
|
||||
|
||||
dir-glob@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz"
|
||||
|
|
@ -293,6 +344,13 @@ dir-glob@^3.0.1:
|
|||
dependencies:
|
||||
path-type "^4.0.0"
|
||||
|
||||
doctrine@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz"
|
||||
integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
|
||||
esbuild@0.25.0:
|
||||
version "0.25.0"
|
||||
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz"
|
||||
|
|
@ -324,6 +382,11 @@ esbuild@0.25.0:
|
|||
"@esbuild/win32-ia32" "0.25.0"
|
||||
"@esbuild/win32-x64" "0.25.0"
|
||||
|
||||
escape-string-regexp@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz"
|
||||
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
||||
|
||||
eslint-scope@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz"
|
||||
|
|
@ -332,6 +395,14 @@ eslint-scope@^5.1.1:
|
|||
esrecurse "^4.3.0"
|
||||
estraverse "^4.1.1"
|
||||
|
||||
eslint-scope@^7.2.2:
|
||||
version "7.2.2"
|
||||
resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz"
|
||||
integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
|
||||
dependencies:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^5.2.0"
|
||||
|
||||
eslint-utils@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz"
|
||||
|
|
@ -349,6 +420,76 @@ eslint-visitor-keys@^3.3.0:
|
|||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
|
||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||
|
||||
eslint-visitor-keys@^3.4.1:
|
||||
version "3.4.3"
|
||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
|
||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||
|
||||
eslint-visitor-keys@^3.4.3:
|
||||
version "3.4.3"
|
||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
|
||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||
|
||||
eslint@*, "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", eslint@>=5:
|
||||
version "8.57.1"
|
||||
resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz"
|
||||
integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.2.0"
|
||||
"@eslint-community/regexpp" "^4.6.1"
|
||||
"@eslint/eslintrc" "^2.1.4"
|
||||
"@eslint/js" "8.57.1"
|
||||
"@humanwhocodes/config-array" "^0.13.0"
|
||||
"@humanwhocodes/module-importer" "^1.0.1"
|
||||
"@nodelib/fs.walk" "^1.2.8"
|
||||
"@ungap/structured-clone" "^1.2.0"
|
||||
ajv "^6.12.4"
|
||||
chalk "^4.0.0"
|
||||
cross-spawn "^7.0.2"
|
||||
debug "^4.3.2"
|
||||
doctrine "^3.0.0"
|
||||
escape-string-regexp "^4.0.0"
|
||||
eslint-scope "^7.2.2"
|
||||
eslint-visitor-keys "^3.4.3"
|
||||
espree "^9.6.1"
|
||||
esquery "^1.4.2"
|
||||
esutils "^2.0.2"
|
||||
fast-deep-equal "^3.1.3"
|
||||
file-entry-cache "^6.0.1"
|
||||
find-up "^5.0.0"
|
||||
glob-parent "^6.0.2"
|
||||
globals "^13.19.0"
|
||||
graphemer "^1.4.0"
|
||||
ignore "^5.2.0"
|
||||
imurmurhash "^0.1.4"
|
||||
is-glob "^4.0.0"
|
||||
is-path-inside "^3.0.3"
|
||||
js-yaml "^4.1.0"
|
||||
json-stable-stringify-without-jsonify "^1.0.1"
|
||||
levn "^0.4.1"
|
||||
lodash.merge "^4.6.2"
|
||||
minimatch "^3.1.2"
|
||||
natural-compare "^1.4.0"
|
||||
optionator "^0.9.3"
|
||||
strip-ansi "^6.0.1"
|
||||
text-table "^0.2.0"
|
||||
|
||||
espree@^9.6.0, espree@^9.6.1:
|
||||
version "9.6.1"
|
||||
resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz"
|
||||
integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==
|
||||
dependencies:
|
||||
acorn "^8.9.0"
|
||||
acorn-jsx "^5.3.2"
|
||||
eslint-visitor-keys "^3.4.1"
|
||||
|
||||
esquery@^1.4.2:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz"
|
||||
integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==
|
||||
dependencies:
|
||||
estraverse "^5.1.0"
|
||||
|
||||
esrecurse@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz"
|
||||
|
|
@ -361,11 +502,26 @@ estraverse@^4.1.1:
|
|||
resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz"
|
||||
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
|
||||
|
||||
estraverse@^5.1.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
|
||||
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
||||
|
||||
estraverse@^5.2.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
|
||||
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
||||
|
||||
esutils@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz"
|
||||
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
|
||||
|
||||
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
|
||||
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
||||
|
||||
fast-glob@^3.2.9:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz"
|
||||
|
|
@ -377,6 +533,16 @@ fast-glob@^3.2.9:
|
|||
merge2 "^1.3.0"
|
||||
micromatch "^4.0.4"
|
||||
|
||||
fast-json-stable-stringify@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz"
|
||||
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
|
||||
|
||||
fast-levenshtein@^2.0.6:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz"
|
||||
integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
|
||||
|
||||
fastq@^1.6.0:
|
||||
version "1.17.1"
|
||||
resolved "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz"
|
||||
|
|
@ -384,6 +550,13 @@ fastq@^1.6.0:
|
|||
dependencies:
|
||||
reusify "^1.0.4"
|
||||
|
||||
file-entry-cache@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz"
|
||||
integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
|
||||
dependencies:
|
||||
flat-cache "^3.0.4"
|
||||
|
||||
fill-range@^7.1.1:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz"
|
||||
|
|
@ -391,6 +564,33 @@ fill-range@^7.1.1:
|
|||
dependencies:
|
||||
to-regex-range "^5.0.1"
|
||||
|
||||
find-up@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz"
|
||||
integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
|
||||
dependencies:
|
||||
locate-path "^6.0.0"
|
||||
path-exists "^4.0.0"
|
||||
|
||||
flat-cache@^3.0.4:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz"
|
||||
integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==
|
||||
dependencies:
|
||||
flatted "^3.2.9"
|
||||
keyv "^4.5.3"
|
||||
rimraf "^3.0.2"
|
||||
|
||||
flatted@^3.2.9:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz"
|
||||
integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||
|
||||
functional-red-black-tree@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz"
|
||||
|
|
@ -403,6 +603,32 @@ glob-parent@^5.1.2:
|
|||
dependencies:
|
||||
is-glob "^4.0.1"
|
||||
|
||||
glob-parent@^6.0.2:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz"
|
||||
integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
|
||||
dependencies:
|
||||
is-glob "^4.0.3"
|
||||
|
||||
glob@^7.1.3:
|
||||
version "7.2.3"
|
||||
resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz"
|
||||
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.1.1"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
globals@^13.19.0:
|
||||
version "13.24.0"
|
||||
resolved "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz"
|
||||
integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==
|
||||
dependencies:
|
||||
type-fest "^0.20.2"
|
||||
|
||||
globby@^11.1.0:
|
||||
version "11.1.0"
|
||||
resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz"
|
||||
|
|
@ -415,17 +641,58 @@ globby@^11.1.0:
|
|||
merge2 "^1.4.1"
|
||||
slash "^3.0.0"
|
||||
|
||||
graphemer@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz"
|
||||
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
|
||||
|
||||
has-flag@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
|
||||
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
|
||||
|
||||
highlight.js@^11.11.1:
|
||||
version "11.11.1"
|
||||
resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz"
|
||||
integrity sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==
|
||||
|
||||
ignore@^5.2.0:
|
||||
version "5.3.2"
|
||||
resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz"
|
||||
integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
|
||||
|
||||
import-fresh@^3.2.1:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz"
|
||||
integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==
|
||||
dependencies:
|
||||
parent-module "^1.0.0"
|
||||
resolve-from "^4.0.0"
|
||||
|
||||
imurmurhash@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz"
|
||||
integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
|
||||
integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
|
||||
dependencies:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
is-extglob@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
|
||||
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
|
||||
|
||||
is-glob@^4.0.1, is-glob@^4.0.3:
|
||||
is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz"
|
||||
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
|
||||
|
|
@ -437,6 +704,70 @@ is-number@^7.0.0:
|
|||
resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
|
||||
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
||||
|
||||
is-path-inside@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz"
|
||||
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
|
||||
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
|
||||
|
||||
js-yaml@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz"
|
||||
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
|
||||
dependencies:
|
||||
argparse "^2.0.1"
|
||||
|
||||
json-buffer@3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz"
|
||||
integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
|
||||
|
||||
json-schema-traverse@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz"
|
||||
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
|
||||
|
||||
json-stable-stringify-without-jsonify@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz"
|
||||
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
|
||||
|
||||
keyv@^4.5.3:
|
||||
version "4.5.4"
|
||||
resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz"
|
||||
integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
|
||||
dependencies:
|
||||
json-buffer "3.0.1"
|
||||
|
||||
levn@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz"
|
||||
integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
|
||||
dependencies:
|
||||
prelude-ls "^1.2.1"
|
||||
type-check "~0.4.0"
|
||||
|
||||
locate-path@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz"
|
||||
integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
|
||||
dependencies:
|
||||
p-locate "^5.0.0"
|
||||
|
||||
lodash.merge@^4.6.2:
|
||||
version "4.6.2"
|
||||
resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz"
|
||||
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
|
||||
|
||||
lodash@^4.17.21:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
||||
merge2@^1.3.0, merge2@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
|
||||
|
|
@ -450,6 +781,13 @@ micromatch@^4.0.4:
|
|||
braces "^3.0.3"
|
||||
picomatch "^2.3.1"
|
||||
|
||||
minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
moment@2.29.4:
|
||||
version "2.29.4"
|
||||
resolved "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz"
|
||||
|
|
@ -460,6 +798,11 @@ ms@^2.1.3:
|
|||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
||||
natural-compare@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
|
||||
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
|
||||
|
||||
obsidian@latest:
|
||||
version "1.8.7"
|
||||
resolved "https://registry.npmjs.org/obsidian/-/obsidian-1.8.7.tgz"
|
||||
|
|
@ -468,6 +811,61 @@ obsidian@latest:
|
|||
"@types/codemirror" "5.60.8"
|
||||
moment "2.29.4"
|
||||
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
|
||||
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
optionator@^0.9.3:
|
||||
version "0.9.4"
|
||||
resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz"
|
||||
integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==
|
||||
dependencies:
|
||||
deep-is "^0.1.3"
|
||||
fast-levenshtein "^2.0.6"
|
||||
levn "^0.4.1"
|
||||
prelude-ls "^1.2.1"
|
||||
type-check "^0.4.0"
|
||||
word-wrap "^1.2.5"
|
||||
|
||||
p-limit@^3.0.2:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz"
|
||||
integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
|
||||
dependencies:
|
||||
yocto-queue "^0.1.0"
|
||||
|
||||
p-locate@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz"
|
||||
integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
|
||||
dependencies:
|
||||
p-limit "^3.0.2"
|
||||
|
||||
parent-module@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz"
|
||||
integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
|
||||
dependencies:
|
||||
callsites "^3.0.0"
|
||||
|
||||
path-exists@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz"
|
||||
integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
|
||||
|
||||
path-is-absolute@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
|
||||
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
|
||||
|
||||
path-key@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz"
|
||||
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
||||
|
||||
path-type@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz"
|
||||
|
|
@ -478,6 +876,16 @@ picomatch@^2.3.1:
|
|||
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
prelude-ls@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz"
|
||||
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
|
||||
|
||||
punycode@^2.1.0:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz"
|
||||
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
|
||||
|
||||
queue-microtask@^1.2.2:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
|
||||
|
|
@ -488,11 +896,23 @@ regexpp@^3.2.0:
|
|||
resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz"
|
||||
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
|
||||
|
||||
resolve-from@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
|
||||
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
|
||||
|
||||
reusify@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz"
|
||||
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
|
||||
|
||||
rimraf@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz"
|
||||
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
run-parallel@^1.1.9:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz"
|
||||
|
|
@ -505,11 +925,52 @@ semver@^7.3.7:
|
|||
resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz"
|
||||
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
|
||||
|
||||
shebang-command@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"
|
||||
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
|
||||
dependencies:
|
||||
shebang-regex "^3.0.0"
|
||||
|
||||
shebang-regex@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz"
|
||||
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
||||
|
||||
slash@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
|
||||
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
||||
|
||||
strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-json-comments@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz"
|
||||
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
|
||||
|
||||
style-mod@^4.1.0:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz"
|
||||
integrity sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==
|
||||
|
||||
supports-color@^7.1.0:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
|
||||
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
|
||||
dependencies:
|
||||
has-flag "^4.0.0"
|
||||
|
||||
text-table@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
|
||||
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
|
||||
|
||||
to-regex-range@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
|
||||
|
|
@ -517,16 +978,16 @@ to-regex-range@^5.0.1:
|
|||
dependencies:
|
||||
is-number "^7.0.0"
|
||||
|
||||
tslib@2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz"
|
||||
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
|
||||
|
||||
tslib@^1.8.1:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tslib@2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz"
|
||||
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
|
||||
|
||||
tsutils@^3.21.0:
|
||||
version "3.21.0"
|
||||
resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz"
|
||||
|
|
@ -534,12 +995,58 @@ tsutils@^3.21.0:
|
|||
dependencies:
|
||||
tslib "^1.8.1"
|
||||
|
||||
typescript@4.7.4:
|
||||
type-check@^0.4.0, type-check@~0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz"
|
||||
integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
|
||||
dependencies:
|
||||
prelude-ls "^1.2.1"
|
||||
|
||||
type-fest@^0.20.2:
|
||||
version "0.20.2"
|
||||
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz"
|
||||
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
|
||||
|
||||
"typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", typescript@4.7.4:
|
||||
version "4.7.4"
|
||||
resolved "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz"
|
||||
integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
|
||||
|
||||
uri-js@^4.2.2:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz"
|
||||
integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
w3c-keyname@^2.2.4:
|
||||
version "2.2.8"
|
||||
resolved "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz"
|
||||
integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==
|
||||
|
||||
which@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz"
|
||||
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
word-wrap@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz"
|
||||
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
|
||||
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
|
||||
|
||||
yaml@^2.7.0:
|
||||
version "2.7.0"
|
||||
resolved "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz"
|
||||
integrity sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==
|
||||
|
||||
yocto-queue@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"
|
||||
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
||||
|
|
|
|||
Loading…
Reference in a new issue