small fixes

- feedback if field can't be processed from jira format to string properly
  - found an in-code style, carried it to styles.css
  - replaced plugin.app.vault.modify() with plugin.app.vault.process() for atomization
  - html to markdown for description
  - now frontmatter data on update has priority over file content one as it saves it's initial type.
  - several changes for logging work, now it's more intuitive.
This commit is contained in:
Alamion 2025-03-20 02:14:28 +03:00
parent e9553967f4
commit 9248212425
No known key found for this signature in database
GPG key ID: 05B153011396F0BC
19 changed files with 3290 additions and 439 deletions

2
.gitignore vendored
View file

@ -10,7 +10,7 @@ node_modules
# Don't include the compiled main.js file in the repo.
# They should be uploaded to GitHub releases instead.
main.js
*.js
# Exclude sourcemaps
*.map

View file

@ -14,7 +14,7 @@ The template can consist of several different parts:
It is highly recommended to specify basic values in the template's formatter: `key` - the Jira task ID used for updates, `summary` - the Jira task title, and `status` - the current status of the task in Jira.
The body takes priority and will overwrite formatter values when updating a task in Jira if a field's value is present in both sections.
The formatter takes priority and will overwrite file content values when updating a task in Jira if a field's value is present in both as formatter saves initial format of value and when putting it in body we parse it to string.
Not all fields are predefined, and some may need adjustments. For example, the template provided in [[docs/template_example.md]] will not correctly retrieve `progressPercent` and `creator` from Jira, even though these fields exist. To fix this, refer to the advanced usage section below.

View file

@ -14,7 +14,7 @@
Настоятельно рекомендуется указать в formatter шаблоона базовые значения: `key` - id задачи в Jira, по которому производится обновление, `summary` - название задачи в Jira, `status` - текущий статус задачи в Jira.
body имеет приоритет и будет перезаписывать значения formatter при одновлении задачи в Jira, если значения для одного поля имеются в обоих местах.
formatter имеет приоритет и будет перезаписывать значения body, если значения для одного поля имеются в обоих местах, так как formatter сохраняет изначальный тип переменной, а body конвертирует её в string.
Не все поля прописаны заранее и некоторые могут нуждаться в доработке. Пример предоставленный в [[docs/template_example.md]] например, не сможет подтянуть корректно `progressPercent` и `creator` из Jira, хотя такие поля существуют. Чтобы это исправить, нужно отбратиться к разделу продвинутого использования ниже.

2023
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -21,5 +21,10 @@
"tslib": "2.4.0",
"typescript": "4.7.4"
},
"dependencies": {}
"dependencies": {
"@types/turndown": "^5.0.5",
"acorn": "^8.14.1",
"turndown": "^7.2.0",
"yaml": "^2.7.0"
}
}

View file

@ -1,4 +1,4 @@
import { MarkdownView, Notice, TFile } from "obsidian";
import { Notice, TFile } from "obsidian";
import JiraPlugin from "../main";
import { IssueTypeModal, ProjectModal } from "../modals";
import { authenticate, fetchIssueTypes, fetchProjects } from "../api";

View file

@ -32,7 +32,7 @@ export async function prepareJiraFieldsFromFile(
// Convert frontmatter and sections to Jira fields
fields = localToJiraFields(
{...frontmatter, ...syncSections},
{...syncSections, ...frontmatter},
{...fieldMappings, ...plugin.settings.fieldMappings});
});

View file

@ -2,7 +2,7 @@ import JiraPlugin from "../main";
import {TFile} from "obsidian";
import {createJiraIssue, updateJiraIssue, updateJiraStatus} from "../api";
import {prepareJiraFieldsFromFile} from "./common_prepareData";
import {updateLocalFromJira} from "../tools/mappingObsidianJiraFields";
import {updateJiraToLocal} from "../tools/mappingObsidianJiraFields";
import {JiraIssue, JiraTransitionType} from "../interfaces";
/**
@ -87,6 +87,6 @@ export async function updateStatusFromFile(plugin: JiraPlugin, file: TFile, tran
}
await updateJiraStatus(plugin, issueKey, transition.id);
await updateLocalFromJira(plugin, file, {fields: {status: {name: transition.status}}} as JiraIssue);
await updateJiraToLocal(plugin, file, {fields: {status: {name: transition.status}}} as JiraIssue);
return issueKey;
}

View file

@ -2,7 +2,7 @@ import JiraPlugin from "../main";
import {JiraIssue} from "../interfaces";
import {ensureIssuesFolder} from "../tools/filesUtils";
import {sanitizeFileName} from "../tools/sanitizers";
import {updateLocalFromJira} from "../tools/mappingObsidianJiraFields";
import {updateJiraToLocal} from "../tools/mappingObsidianJiraFields";
import {Notice, TFile} from "obsidian";
/**
@ -25,7 +25,7 @@ export async function createOrUpdateIssueNote(plugin: JiraPlugin, issue: JiraIss
if (existingFile) {
// File exists, update it
await updateLocalFromJira(plugin, existingFile, issue)
await updateJiraToLocal(plugin, existingFile, issue)
// Open the file
await plugin.app.workspace.openLinkText(existingFile.path, "");
@ -34,7 +34,7 @@ export async function createOrUpdateIssueNote(plugin: JiraPlugin, issue: JiraIss
const newFile = await createNewIssueFile(plugin, filePath);
// Update it
await updateLocalFromJira(plugin, newFile, issue)
await updateJiraToLocal(plugin, newFile, issue)
// Open the file
await plugin.app.workspace.openLinkText(newFile.path, "");

View file

@ -12,6 +12,7 @@ export interface JiraSettings {
templatePath: string;
fieldMappings: Record<string, FieldMapping>;
fieldMappingsStrings: Record<string, { toJira: string; fromJira: string }>;
enableFieldValidation: boolean;
}

View file

@ -67,7 +67,7 @@ export default class JiraPlugin extends Plugin {
*/
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
this.settings.fieldMappings = transform_string_to_functions_mappings(this.settings.fieldMappingsStrings);
this.settings.fieldMappings = await transform_string_to_functions_mappings(this.settings.fieldMappingsStrings);
}
/**

View file

@ -10,6 +10,8 @@ export class WorkLogModal extends Modal {
private startDate: string = "";
private workDescription: string = "";
private displayDate: string = "";
private timeSpentSetting: Setting;
private dateSetting: Setting;
constructor(app: App, onSubmit: (timeSpent: string, startDate: string, workDescription: string) => void) {
super(app);
@ -67,7 +69,7 @@ export class WorkLogModal extends Modal {
this.contentEl.createEl("h2", { text: "Add Work Log" });
// Time Spent field
new Setting(this.contentEl)
this.timeSpentSetting = new Setting(this.contentEl)
.setName("Time Spent")
.setDesc("Format: 3w 4d 12h 30m (weeks, days, hours, minutes)")
.addText((text) =>
@ -79,29 +81,41 @@ export class WorkLogModal extends Modal {
})
);
this.dateSetting = new Setting(this.contentEl)
.setName("Start Time")
.setDesc("Format: DD/MMM/YY HH:MM AM/PM")
.addText((text) =>
text
.setPlaceholder("e.g., 01/Feb/25 10:00 AM")
.setValue(this.displayDate)
.onChange((value) => {
this.displayDate = value;
})
);
// Start Date field with date picker icon
// const dateContainer = this.contentEl.createDiv("date-container");
// dateContainer.style.display = "flex";
// dateContainer.style.alignItems = "center";
// dateContainer.style.gap = "10px";
const dateSetting = new Setting(this.contentEl)
.setName("Date Started")
.setDesc("Format: DD/MMM/YY HH:MM AM/PM")
.addText((text) =>
text
.setPlaceholder("e.g., 01/Jun/21 09:00 AM")
.setValue(this.displayDate)
.onChange((value) => {
this.displayDate = value;
// Parse display date and convert to ISO
const parsedDate = this.parseDisplayDate(value);
if (parsedDate) {
this.startDate = parsedDate.toISOString().split('.')[0] + ".000+0000";
}
})
);
// const dateSetting = new Setting(this.contentEl)
// .setName("Date Started")
// .setDesc("Format: DD/MMM/YY HH:MM AM/PM")
// .addText((text) =>
// text
// .setPlaceholder("e.g., 01/Jun/21 09:00 AM")
// .setValue(this.displayDate)
// .onChange((value) => {
// this.displayDate = value;
//
// // Parse display date and convert to ISO
// const parsedDate = this.parseDisplayDate(value);
// if (parsedDate) {
// this.startDate = parsedDate.toISOString().split('.')[0] + ".000+0000";
// }
// })
// );
// Add date picker later
// const datePickerButton = dateContainer.createEl("button", { cls: "date-picker-button" });
@ -160,7 +174,6 @@ export class WorkLogModal extends Modal {
const textareaComponent = this.contentEl.querySelector(".work-description-container textarea");
if (textareaComponent) {
(textareaComponent as HTMLTextAreaElement).rows = 5;
(textareaComponent as HTMLTextAreaElement).style.width = "100%";
}
// Submit button
@ -185,11 +198,7 @@ export class WorkLogModal extends Modal {
private validateInputs(): boolean {
if (!this.timeSpent.trim()) {
new Notice("Time spent is required");
return false;
}
if (!this.displayDate.trim()) {
new Notice("Start date is required");
this.timeSpentSetting.setClass('invalid');
return false;
}
@ -197,12 +206,20 @@ export class WorkLogModal extends Modal {
const timeSpentPattern = /^(\d+[wdhm]\s*)+$/;
if (!timeSpentPattern.test(this.timeSpent)) {
new Notice("Invalid time format. Use combinations of w (weeks), d (days), h (hours), m (minutes)");
this.timeSpentSetting.setClass('invalid');
return false;
}
if (!this.displayDate.trim()) {
new Notice("Start date is required");
this.dateSetting.setClass('invalid');
return false;
}
// Validate date format by trying to parse it
if (!this.parseDisplayDate(this.displayDate)) {
new Notice("Invalid date format. Use DD/MMM/YY HH:MM AM/PM");
this.dateSetting.setClass('invalid');
return false;
}

View file

@ -1,9 +1,8 @@
import {App, normalizePath, PluginSettingTab, setIcon, Setting} from "obsidian";
import {App, normalizePath, Notice, PluginSettingTab, setIcon, Setting} from "obsidian";
import JiraPlugin from "../main";
import {fieldMappings} from "../tools/mappingObsidianJiraFields";
import {
functionToExpressionString,
transform_string_to_functions_mappings
functionToExpressionString, transform_string_to_functions_mappings, validateFunctionString
} from "../tools/convertFunctionString";
import {debugLog} from "../tools/debugLogging";
@ -18,6 +17,48 @@ export class JiraSettingTab extends PluginSettingTab {
this.plugin = plugin;
}
// 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;
}
// @ts-ignore
const fieldName = fieldNameInput.value.trim();
// @ts-ignore
const toJira = toJiraInput.value.trim();
// @ts-ignore
const fromJira = fromJiraInput.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)}`)
await this.plugin.saveSettings();
};
display(): void {
const { containerEl } = this;
@ -116,11 +157,87 @@ export class JiraSettingTab extends PluginSettingTab {
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 HTMLInputElement, value, 'function', ['value']);
if (fieldNameInput) await fieldValidation(fromJiraInput as HTMLInputElement, 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 {
// @ts-ignore
input.removeEventListener("change", input._validatorFunction);
// @ts-ignore
input._validatorFunction = validatorFunction;
}
if (requireValidating) {
// @ts-ignore
input.addEventListener("change", input._validatorFunction);
await validatorFunction(); // Run initial validation
} else {
// @ts-ignore
input.removeEventListener("change", input._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 = (fieldName = "", toJira = "", fromJira = "") => {
const addFieldMapping = async (fieldName = "", toJira = "", fromJira = "") => {
const fieldContainer = fieldsList.createDiv({ cls: "field-mapping-item" });
// Field name input
@ -135,22 +252,22 @@ export class JiraSettingTab extends PluginSettingTab {
// toJira function input
const toJiraContainer = fieldContainer.createDiv({ cls: "to-jira-container" });
toJiraContainer.createEl("span", { text: "toJira:", cls: "field-mapping-label" });
const toJiraInput = toJiraContainer.createEl("input", {
type: "text",
const toJiraInput = toJiraContainer.createEl("textarea", {
value: toJira,
placeholder: "(value) => value",
placeholder: "(value) => null",
cls: "to-jira-input"
});
toJiraInput.rows = 1;
// fromJira function input
const fromJiraContainer = fieldContainer.createDiv({ cls: "from-jira-container" });
fromJiraContainer.createEl("span", { text: "fromJira:", cls: "field-mapping-label" });
const fromJiraInput = fromJiraContainer.createEl("input", {
type: "text",
const fromJiraInput = fromJiraContainer.createEl("textarea", {
value: fromJira,
placeholder: "(issue) => issue.fields.fieldName",
placeholder: "(issue, data_source) => null",
cls: "from-jira-input"
});
fromJiraInput.rows = 1;
// Add remove button
const removeBtn = fieldContainer.createEl("button", {
@ -161,57 +278,16 @@ export class JiraSettingTab extends PluginSettingTab {
// Handle field removal
removeBtn.addEventListener("click", () => {
fieldContainer.remove();
saveFieldMappings();
// saveFieldMappings();
});
// Add change listeners to update settings
[fieldNameInput, toJiraInput, fromJiraInput].forEach(input => {
input.addEventListener("change", () => {
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 };
};
// Function to save all field mappings
const saveFieldMappings = async () => {
debugLog(`From strings ${JSON.stringify(this.plugin.settings.fieldMappingsStrings)}\n\n and funcs ${JSON.stringify(this.plugin.settings.fieldMappings)}`)
const mappings: Record<string, { toJira: string; fromJira: string }> = {};
const fieldItems = fieldsList.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;
}
// @ts-ignore
const fieldName = fieldNameInput.value.trim();
// @ts-ignore
const toJira = toJiraInput.value.trim();
// @ts-ignore
const fromJira = fromJiraInput.value.trim();
// Only save valid mappings with all fields filled
if (fieldName && toJira && fromJira) {
mappings[fieldName] = {
toJira: toJira,
fromJira: fromJira
};
}
});
// Store the string representations directly in a separate property
this.plugin.settings.fieldMappingsStrings = mappings;
// Save the functional mappings
debugLog(`To strings ${JSON.stringify(this.plugin.settings.fieldMappingsStrings)}\n\nand funcs ${JSON.stringify(this.plugin.settings.fieldMappings)}`)
await this.plugin.saveSettings();
};
const buttonView = mappingSection.createDiv({ cls: "button-view" });
// Add button to add new field mapping
@ -221,8 +297,8 @@ export class JiraSettingTab extends PluginSettingTab {
});
setIcon(addFieldBtn, "circle-plus")
addFieldBtn.addEventListener("click", () => {
addFieldMapping();
addFieldBtn.addEventListener("click", async () => {
await addFieldMapping();
});
const resetBtn = buttonView.createEl("button", {
@ -230,11 +306,11 @@ export class JiraSettingTab extends PluginSettingTab {
cls: "reset-field-mappings-btn"
})
setIcon(resetBtn, "refresh-cw")
resetBtn.addEventListener("click", () => {
resetBtn.addEventListener("click", async () => {
this.plugin.settings.fieldMappings = {};
this.plugin.settings.fieldMappingsStrings = {};
loadExistingMappings();
this.plugin.saveSettings();
await loadExistingMappings();
await this.plugin.saveSettings();
});
const reloadBtn = buttonView.createEl("button", {
@ -242,7 +318,7 @@ export class JiraSettingTab extends PluginSettingTab {
cls: "reset-field-mappings-btn"
})
setIcon(reloadBtn, "list-restart")
reloadBtn.addEventListener("click", () => {
reloadBtn.addEventListener("click", async () => {
this.plugin.settings.fieldMappings = fieldMappings;
// Also reset the string representations with default values
@ -255,12 +331,12 @@ export class JiraSettingTab extends PluginSettingTab {
}
this.plugin.settings.fieldMappingsStrings = defaultMappingsStrings;
loadExistingMappings();
this.plugin.saveSettings();
await loadExistingMappings();
await this.plugin.saveSettings();
});
// Load existing mappings if available
const loadExistingMappings = () => {
const loadExistingMappings = async () => {
debugLog(`Loading mapping settings`)
// Clear existing field list
fieldsList.empty();
@ -272,14 +348,15 @@ export class JiraSettingTab extends PluginSettingTab {
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) {
addFieldMapping(
await addFieldMapping(
fieldName,
mapping.toJira,
mapping.fromJira
);
}
}
this.plugin.settings.fieldMappings = transform_string_to_functions_mappings(this.plugin.settings.fieldMappingsStrings);
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 &&
@ -288,7 +365,7 @@ export class JiraSettingTab extends PluginSettingTab {
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) {
addFieldMapping(
await addFieldMapping(
fieldName,
functionToExpressionString(mapping.toJira),
functionToExpressionString(mapping.fromJira)
@ -297,7 +374,7 @@ export class JiraSettingTab extends PluginSettingTab {
}
// Create the string representations for future use
saveFieldMappings();
await this.saveStringFieldMappings(fieldsList);
}
};
@ -340,8 +417,8 @@ export class JiraSettingTab extends PluginSettingTab {
item.createSpan({ text: `fromJira: ${example.fromJira}` });
useBtn.addEventListener("click", () => {
addFieldMapping(example.name, example.toJira, example.fromJira);
useBtn.addEventListener("click", async () => {
await addFieldMapping(example.name, example.toJira, example.fromJira);
});
});
@ -350,4 +427,12 @@ export class JiraSettingTab extends PluginSettingTab {
securityNote.createEl("strong", { text: "⚠️ Security Note: " });
securityNote.createSpan({ text: "Field mapping uses JavaScript function strings. Validate any shared mappings to prevent security issues." });
}
hide() {
const fieldsList = this.containerEl.querySelector(".field-mappings-list");
if (fieldsList) {
this.saveStringFieldMappings(fieldsList as HTMLDivElement);
}
super.hide();
}
}

View file

@ -12,6 +12,7 @@ export const DEFAULT_SETTINGS: JiraSettings = {
sessionCookieName: "JSESSIONID",
templatePath: "",
fieldMappings: {},
fieldMappingsStrings: {}
fieldMappingsStrings: {},
enableFieldValidation: true
};

View file

@ -1,52 +1,174 @@
import {Notice} from "obsidian";
import { Notice } from "obsidian";
import { FieldMapping } from "./mappingObsidianJiraFields";
import { JiraIssue } from "../interfaces";
import { parse } from "acorn";
import {debugLog} from "./debugLogging";
const forbiddenPatterns = ["document", "window", "eval", "Function", "fetch"]; // Prevent unsafe code execution
import {FieldMapping} from "./mappingObsidianJiraFields";
import {JiraIssue} from "../interfaces";
// Constants for validation and error messages
const FORBIDDEN_PATTERNS = ["document", "window", "eval", "Function", "fetch", "setTimeout"]; // Prevent unsafe code execution
const SYNTAX_KEYWORDS = ["return", "if", "else", "for", "while", "switch", "try", "catch"];
function isValidFunctionBody(fnString: string): boolean {
return !forbiddenPatterns.some(forbidden => fnString.includes(forbidden));
}
export function safeStringToFunction(exprString: string): Function | null {
try {
// Check if the input is a full arrow function or just an expression
const arrowFnMatch = exprString.match(/^\s*\((.*?)\)\s*=>\s*(.*)$/s);
// If it's an arrow function, extract just the body
const body = arrowFnMatch ? arrowFnMatch[2].trim() : exprString.trim();
// Ensure function body does not contain unsafe references
if (!isValidFunctionBody(body)) {
console.warn(`Unsafe expression detected: ${exprString}`);
new Notice(`Unsafe expression detected: ${exprString}`);
return null;
export function validateFunctionStringBrowser(fnString: string, approved_vars: string[] = []): Promise<{ isValid: boolean; errorMessage?: string }> {
return new Promise((resolve) => {
try {
parse(fnString, { ecmaVersion: "latest" });
} catch (error) {
return resolve({ isValid: false, errorMessage: `Syntax error: ${(error as Error).message}` });
}
// Create a function that has access to our utility functions
return function(issue: any) {
// Create a context with our utility functions
const context = {
// jiraToMarkdown,
// markdownToJira
};
const iframe = document.createElement("iframe");
iframe.style.display = "none";
document.body.appendChild(iframe);
const iframeWindow = iframe.contentWindow as Window;
// Create a new function with the utility functions in scope
const fn = new Function(
'issue',
`
// const jiraToMarkdown = this.jiraToMarkdown;
// const markdownToJira = this.markdownToJira;
return ${body};
`
);
try {
if (isSimpleExpression(fnString) || (fnString.startsWith("{") && fnString.endsWith("}") && !fnString.includes("return"))) {
fnString = `(${approved_vars.map(varName => varName==='issue'?`${varName} = {fields: {}}`:`${varName} = {}`).join(', ')}) => ${fnString}`;
}
debugLog(`checking function: ${fnString}`);
// @ts-ignore
iframeWindow.eval(fnString);
resolve({ isValid: true });
} catch (error) {
resolve({ isValid: false, errorMessage: `Runtime error: ${(error as Error).message}` });
} finally {
document.body.removeChild(iframe);
}
});
}
// Execute the function with our context
return fn.apply(context, [issue]);
/**
* Validates a function string for security and syntax issues
* @param fnString - The function string to validate
* @param approved_vars - An array of approved variable names
* @returns An object with validation result and optional error message
*/
export async function validateFunctionString(fnString: string, approved_vars: string[] = []): Promise<{ isValid: boolean; errorMessage?: string }> {
// Check for null, undefined or empty string
if (!fnString || fnString.trim().length === 0) {
return { isValid: true };
}
// Check for forbidden patterns (security)
const foundForbidden = FORBIDDEN_PATTERNS.find(pattern => fnString.includes(pattern));
if (foundForbidden) {
return {
isValid: false,
errorMessage: `Unsafe reference detected: '${foundForbidden}' is not allowed`
};
}
return validateFunctionStringBrowser(fnString, approved_vars);
}
/**
* Determines if the function string is a simple expression or complex function body
* @param fnString - The function string to analyze
* @returns Whether the string is a simple expression (vs. a full function body)
*/
function isSimpleExpression(fnString: string): boolean {
const trimmed = fnString.trim();
// Check if it's a full arrow function
if (trimmed.match(/^\s*\(.*?\)\s*=>\s*.*$/s)) {
return false;
}
// Check if it has typical function body syntax elements
const hasComplexSyntax = SYNTAX_KEYWORDS.some(keyword =>
// Match full keywords, not substrings
new RegExp(`\\b${keyword}\\b`).test(trimmed)
);
// Has curly braces which might indicate a code block
const hasCodeBlock = trimmed.includes("{") && trimmed.includes("}") && trimmed.includes("return");
return !hasComplexSyntax && !hasCodeBlock;
}
/**
* Safely converts a string into a function that can be executed with proper context
* @param exprString - The function or expression string to convert
* @param type - The type of transformation function ('toJira' or 'fromJira')
* @param extraValidate - Whether to validate the function string on syntax, type and other errors
* @returns A wrapped function or null if conversion fails
*/
export async function safeStringToFunction(
exprString: string,
type: 'toJira' | 'fromJira' = 'toJira',
extraValidate: boolean = true
): Promise<Function | null> {
try {
if (exprString.trim().length === 0) {
return () => null;
}
// First validate the string
if (extraValidate) {
const validation = await validateFunctionString(exprString, type === 'fromJira' ? ['issue', 'data_source'] : ['value']);
if (!validation.isValid) {
console.warn(`Invalid function: ${validation.errorMessage}`);
// new Notice(`Invalid function: ${validation.errorMessage}`);
return null;
}
}
// Extract just the function body if it's an arrow function
const arrowFnMatch = exprString.match(/^\s*\((.*?)\)\s*=>\s*(.*)$/s);
let body = arrowFnMatch ? arrowFnMatch[2].trim() : exprString.trim();
// If it's a simple expression, wrap it in a return statement
if (isSimpleExpression(body)) {
body = `return ${body};`;
}
// If body is wrapped in curly braces but doesn't contain a return statement, add one
if (body.startsWith("{") && body.endsWith("}") && !body.includes("return")) {
// Remove the outer braces, add return and put the braces back
body = `{ return ${body.slice(1, -1)} }`;
}
// Create appropriate function based on the type
if (type === 'toJira') {
return function(value: any) {
const context = {
// Add utility functions that should be available in the executed function
// markdownToJira: utility.markdownToJira
};
const fn = new Function('value', `
try {
${body}
} catch (e) {
console.error("Error in toJira function:", e);
return null;
}
`);
return fn.apply(context, [value]);
};
} else { // fromJira
return function(issue: JiraIssue, data_source: Record<string, any> | null) {
const context = {
// Add utility functions for the fromJira context
// jiraToMarkdown: utility.jiraToMarkdown
};
const fn = new Function('issue', 'data_source', `
try {
${body}
} catch (e) {
console.error("Error in fromJira function:", e);
return null;
}
`);
return fn.apply(context, [issue, data_source]);
};
}
} catch (error) {
console.error("Failed to parse expression:", error);
console.error("Failed to parse function:", error);
new Notice(`Failed to create function: ${(error as Error).message}`);
return null;
}
}
@ -75,6 +197,7 @@ export function functionToExpressionString(fn: Function): string {
// If we can't parse it properly, return empty string
console.error("Failed to extract expression from function:", fnStr);
new Notice("Failed to extract expression from function");
return "";
} catch (error) {
console.error("Error converting function to expression string:", error);
@ -82,18 +205,18 @@ export function functionToExpressionString(fn: Function): string {
}
}
export const transform_string_to_functions_mappings = (
mappings: Record<string, { toJira: string; fromJira: string }>) => {
export async function transform_string_to_functions_mappings (
mappings: Record<string, { toJira: string; fromJira: string }>, extraValidate: boolean = true) {
// Also convert to functions for runtime use
const transformedMappings: Record<string, FieldMapping> = {};
for (const [fieldName, { toJira, fromJira }] of Object.entries(mappings)) {
const toJiraFn = safeStringToFunction(toJira);
const fromJiraFn = safeStringToFunction(fromJira);
const toJiraFn = safeStringToFunction(toJira, 'toJira', extraValidate);
const fromJiraFn = safeStringToFunction(fromJira, 'fromJira', extraValidate);
if (toJiraFn && fromJiraFn) {
transformedMappings[fieldName] = {
toJira: toJiraFn as (value: any) => any,
fromJira: fromJiraFn as (issue: JiraIssue, data_source: Record<string, any>) => any,
toJira: await toJiraFn as (value: any) => any,
fromJira: await fromJiraFn as (issue: JiraIssue, data_source: Record<string, any>) => any,
};
} else {
console.warn(`Invalid function in field: ${fieldName}`);

View file

@ -1,9 +1,9 @@
import { JiraIssue } from "../interfaces";
import {jiraToMarkdown, markdownToJira} from "../markdown_html";
import {htmlToMarkdown, jiraToMarkdown} from "./markdown_html";
import {Notice, TFile} from "obsidian";
import JiraPlugin from "../main";
import {extractAllJiraSyncValuesFromContent, updateJiraSyncContent} from "./sectionTools";
import {debugLog} from "./debugLogging";
import YAML from 'yaml'
/**
* Field mapping configurations
@ -14,7 +14,7 @@ export interface FieldMapping {
// Function to transform a value from Obsidian to Jira format
toJira: (value: any) => any;
// Function to transform a value from Jira to Obsidian format
fromJira: (issue: JiraIssue, data_source: Record<string, any>) => any;
fromJira: (issue: JiraIssue, data_source: Record<string, any> | null) => any;
}
/**
@ -28,13 +28,17 @@ export const fieldMappings: Record<string, FieldMapping> = {
fromJira: (issue) => issue.fields.summary,
},
"description": {
toJira: (value) => value, // markdownToJira is applied separately
fromJira: (issue) => issue.fields.description,
toJira: () => null, // markdownToJira is applied separately
fromJira: (issue) => htmlToMarkdown(issue.fields.description),
},
"key": {
toJira: () => null, // Not sent to Jira
fromJira: (issue) => issue.key,
},
"self": {
toJira: () => null,
fromJira: (issue) => issue.self,
},
"project": {
toJira: (value) => ({ key: value }),
fromJira: (issue) =>
@ -65,6 +69,10 @@ export const fieldMappings: Record<string, FieldMapping> = {
toJira: () => null,
fromJira: (issue) => issue.fields["lastViewed"],
},
"link": {
toJira: () => null,
fromJira: (issue) => issue.self.replace(/(\w+:\/\/\S+?)\/.*/, `$1/browse/${issue.key}`),
},
// Add more fields as needed following the same pattern
// Forbidden
@ -76,6 +84,10 @@ export const fieldMappings: Record<string, FieldMapping> = {
toJira: () => null,
fromJira: () => null,
},
"deadline": {
toJira: () => null,
fromJira: () => null,
},
};
/**
@ -95,6 +107,7 @@ export function isMappableField(fieldName: string, customFieldMappings: Record<s
/**
* Convert frontmatter and section fields to Jira fields structure
* @param data_source The frontmatter + sections object
* @param customFieldMappings The custom field mappings
* @returns Object with Jira API compatible structure
*/
export function localToJiraFields(
@ -133,100 +146,131 @@ export function localToJiraFields(
return jiraFields;
}
export async function updateLocalFromJira(
export async function updateJiraToLocal(
plugin: JiraPlugin,
file: TFile,
issue: JiraIssue
): Promise<void> {
// Read the current file content
let fileContent = await plugin.app.vault.read(file);
// Process the file atomically to avoid multiple read/writes
await plugin.app.vault.process(file, (fileContent) => {
// Extract existing sync sections
const syncSections = extractAllJiraSyncValuesFromContent(fileContent);
// Extract existing sync sections
const syncSections = extractAllJiraSyncValuesFromContent(fileContent);
// Create a copy of frontmatter for processing
let frontmatter = {};
// Update frontmatter
await plugin.app.fileManager.processFrontMatter(file, (frontmatter) => {
updateLocalRecordsFromJira(frontmatter, syncSections, issue,
{...fieldMappings, ...plugin.settings.fieldMappings});
// Extract and update frontmatter (we'll need to manually parse and re-add it)
const frontmatterMatch = fileContent.match(/^---\n([\s\S]*?)\n---\n/);
if (frontmatterMatch) {
try {
frontmatter = YAML.parse(frontmatterMatch[1]);
// Update frontmatter with Jira data
applyJiraDataToLocal(frontmatter, issue, {...fieldMappings, ...plugin.settings.fieldMappings});
} catch (e) {
console.error("Error parsing frontmatter:", e);
new Notice("Error parsing frontmatter");
}
}
// Update sync sections with Jira data
applyJiraDataToLocal(syncSections, issue, {...fieldMappings, ...plugin.settings.fieldMappings});
// Replace frontmatter in content
let updatedContent = fileContent;
if (frontmatterMatch) {
const updatedFrontmatter = YAML.stringify(frontmatter);
updatedContent = fileContent.replace(
frontmatterMatch[0],
`---\n${updatedFrontmatter}---\n`
);
}
// Update content sections from Jira fields
for (const [fieldName, fieldValue] of Object.entries(syncSections)) {
const markdownValue = jiraToMarkdown(fieldValue);
updatedContent = updateJiraSyncContent(updatedContent, fieldName, markdownValue);
}
return updatedContent;
});
// Read the updated content (with new frontmatter)
fileContent = await plugin.app.vault.read(file);
// Update sections from Jira fields if they exist
for (const [fieldName, fieldValue] of Object.entries(syncSections)) {
// Only update fields that can be in sections and only existing sections
debugLog(`Updating ${fieldName} = ${fieldValue} in content`)
const markdownValue = jiraToMarkdown(fieldValue);
debugLog(`Converted from jira variant ${fieldValue} to md variant ${markdownValue}`)
fileContent = updateJiraSyncContent(fileContent, fieldName, markdownValue);
}
// Save the updated content
await plugin.app.vault.modify(file, fileContent);
}
/**
* Update frontmatter and sections with values from Jira issue
* @param frontmatter The frontmatter object to update
* @param sections The sections object to update
* @param issue The Jira issue
* Apply Jira data to local records using field mappings
* @param localData - The local data to update (frontmatter or sections)
* @param issue - The Jira issue with source data
* @param fieldMappings - Custom field mappings for transformations
*/
export function updateLocalRecordsFromJira(
frontmatter: Record<string, any>,
sections: Record<string, any>,
export function applyJiraDataToLocal(
localData: Record<string, any>,
issue: JiraIssue,
customFieldMappings: Record<string, FieldMapping>
fieldMappings: Record<string, FieldMapping>
): void {
// Process known fields with mappings
for (const key of Object.keys(frontmatter) as Array<string>) {
// Apply transformation if field exists in frontmatter or is required
if (key in frontmatter || key === 'key' || key === 'summary') {
let value = issue.fields[key];
if (key in customFieldMappings) {
try{
value = customFieldMappings[key].fromJira(issue, {...frontmatter, ...sections});
} catch (e) {
console.error(`Error mapping for ${key}: ${e}`);
new Notice(`Error mapping for ${key}: ${e}`);
continue;
}
}
if (value !== null && value !== undefined) {
frontmatter[key] = value;
}
}
// Process existing fields in local data
for (const key of Object.keys(localData)) {
updateFieldFromJira(key, localData, issue, fieldMappings);
}
for (const key of Object.keys(sections) as Array<string>) {
// Apply transformation if field exists in frontmatter or is required
if (key in sections) {
let value = issue.fields[key];
if (key in customFieldMappings) {
try {
value = customFieldMappings[key].fromJira(issue, {...frontmatter, ...sections});
} catch (e) {
const result: Record<string, {
hasToJira: string,
hasFromJira: string
}> = {};
for (const key of Object.keys(customFieldMappings)) {
result[key] = {
hasToJira: typeof customFieldMappings[key].toJira,
hasFromJira: typeof customFieldMappings[key].fromJira
};
}
console.error(`Error mapping for ${key}: ${e}\n${JSON.stringify(result)}`);
new Notice(`Error mapping for ${key}: ${e}`);
continue;
}
}
if (value !== null && value !== undefined) {
sections[key] = value;
}
// Ensure required fields are always processed
const requiredFields = ['key', 'summary'];
for (const field of requiredFields) {
if (!(field in localData)) {
updateFieldFromJira(field, localData, issue, fieldMappings);
}
}
}
/**
* Update a single field from Jira data
* @param key - The field key to update
* @param targetObject - The object to update (frontmatter or sections)
* @param issue - The Jira issue with source data
* @param fieldMappings - Custom field mappings for transformations
*/
function updateFieldFromJira(
key: string,
targetObject: Record<string, any>,
issue: JiraIssue,
fieldMappings: Record<string, FieldMapping>
): void {
try {
let value = issue.fields[key];
// Apply custom mapping if available
if (key in fieldMappings) {
value = fieldMappings[key].fromJira(issue, targetObject);
}
// Only update if value exists
if (value !== null && value !== undefined) {
targetObject[key] = value;
}
} catch (e) {
// Log available mappings for debugging
logMappingDebugInfo(key, e, fieldMappings);
}
}
/**
* Log debug information for mapping errors
*/
function logMappingDebugInfo(
key: string,
error: Error,
fieldMappings: Record<string, FieldMapping>
): void {
console.error(`Error mapping for ${key}: ${error}`);
new Notice(`Error mapping for ${key}: ${error}`);
// Create debug info about available mappings
const mappingInfo: Record<string, { hasToJira: string, hasFromJira: string }> = {};
for (const mappingKey of Object.keys(fieldMappings)) {
mappingInfo[mappingKey] = {
hasToJira: typeof fieldMappings[mappingKey].toJira,
hasFromJira: typeof fieldMappings[mappingKey].fromJira
};
}
console.debug(`Available mappings: ${JSON.stringify(mappingInfo)}`);
}

View file

@ -1,71 +1,95 @@
import {Notice} from "obsidian";
import TurndownService from 'turndown';
export function htmlToMarkdown(str: any): string {
if (str === null || str === undefined) return '';
else if (typeof str === "number") {
return str.toString()
}
else if (typeof str === "object") {
return JSON.stringify(str)
}
const turndownService = new TurndownService();
return turndownService.turndown(str);
}
/**
* Convert Jira markup to Markdown
* @param str The Jira markup string
* @returns The Markdown string
*/
export function jiraToMarkdown(str: any): string {
if (str === null || str === undefined) return '';
else if (typeof str === "number") {
str = str.toString()
try {
if (str === null || str === undefined) return '';
else if (typeof str === "number") {
str = str.toString()
}
else if (typeof str === "object") {
str = JSON.stringify(str)
}
return (
str
// Un-Ordered Lists
.replace(/^[ \t]*(\*+)\s+/gm, (match: string, stars: string) => {
return `${Array(stars.length).fill('').join('')}* `;
})
// Ordered lists
.replace(/^[ \t]*(#+)\s+/gm, (match: string, nums: string) => {
return `${Array(nums.length).fill('').join('')}1. `;
})
// Headers 1-6
.replace(/^h([0-6])\.(.*)$/gm, (match: string, level: string, content: string) => {
return Array(parseInt(level, 10) + 1).join('#') + ' ' + content.trim();
})
// Bold (process before italic to avoid conflicts)
.replace(/\*([^*\n]+)\*/g, '**$1**')
// Italic
.replace(/_([^_\n]+)_/g, '*$1*')
// Monospaced text
.replace(/\{\{([^}]+)\}\}/g, '`$1`')
// Inserts
.replace(/\+([^+]*)\+/g, '<ins>$1</ins>')
// Superscript
.replace(/\^([^^]*)\^/g, '<sup>$1</sup>')
// Subscript
.replace(/~([^~]*)~/g, '<sub>$1</sub>')
// Strikethrough
.replace(/(\s+)-(\S+.*?\S)-(\s+)/g, '$1~~$2~~$3')
// Code Block
.replace(
/\{code(:([a-z]+))?([:|]?(title|borderStyle|borderColor|borderWidth|bgColor|titleBGColor)=.+?)*\}([^]*?)\n?\{code\}/gm,
'```$2$5\n```'
)
// Pre-formatted text
.replace(/{noformat}/g, '```')
// Un-named Links
.replace(/\[([^|]+?)\]/g, '<$1>')
// Images
.replace(/!(.+)!/g, '![]($1)')
// Named Links
.replace(/\[(.+?)\|(.+?)\]/g, '[$1]($2)')
// Single Paragraph Blockquote
.replace(/^bq\.\s+/gm, '> ')
// Remove color: unsupported in md
.replace(/\{color:[^}]+\}([^]*?)\{color\}/gm, '$1')
// panel into table
.replace(/\{panel:title=([^}]*)\}\n?([^]*?)\n?\{panel\}/gm, '\n| $1 |\n| --- |\n| $2 |')
// table header
.replace(/^[ \t]*((?:\|\|.*?)+\|\|)[ \t]*$/gm, (match: string, headers: string) => {
const singleBarred = headers.replace(/\|\|/g, '|');
return `${singleBarred}\n${singleBarred.replace(/\|[^|]+/g, '| --- ')}`;
})
// remove leading-space of table headers and rows
.replace(/^[ \t]*\|/gm, '|')
);
} catch (e) {
new Notice(`Error converting Jira markup to Markdown\n${e}`);
console.error(e);
return typeof str === "string" ? str : str.toString();
}
else if (typeof str === "object") {
str = JSON.stringify(str)
}
return (
str
// Un-Ordered Lists
.replace(/^[ \t]*(\*+)\s+/gm, (match: string, stars: string) => {
return `${Array(stars.length).fill('').join('')}* `;
})
// Ordered lists
.replace(/^[ \t]*(#+)\s+/gm, (match: string, nums: string) => {
return `${Array(nums.length).fill('').join('')}1. `;
})
// Headers 1-6
.replace(/^h([0-6])\.(.*)$/gm, (match: string, level: string, content: string) => {
return Array(parseInt(level, 10) + 1).join('#') + ' ' + content.trim();
})
// Bold (process before italic to avoid conflicts)
.replace(/\*([^*\n]+)\*/g, '**$1**')
// Italic
.replace(/_([^_\n]+)_/g, '*$1*')
// Monospaced text
.replace(/\{\{([^}]+)\}\}/g, '`$1`')
// Inserts
.replace(/\+([^+]*)\+/g, '<ins>$1</ins>')
// Superscript
.replace(/\^([^^]*)\^/g, '<sup>$1</sup>')
// Subscript
.replace(/~([^~]*)~/g, '<sub>$1</sub>')
// Strikethrough
.replace(/(\s+)-(\S+.*?\S)-(\s+)/g, '$1~~$2~~$3')
// Code Block
.replace(
/\{code(:([a-z]+))?([:|]?(title|borderStyle|borderColor|borderWidth|bgColor|titleBGColor)=.+?)*\}([^]*?)\n?\{code\}/gm,
'```$2$5\n```'
)
// Pre-formatted text
.replace(/{noformat}/g, '```')
// Un-named Links
.replace(/\[([^|]+?)\]/g, '<$1>')
// Images
.replace(/!(.+)!/g, '![]($1)')
// Named Links
.replace(/\[(.+?)\|(.+?)\]/g, '[$1]($2)')
// Single Paragraph Blockquote
.replace(/^bq\.\s+/gm, '> ')
// Remove color: unsupported in md
.replace(/\{color:[^}]+\}([^]*?)\{color\}/gm, '$1')
// panel into table
.replace(/\{panel:title=([^}]*)\}\n?([^]*?)\n?\{panel\}/gm, '\n| $1 |\n| --- |\n| $2 |')
// table header
.replace(/^[ \t]*((?:\|\|.*?)+\|\|)[ \t]*$/gm, (match: string, headers: string) => {
const singleBarred = headers.replace(/\|\|/g, '|');
return `${singleBarred}\n${singleBarred.replace(/\|[^|]+/g, '| --- ')}`;
})
// remove leading-space of table headers and rows
.replace(/^[ \t]*\|/gm, '|')
);
}
/**

View file

@ -13,25 +13,34 @@
margin-bottom: 8px;
padding: 8px;
border: 1px solid var(--background-modifier-border);
border-radius: 4px;
align-items: center;
}
.work-description-container textarea {
width: 100%;
}
.field-name-container {
background-color: var(--background-primary);
}
.field-mapping-label {
margin-right: 4px;
font-weight: 500;
}
.field-name-input, .to-jira-input, .from-jira-input {
width: 100%;
padding: 4px 8px;
border-radius: 4px;
border: 1px solid var(--background-modifier-border);
}
.field-mapping-item .invalid,
.setting-item.invalid input {
background-color: rgba(var(--color-red-rgb), 0.2);
}
.remove-field-btn {
padding: 4px 8px;
border-radius: 4px;
background-color: var(--background-modifier-error);
color: var(--text-on-accent);
cursor: pointer;

787
yarn.lock
View file

@ -2,131 +2,88 @@
# 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.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz#c8e119a30a7c8d60b9d2e22d2073722dde3b710b"
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==
"@mixmark-io/domino@^2.2.0":
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==
"@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 +92,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==
@ -177,6 +134,11 @@
dependencies:
"@types/estree" "*"
"@types/turndown@^5.0.5":
version "5.0.5"
resolved "https://registry.npmjs.org/@types/turndown/-/turndown-5.0.5.tgz"
integrity sha512-TL2IgGgc7B5j78rIccBtlYAnkuv8nUQqhQc+DSYV5j9Be9XOcm/SKOVRuA47xAVI3680Tk9B1d8flK2GWT2+4w==
"@typescript-eslint/eslint-plugin@5.29.0":
version "5.29.0"
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.29.0.tgz"
@ -192,7 +154,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,11 +219,66 @@
"@typescript-eslint/types" "5.29.0"
eslint-visitor-keys "^3.3.0"
"@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"
@ -274,13 +291,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"
@ -288,9 +349,16 @@ 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.yarnpkg.com/esbuild/-/esbuild-0.25.0.tgz#0de1787a77206c5a79eeb634a623d39b5006ce92"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz"
integrity sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==
optionalDependencies:
"@esbuild/aix-ppc64" "0.25.0"
@ -319,6 +387,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"
@ -327,6 +400,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"
@ -344,6 +425,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"
@ -356,11 +507,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"
@ -372,6 +538,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"
@ -379,6 +555,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"
@ -386,6 +569,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"
@ -398,6 +608,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"
@ -410,17 +646,53 @@ 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==
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==
@ -432,6 +704,65 @@ 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==
merge2@^1.3.0, merge2@^1.4.1:
version "1.4.1"
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
@ -445,6 +776,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"
@ -455,14 +793,74 @@ 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.7.2"
resolved "https://registry.npmjs.org/obsidian/-/obsidian-1.7.2.tgz"
integrity sha512-k9hN9brdknJC+afKr5FQzDRuEFGDKbDjfCazJwpgibwCAoZNYHYV8p/s3mM8I6AsnKrPKNXf8xGuMZ4enWelZQ==
version "1.8.7"
resolved "https://registry.npmjs.org/obsidian/-/obsidian-1.8.7.tgz"
integrity sha512-h4bWwNFAGRXlMlMAzdEiIM2ppTGlrh7uGOJS6w4gClrsjc+ei/3YAtU2VdFUlCiPuTHpY4aBpFJJW75S1Tl/JA==
dependencies:
"@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"
@ -473,6 +871,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"
@ -483,11 +891,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"
@ -500,11 +920,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"
@ -512,16 +973,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"
@ -529,7 +990,65 @@ tsutils@^3.21.0:
dependencies:
tslib "^1.8.1"
typescript@4.7.4:
turndown@^7.2.0:
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"
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==