commit 731850d7ec174248d4cb20894db61c29cd0e289e Author: Serhii Karavashkin Date: Mon Apr 20 20:14:16 2026 +0300 initial release v1.0.0 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3bdd52e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +dist/ +.DS_Store diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..66d43fa --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Kharizma & Latreia + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d8bd972 --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +# Alchemist for Obsidian + +Alchemist is a modular super-plugin designed for seamless data transmutation and vault hygiene. It consolidates multiple powerful features into a single, high-performance toolkit for Obsidian power users. + +## Features + +### TextBundle Export/Import +Preserve the sovereignty of your data. Export your notes with all linked assets (images, audio, PDFs) into a standardized .textbundle or .textpack format. Perfect for sharing notes with other apps or creating portable backups. +- Recursion Depth: Include linked notes up to 5 levels deep. +- Conflict Resolution: Smart hashing to detect identical files and avoid duplicates. +- TextPack Support: Compressed multi-note archives. + +### Audio Converter (Desktop Only) +Transform your voice recordings into high-quality MP3s or FLACs without leaving Obsidian. +- Meta-Sync: Automatically extracts ID3 tags (Title, Artist, Date, Genre) from the note's YAML frontmatter. +- Cleanup: Option to delete the original heavy .webm files after successful conversion. +- FFmpeg Powered: Uses the industry-standard FFmpeg engine for crystal-clear quality. + +### Dataview Table Export +Turn your dynamic Dataview queries into static, shareable CSV files with a single click. +- One-Click Export: Adds a subtle CSV button to every Dataview table. +- Silent Save: Configure a target folder in your Vault for distraction-free exporting. +- Traceability: Injects source note information and export timestamps into the CSV. + +### Smart Paste Hygiene +Keep your Vault clean from the "digital footprint" of the web. +- UTM Stripping: Automatically removes tracking parameters from pasted URLs. +- Pure Interception: Surgical cleaning that doesn't break Obsidian's native formatting or code blocks. +- Manual Cleanup: A dedicated command to clean an entire document from trackers in one go. + +--- + +## Installation + +1. Install via Community Plugins in Obsidian (Search for "Alchemist"). +2. For Audio Converter: Ensure ffmpeg is installed on your system and available in your PATH. +3. Enable the modules you need in the Alchemist settings tab. + +--- + +## Support & Sponsorship + +Alchemist is a labor of love, dedicated to the pursuit of digital purity and knowledge sovereignty. If it helps you in your workflow, consider supporting its continued evolution: + +- [Buy me a coffee (Ko-fi)](https://ko-fi.com/kharizma) +- [Support on Boosty](https://boosty.to/kharizma) + +--- + +## License + +This project is licensed under the MIT License. diff --git a/dist/main.js b/dist/main.js new file mode 100644 index 0000000..cc18daf --- /dev/null +++ b/dist/main.js @@ -0,0 +1,2349 @@ +/* +THIS IS A GENERATED/BUNDLED FILE BY ESBUILD +if you want to view the source, please visit the github repository of this plugin +*/ + +"use strict"; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// main.ts +var main_exports = {}; +__export(main_exports, { + default: () => AlchemistPlugin +}); +module.exports = __toCommonJS(main_exports); +var import_obsidian9 = require("obsidian"); + +// settings.ts +var import_obsidian = require("obsidian"); +var DEFAULT_SETTINGS = { + enableTextBundle: true, + enableAudioConverter: true, + enableDataviewExport: true, + enableSmartPaste: true, + lastDialogPath: "", + defaultImportPath: "", + includeImages: true, + includeAudio: true, + includeVideo: true, + includePDF: true, + recursionDepth: 0, + compressionFormat: "zip", + conflictStrategy: "rename", + restoreFolderStructure: true, + targetFolderStrategy: "source", + specificTargetFolder: "", + deleteOriginalWebM: false, + defaultAudioOutputFormat: "mp3", + defaultAudioArtist: "Alchemist", + defaultAudioAlbum: "Obsidian Vault", + defaultAudioGenre: "Voice Note", + dataviewExportStrategy: "dialog", + dataviewVaultPath: "Exports", + stripTrackingParameters: true, + cleanMsoHtml: true +}; +var AlchemistSettingTab = class extends import_obsidian.PluginSettingTab { + constructor(app, plugin) { + super(app, plugin); + this.plugin = plugin; + } + display() { + const { containerEl } = this; + containerEl.empty(); + containerEl.createEl("h2", { text: "Alchemist: Central Command" }); + containerEl.createEl("h3", { text: "Core Modules" }); + new import_obsidian.Setting(containerEl).setName("Enable TextBundle").setDesc("Export/Import notes as TextBundle.").addToggle((toggle) => toggle.setValue(this.plugin.settings.enableTextBundle).onChange(async (value) => { + this.plugin.settings.enableTextBundle = value; + await this.plugin.saveSettings(); + this.display(); + })); + new import_obsidian.Setting(containerEl).setName("Enable Audio Converter").setDesc("Convert WebM recordings to MP3/WAV/OGG (Desktop).").addToggle((toggle) => toggle.setValue(this.plugin.settings.enableAudioConverter).onChange(async (value) => { + this.plugin.settings.enableAudioConverter = value; + await this.plugin.saveSettings(); + this.display(); + })); + new import_obsidian.Setting(containerEl).setName("Enable Dataview Export").setDesc("Add CSV export button to Dataview tables.").addToggle((toggle) => toggle.setValue(this.plugin.settings.enableDataviewExport).onChange(async (value) => { + this.plugin.settings.enableDataviewExport = value; + await this.plugin.saveSettings(); + this.display(); + })); + new import_obsidian.Setting(containerEl).setName("Enable Smart Paste").setDesc("Clean clipboard content from trackers and junk HTML.").addToggle((toggle) => toggle.setValue(this.plugin.settings.enableSmartPaste).onChange(async (value) => { + this.plugin.settings.enableSmartPaste = value; + await this.plugin.saveSettings(); + this.display(); + })); + if (this.plugin.settings.enableTextBundle) { + containerEl.createEl("h3", { text: "TextBundle Strategy" }); + new import_obsidian.Setting(containerEl).setName("Default Import Path").setDesc("Folder where TextBundles will be unpacked by default.").addText((text) => text.setPlaceholder("e.g. Imports/TextBundle").setValue(this.plugin.settings.defaultImportPath).onChange(async (value) => { + this.plugin.settings.defaultImportPath = value; + await this.plugin.saveSettings(); + })); + new import_obsidian.Setting(containerEl).setName("Include Images").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeImages).onChange(async (value) => { + this.plugin.settings.includeImages = value; + await this.plugin.saveSettings(); + })); + new import_obsidian.Setting(containerEl).setName("Include Audio").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeAudio).onChange(async (value) => { + this.plugin.settings.includeAudio = value; + await this.plugin.saveSettings(); + })); + new import_obsidian.Setting(containerEl).setName("Include Video").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeVideo).onChange(async (value) => { + this.plugin.settings.includeVideo = value; + await this.plugin.saveSettings(); + })); + new import_obsidian.Setting(containerEl).setName("Include PDFs").addToggle((toggle) => toggle.setValue(this.plugin.settings.includePDF).onChange(async (value) => { + this.plugin.settings.includePDF = value; + await this.plugin.saveSettings(); + })); + new import_obsidian.Setting(containerEl).setName("Recursion Depth").setDesc("How many levels of linked notes to include (0 = current note only).").addSlider((slider) => slider.setLimits(0, 5, 1).setValue(this.plugin.settings.recursionDepth).setDynamicTooltip().onChange(async (value) => { + this.plugin.settings.recursionDepth = value; + await this.plugin.saveSettings(); + })); + new import_obsidian.Setting(containerEl).setName("Compression Format").setDesc("Target file extension for exports.").addDropdown((dropdown) => dropdown.addOption("zip", ".zip (Standard)").addOption("textbundle", ".textbundle").addOption("textpack", ".textpack").setValue(this.plugin.settings.compressionFormat).onChange(async (value) => { + this.plugin.settings.compressionFormat = value; + await this.plugin.saveSettings(); + })); + new import_obsidian.Setting(containerEl).setName("Conflict Strategy").setDesc("What to do if a file with the same name already exists during import.").addDropdown((dropdown) => dropdown.addOption("rename", "Auto-rename (Versioning)").addOption("skip", "Skip Existing").addOption("overwrite", "Overwrite (CAUTION)").setValue(this.plugin.settings.conflictStrategy).onChange(async (value) => { + this.plugin.settings.conflictStrategy = value; + await this.plugin.saveSettings(); + })); + new import_obsidian.Setting(containerEl).setName("Restore Folder Structure").setDesc("Try to recreate the original vault path using metadata.").addToggle((toggle) => toggle.setValue(this.plugin.settings.restoreFolderStructure).onChange(async (value) => { + this.plugin.settings.restoreFolderStructure = value; + await this.plugin.saveSettings(); + })); + } + if (this.plugin.settings.enableAudioConverter) { + containerEl.createEl("h3", { text: "Audio Transformation" }); + new import_obsidian.Setting(containerEl).setName("Target Folder Strategy").setDesc("Where to save converted files.").addDropdown((dropdown) => dropdown.addOption("source", "Same as source").addOption("specific", "Specific folder").addOption("dialog", "Always ask with dialog").setValue(this.plugin.settings.targetFolderStrategy).onChange(async (value) => { + this.plugin.settings.targetFolderStrategy = value; + await this.plugin.saveSettings(); + this.display(); + })); + if (this.plugin.settings.targetFolderStrategy === "specific") { + new import_obsidian.Setting(containerEl).setName("Specific Target Folder").addText((text) => text.setValue(this.plugin.settings.specificTargetFolder).onChange(async (value) => { + this.plugin.settings.specificTargetFolder = value; + await this.plugin.saveSettings(); + })); + } + new import_obsidian.Setting(containerEl).setName("Default Output Format").setDesc("Target format for audio conversion.").addDropdown((dropdown) => dropdown.addOption("mp3", "MP3").addOption("wav", "WAV").addOption("ogg", "OGG").addOption("m4a", "M4A").addOption("flac", "FLAC").setValue(this.plugin.settings.defaultAudioOutputFormat).onChange(async (value) => { + this.plugin.settings.defaultAudioOutputFormat = value; + await this.plugin.saveSettings(); + this.display(); + })); + new import_obsidian.Setting(containerEl).setName("Delete original WebM").setDesc("Remove the original file after successful conversion.").addToggle((toggle) => toggle.setValue(this.plugin.settings.deleteOriginalWebM).onChange(async (value) => { + this.plugin.settings.deleteOriginalWebM = value; + await this.plugin.saveSettings(); + })); + containerEl.createEl("h4", { text: "Default Metadata" }); + new import_obsidian.Setting(containerEl).setName("Default Artist").addText((text) => text.setValue(this.plugin.settings.defaultAudioArtist).onChange(async (value) => { + this.plugin.settings.defaultAudioArtist = value; + await this.plugin.saveSettings(); + })); + new import_obsidian.Setting(containerEl).setName("Default Album").addText((text) => text.setValue(this.plugin.settings.defaultAudioAlbum).onChange(async (value) => { + this.plugin.settings.defaultAudioAlbum = value; + await this.plugin.saveSettings(); + })); + new import_obsidian.Setting(containerEl).setName("Default Genre").addText((text) => text.setValue(this.plugin.settings.defaultAudioGenre).onChange(async (value) => { + this.plugin.settings.defaultAudioGenre = value; + await this.plugin.saveSettings(); + })); + } + if (this.plugin.settings.enableDataviewExport) { + containerEl.createEl("h3", { text: "Dataview Export" }); + new import_obsidian.Setting(containerEl).setName("Export Strategy").setDesc("How to handle CSV generation.").addDropdown((dropdown) => dropdown.addOption("dialog", "System Save Dialog").addOption("vault", "Silent Save to Vault").setValue(this.plugin.settings.dataviewExportStrategy).onChange(async (value) => { + this.plugin.settings.dataviewExportStrategy = value; + await this.plugin.saveSettings(); + this.display(); + })); + if (this.plugin.settings.dataviewExportStrategy === "vault") { + new import_obsidian.Setting(containerEl).setName("Vault Target Folder").setDesc("Folder where Dataview CSVs will be saved.").addText((text) => text.setPlaceholder("Exports").setValue(this.plugin.settings.dataviewVaultPath).onChange(async (value) => { + this.plugin.settings.dataviewVaultPath = value; + await this.plugin.saveSettings(); + })); + } + } + if (this.plugin.settings.enableSmartPaste) { + containerEl.createEl("h3", { text: "Hygiene & Sanitization (Paste)" }); + new import_obsidian.Setting(containerEl).setName("Strip Marketing Trackers").setDesc("Remove UTM, fbclid, and other trackers from pasted URLs.").addToggle((toggle) => toggle.setValue(this.plugin.settings.stripTrackingParameters).onChange(async (value) => { + this.plugin.settings.stripTrackingParameters = value; + await this.plugin.saveSettings(); + })); + new import_obsidian.Setting(containerEl).setName("Clean HTML Artifacts").setDesc("Remove proprietary meta-tags from Google Docs/MS Office pastes.").addToggle((toggle) => toggle.setValue(this.plugin.settings.cleanMsoHtml).onChange(async (value) => { + this.plugin.settings.cleanMsoHtml = value; + await this.plugin.saveSettings(); + })); + } + containerEl.createEl("hr"); + const supportDiv = containerEl.createDiv({ cls: "alchemist-support-container" }); + supportDiv.style.textAlign = "center"; + supportDiv.style.padding = "20px"; + supportDiv.createEl("h3", { text: "Support the Alchemist" }); + supportDiv.createEl("p", { text: "If you find this tool useful, consider supporting its development." }); + const buttonsDiv = supportDiv.createDiv(); + buttonsDiv.style.display = "flex"; + buttonsDiv.style.justifyContent = "center"; + buttonsDiv.style.gap = "15px"; + const kofiBtn = buttonsDiv.createEl("a", { + href: "https://ko-fi.com/kharizma", + cls: "alchemist-donate-btn" + }); + kofiBtn.innerText = "Buy me a coffee"; + kofiBtn.style.cssText = "background: #29abe0; color: white; padding: 8px 15px; border-radius: 5px; text-decoration: none; font-weight: bold;"; + const boostyBtn = buttonsDiv.createEl("a", { + href: "https://boosty.to/kharizma", + cls: "alchemist-donate-btn" + }); + boostyBtn.innerText = "Support on Boosty"; + boostyBtn.style.cssText = "background: #f15f2c; color: white; padding: 8px 15px; border-radius: 5px; text-decoration: none; font-weight: bold;"; + } +}; + +// src/core/SystemAdapter.ts +var ElectronSystemAdapter = class { + constructor() { + const electron = window.require("electron"); + let remote; + try { + remote = window.require("@electron/remote"); + } catch (e) { + remote = electron.remote; + } + this.dialog = remote ? remote.dialog : electron.dialog; + this.fs = window.require("fs"); + this.path = window.require("path"); + this.os = window.require("os"); + } + async showSaveDialog(options) { + return await this.dialog.showSaveDialog(options); + } + async showOpenDialog(options) { + return await this.dialog.showOpenDialog(options); + } +}; + +// src/features/textbundle/TextBundleModule.ts +var import_obsidian5 = require("obsidian"); + +// src/features/textbundle/collector.ts +var import_obsidian2 = require("obsidian"); +var TextBundleFeature = class { + constructor(app, settings) { + this.app = app; + this.settings = settings; + } + /** + * Collects all files (note itself + assets + linked notes) for TextBundle export. + */ + async collectResources(startFile) { + const context = { + visitedFiles: /* @__PURE__ */ new Set(), + assetMap: /* @__PURE__ */ new Map(), + assets: /* @__PURE__ */ new Map(), + notes: [] + }; + await this.traverse(startFile, context, 0); + return context; + } + async traverse(file, context, depth) { + if (context.visitedFiles.has(file.path)) return; + context.visitedFiles.add(file.path); + if (file.extension === "md") { + context.notes.push(file); + const cache = this.app.metadataCache.getFileCache(file); + if (!cache) return; + if (cache.embeds) { + for (const embed of cache.embeds) { + const assetFile = this.app.metadataCache.getFirstLinkpathDest(embed.link, file.path); + if (assetFile instanceof import_obsidian2.TFile && this.shouldIncludeAsset(assetFile)) { + this.addAssetToContext(assetFile, context); + } + } + } + if (depth < this.settings.recursionDepth && cache.links) { + for (const link of cache.links) { + const linkedFile = this.app.metadataCache.getFirstLinkpathDest(link.link, file.path); + if (linkedFile instanceof import_obsidian2.TFile && linkedFile.extension === "md") { + await this.traverse(linkedFile, context, depth + 1); + } + } + } + } else { + if (this.shouldIncludeAsset(file)) { + this.addAssetToContext(file, context); + } + } + } + addAssetToContext(file, context) { + if (context.assetMap.has(file.path)) return; + let bundleName = file.name; + let counter = 1; + const nameParts = file.name.split("."); + const ext = nameParts.pop(); + const base = nameParts.join("."); + while (context.assets.has(bundleName)) { + bundleName = `${base}_${counter}.${ext}`; + counter++; + } + context.assetMap.set(file.path, bundleName); + context.assets.set(bundleName, file); + } + shouldIncludeAsset(file) { + const ext = file.extension.toLowerCase(); + if (ext === "md" || ext === "markdown") return false; + const imageExtensions = ["jpg", "jpeg", "png", "gif", "svg", "webp", "bmp", "tiff"]; + const audioExtensions = ["mp3", "wav", "ogg", "m4a", "flac", "webm", "opus"]; + const videoExtensions = ["mp4", "webm", "mkv", "avi", "mov"]; + const pdfExtensions = ["pdf"]; + if (imageExtensions.includes(ext)) return this.settings.includeImages; + if (audioExtensions.includes(ext)) return this.settings.includeAudio; + if (videoExtensions.includes(ext)) return this.settings.includeVideo; + if (pdfExtensions.includes(ext)) return this.settings.includePDF; + return true; + } +}; + +// src/features/textbundle/packer.ts +var import_obsidian3 = require("obsidian"); + +// node_modules/fflate/esm/browser.js +var ch2 = {}; +var wk = (function(c, id, msg, transfer, cb) { + var w = new Worker(ch2[id] || (ch2[id] = URL.createObjectURL(new Blob([ + c + ';addEventListener("error",function(e){e=e.error;postMessage({$e$:[e.message,e.code,e.stack]})})' + ], { type: "text/javascript" })))); + w.onmessage = function(e) { + var d = e.data, ed = d.$e$; + if (ed) { + var err2 = new Error(ed[0]); + err2["code"] = ed[1]; + err2.stack = ed[2]; + cb(err2, null); + } else + cb(null, d); + }; + w.postMessage(msg, transfer); + return w; +}); +var u8 = Uint8Array; +var u16 = Uint16Array; +var u32 = Uint32Array; +var fleb = new u8([ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5, + 0, + /* unused */ + 0, + 0, + /* impossible */ + 0 +]); +var fdeb = new u8([ + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 5, + 5, + 6, + 6, + 7, + 7, + 8, + 8, + 9, + 9, + 10, + 10, + 11, + 11, + 12, + 12, + 13, + 13, + /* unused */ + 0, + 0 +]); +var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); +var freb = function(eb, start) { + var b = new u16(31); + for (var i = 0; i < 31; ++i) { + b[i] = start += 1 << eb[i - 1]; + } + var r = new u32(b[30]); + for (var i = 1; i < 30; ++i) { + for (var j = b[i]; j < b[i + 1]; ++j) { + r[j] = j - b[i] << 5 | i; + } + } + return [b, r]; +}; +var _a = freb(fleb, 2); +var fl = _a[0]; +var revfl = _a[1]; +fl[28] = 258, revfl[258] = 28; +var _b = freb(fdeb, 0); +var fd = _b[0]; +var revfd = _b[1]; +var rev = new u16(32768); +for (i = 0; i < 32768; ++i) { + x = (i & 43690) >>> 1 | (i & 21845) << 1; + x = (x & 52428) >>> 2 | (x & 13107) << 2; + x = (x & 61680) >>> 4 | (x & 3855) << 4; + rev[i] = ((x & 65280) >>> 8 | (x & 255) << 8) >>> 1; +} +var x; +var i; +var hMap = (function(cd, mb, r) { + var s = cd.length; + var i = 0; + var l = new u16(mb); + for (; i < s; ++i) { + if (cd[i]) + ++l[cd[i] - 1]; + } + var le = new u16(mb); + for (i = 0; i < mb; ++i) { + le[i] = le[i - 1] + l[i - 1] << 1; + } + var co; + if (r) { + co = new u16(1 << mb); + var rvb = 15 - mb; + for (i = 0; i < s; ++i) { + if (cd[i]) { + var sv = i << 4 | cd[i]; + var r_1 = mb - cd[i]; + var v = le[cd[i] - 1]++ << r_1; + for (var m = v | (1 << r_1) - 1; v <= m; ++v) { + co[rev[v] >>> rvb] = sv; + } + } + } + } else { + co = new u16(s); + for (i = 0; i < s; ++i) { + if (cd[i]) { + co[i] = rev[le[cd[i] - 1]++] >>> 15 - cd[i]; + } + } + } + return co; +}); +var flt = new u8(288); +for (i = 0; i < 144; ++i) + flt[i] = 8; +var i; +for (i = 144; i < 256; ++i) + flt[i] = 9; +var i; +for (i = 256; i < 280; ++i) + flt[i] = 7; +var i; +for (i = 280; i < 288; ++i) + flt[i] = 8; +var i; +var fdt = new u8(32); +for (i = 0; i < 32; ++i) + fdt[i] = 5; +var i; +var flm = /* @__PURE__ */ hMap(flt, 9, 0); +var flrm = /* @__PURE__ */ hMap(flt, 9, 1); +var fdm = /* @__PURE__ */ hMap(fdt, 5, 0); +var fdrm = /* @__PURE__ */ hMap(fdt, 5, 1); +var max = function(a) { + var m = a[0]; + for (var i = 1; i < a.length; ++i) { + if (a[i] > m) + m = a[i]; + } + return m; +}; +var bits = function(d, p, m) { + var o = p / 8 | 0; + return (d[o] | d[o + 1] << 8) >> (p & 7) & m; +}; +var bits16 = function(d, p) { + var o = p / 8 | 0; + return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7); +}; +var shft = function(p) { + return (p + 7) / 8 | 0; +}; +var slc = function(v, s, e) { + if (s == null || s < 0) + s = 0; + if (e == null || e > v.length) + e = v.length; + var n = new (v.BYTES_PER_ELEMENT == 2 ? u16 : v.BYTES_PER_ELEMENT == 4 ? u32 : u8)(e - s); + n.set(v.subarray(s, e)); + return n; +}; +var ec = [ + "unexpected EOF", + "invalid block type", + "invalid length/literal", + "invalid distance", + "stream finished", + "no stream handler", + , + "no callback", + "invalid UTF-8 data", + "extra field too long", + "date not in range 1980-2099", + "filename too long", + "stream finishing", + "invalid zip data" + // determined by unknown compression method +]; +var err = function(ind, msg, nt) { + var e = new Error(msg || ec[ind]); + e.code = ind; + if (Error.captureStackTrace) + Error.captureStackTrace(e, err); + if (!nt) + throw e; + return e; +}; +var inflt = function(dat, buf, st) { + var sl = dat.length; + if (!sl || st && st.f && !st.l) + return buf || new u8(0); + var noBuf = !buf || st; + var noSt = !st || st.i; + if (!st) + st = {}; + if (!buf) + buf = new u8(sl * 3); + var cbuf = function(l2) { + var bl = buf.length; + if (l2 > bl) { + var nbuf = new u8(Math.max(bl * 2, l2)); + nbuf.set(buf); + buf = nbuf; + } + }; + var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n; + var tbts = sl * 8; + do { + if (!lm) { + final = bits(dat, pos, 1); + var type = bits(dat, pos + 1, 3); + pos += 3; + if (!type) { + var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l; + if (t > sl) { + if (noSt) + err(0); + break; + } + if (noBuf) + cbuf(bt + l); + buf.set(dat.subarray(s, t), bt); + st.b = bt += l, st.p = pos = t * 8, st.f = final; + continue; + } else if (type == 1) + lm = flrm, dm = fdrm, lbt = 9, dbt = 5; + else if (type == 2) { + var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4; + var tl = hLit + bits(dat, pos + 5, 31) + 1; + pos += 14; + var ldt = new u8(tl); + var clt = new u8(19); + for (var i = 0; i < hcLen; ++i) { + clt[clim[i]] = bits(dat, pos + i * 3, 7); + } + pos += hcLen * 3; + var clb = max(clt), clbmsk = (1 << clb) - 1; + var clm = hMap(clt, clb, 1); + for (var i = 0; i < tl; ) { + var r = clm[bits(dat, pos, clbmsk)]; + pos += r & 15; + var s = r >>> 4; + if (s < 16) { + ldt[i++] = s; + } else { + var c = 0, n = 0; + if (s == 16) + n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1]; + else if (s == 17) + n = 3 + bits(dat, pos, 7), pos += 3; + else if (s == 18) + n = 11 + bits(dat, pos, 127), pos += 7; + while (n--) + ldt[i++] = c; + } + } + var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit); + lbt = max(lt); + dbt = max(dt); + lm = hMap(lt, lbt, 1); + dm = hMap(dt, dbt, 1); + } else + err(1); + if (pos > tbts) { + if (noSt) + err(0); + break; + } + } + if (noBuf) + cbuf(bt + 131072); + var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1; + var lpos = pos; + for (; ; lpos = pos) { + var c = lm[bits16(dat, pos) & lms], sym = c >>> 4; + pos += c & 15; + if (pos > tbts) { + if (noSt) + err(0); + break; + } + if (!c) + err(2); + if (sym < 256) + buf[bt++] = sym; + else if (sym == 256) { + lpos = pos, lm = null; + break; + } else { + var add = sym - 254; + if (sym > 264) { + var i = sym - 257, b = fleb[i]; + add = bits(dat, pos, (1 << b) - 1) + fl[i]; + pos += b; + } + var d = dm[bits16(dat, pos) & dms], dsym = d >>> 4; + if (!d) + err(3); + pos += d & 15; + var dt = fd[dsym]; + if (dsym > 3) { + var b = fdeb[dsym]; + dt += bits16(dat, pos) & (1 << b) - 1, pos += b; + } + if (pos > tbts) { + if (noSt) + err(0); + break; + } + if (noBuf) + cbuf(bt + 131072); + var end = bt + add; + for (; bt < end; bt += 4) { + buf[bt] = buf[bt - dt]; + buf[bt + 1] = buf[bt + 1 - dt]; + buf[bt + 2] = buf[bt + 2 - dt]; + buf[bt + 3] = buf[bt + 3 - dt]; + } + bt = end; + } + } + st.l = lm, st.p = lpos, st.b = bt, st.f = final; + if (lm) + final = 1, st.m = lbt, st.d = dm, st.n = dbt; + } while (!final); + return bt == buf.length ? buf : slc(buf, 0, bt); +}; +var wbits = function(d, p, v) { + v <<= p & 7; + var o = p / 8 | 0; + d[o] |= v; + d[o + 1] |= v >>> 8; +}; +var wbits16 = function(d, p, v) { + v <<= p & 7; + var o = p / 8 | 0; + d[o] |= v; + d[o + 1] |= v >>> 8; + d[o + 2] |= v >>> 16; +}; +var hTree = function(d, mb) { + var t = []; + for (var i = 0; i < d.length; ++i) { + if (d[i]) + t.push({ s: i, f: d[i] }); + } + var s = t.length; + var t2 = t.slice(); + if (!s) + return [et, 0]; + if (s == 1) { + var v = new u8(t[0].s + 1); + v[t[0].s] = 1; + return [v, 1]; + } + t.sort(function(a, b) { + return a.f - b.f; + }); + t.push({ s: -1, f: 25001 }); + var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2; + t[0] = { s: -1, f: l.f + r.f, l, r }; + while (i1 != s - 1) { + l = t[t[i0].f < t[i2].f ? i0++ : i2++]; + r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++]; + t[i1++] = { s: -1, f: l.f + r.f, l, r }; + } + var maxSym = t2[0].s; + for (var i = 1; i < s; ++i) { + if (t2[i].s > maxSym) + maxSym = t2[i].s; + } + var tr = new u16(maxSym + 1); + var mbt = ln(t[i1 - 1], tr, 0); + if (mbt > mb) { + var i = 0, dt = 0; + var lft = mbt - mb, cst = 1 << lft; + t2.sort(function(a, b) { + return tr[b.s] - tr[a.s] || a.f - b.f; + }); + for (; i < s; ++i) { + var i2_1 = t2[i].s; + if (tr[i2_1] > mb) { + dt += cst - (1 << mbt - tr[i2_1]); + tr[i2_1] = mb; + } else + break; + } + dt >>>= lft; + while (dt > 0) { + var i2_2 = t2[i].s; + if (tr[i2_2] < mb) + dt -= 1 << mb - tr[i2_2]++ - 1; + else + ++i; + } + for (; i >= 0 && dt; --i) { + var i2_3 = t2[i].s; + if (tr[i2_3] == mb) { + --tr[i2_3]; + ++dt; + } + } + mbt = mb; + } + return [new u8(tr), mbt]; +}; +var ln = function(n, l, d) { + return n.s == -1 ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) : l[n.s] = d; +}; +var lc = function(c) { + var s = c.length; + while (s && !c[--s]) + ; + var cl = new u16(++s); + var cli = 0, cln = c[0], cls = 1; + var w = function(v) { + cl[cli++] = v; + }; + for (var i = 1; i <= s; ++i) { + if (c[i] == cln && i != s) + ++cls; + else { + if (!cln && cls > 2) { + for (; cls > 138; cls -= 138) + w(32754); + if (cls > 2) { + w(cls > 10 ? cls - 11 << 5 | 28690 : cls - 3 << 5 | 12305); + cls = 0; + } + } else if (cls > 3) { + w(cln), --cls; + for (; cls > 6; cls -= 6) + w(8304); + if (cls > 2) + w(cls - 3 << 5 | 8208), cls = 0; + } + while (cls--) + w(cln); + cls = 1; + cln = c[i]; + } + } + return [cl.subarray(0, cli), s]; +}; +var clen = function(cf, cl) { + var l = 0; + for (var i = 0; i < cl.length; ++i) + l += cf[i] * cl[i]; + return l; +}; +var wfblk = function(out, pos, dat) { + var s = dat.length; + var o = shft(pos + 2); + out[o] = s & 255; + out[o + 1] = s >>> 8; + out[o + 2] = out[o] ^ 255; + out[o + 3] = out[o + 1] ^ 255; + for (var i = 0; i < s; ++i) + out[o + i + 4] = dat[i]; + return (o + 4 + s) * 8; +}; +var wblk = function(dat, out, final, syms, lf, df, eb, li, bs, bl, p) { + wbits(out, p++, final); + ++lf[256]; + var _a2 = hTree(lf, 15), dlt = _a2[0], mlb = _a2[1]; + var _b2 = hTree(df, 15), ddt = _b2[0], mdb = _b2[1]; + var _c = lc(dlt), lclt = _c[0], nlc = _c[1]; + var _d = lc(ddt), lcdt = _d[0], ndc = _d[1]; + var lcfreq = new u16(19); + for (var i = 0; i < lclt.length; ++i) + lcfreq[lclt[i] & 31]++; + for (var i = 0; i < lcdt.length; ++i) + lcfreq[lcdt[i] & 31]++; + var _e = hTree(lcfreq, 7), lct = _e[0], mlcb = _e[1]; + var nlcc = 19; + for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc) + ; + var flen = bl + 5 << 3; + var ftlen = clen(lf, flt) + clen(df, fdt) + eb; + var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + (2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18]); + if (flen <= ftlen && flen <= dtlen) + return wfblk(out, p, dat.subarray(bs, bs + bl)); + var lm, ll, dm, dl; + wbits(out, p, 1 + (dtlen < ftlen)), p += 2; + if (dtlen < ftlen) { + lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt; + var llm = hMap(lct, mlcb, 0); + wbits(out, p, nlc - 257); + wbits(out, p + 5, ndc - 1); + wbits(out, p + 10, nlcc - 4); + p += 14; + for (var i = 0; i < nlcc; ++i) + wbits(out, p + 3 * i, lct[clim[i]]); + p += 3 * nlcc; + var lcts = [lclt, lcdt]; + for (var it = 0; it < 2; ++it) { + var clct = lcts[it]; + for (var i = 0; i < clct.length; ++i) { + var len = clct[i] & 31; + wbits(out, p, llm[len]), p += lct[len]; + if (len > 15) + wbits(out, p, clct[i] >>> 5 & 127), p += clct[i] >>> 12; + } + } + } else { + lm = flm, ll = flt, dm = fdm, dl = fdt; + } + for (var i = 0; i < li; ++i) { + if (syms[i] > 255) { + var len = syms[i] >>> 18 & 31; + wbits16(out, p, lm[len + 257]), p += ll[len + 257]; + if (len > 7) + wbits(out, p, syms[i] >>> 23 & 31), p += fleb[len]; + var dst = syms[i] & 31; + wbits16(out, p, dm[dst]), p += dl[dst]; + if (dst > 3) + wbits16(out, p, syms[i] >>> 5 & 8191), p += fdeb[dst]; + } else { + wbits16(out, p, lm[syms[i]]), p += ll[syms[i]]; + } + } + wbits16(out, p, lm[256]); + return p + ll[256]; +}; +var deo = /* @__PURE__ */ new u32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]); +var et = /* @__PURE__ */ new u8(0); +var dflt = function(dat, lvl, plvl, pre, post, lst) { + var s = dat.length; + var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7e3)) + post); + var w = o.subarray(pre, o.length - post); + var pos = 0; + if (!lvl || s < 8) { + for (var i = 0; i <= s; i += 65535) { + var e = i + 65535; + if (e >= s) { + w[pos >> 3] = lst; + } + pos = wfblk(w, pos + 1, dat.subarray(i, e)); + } + } else { + var opt = deo[lvl - 1]; + var n = opt >>> 13, c = opt & 8191; + var msk_1 = (1 << plvl) - 1; + var prev = new u16(32768), head = new u16(msk_1 + 1); + var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1; + var hsh = function(i2) { + return (dat[i2] ^ dat[i2 + 1] << bs1_1 ^ dat[i2 + 2] << bs2_1) & msk_1; + }; + var syms = new u32(25e3); + var lf = new u16(288), df = new u16(32); + var lc_1 = 0, eb = 0, i = 0, li = 0, wi = 0, bs = 0; + for (; i < s; ++i) { + var hv = hsh(i); + var imod = i & 32767, pimod = head[hv]; + prev[imod] = pimod; + head[hv] = imod; + if (wi <= i) { + var rem = s - i; + if ((lc_1 > 7e3 || li > 24576) && rem > 423) { + pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos); + li = lc_1 = eb = 0, bs = i; + for (var j = 0; j < 286; ++j) + lf[j] = 0; + for (var j = 0; j < 30; ++j) + df[j] = 0; + } + var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767; + if (rem > 2 && hv == hsh(i - dif)) { + var maxn = Math.min(n, rem) - 1; + var maxd = Math.min(32767, i); + var ml = Math.min(258, rem); + while (dif <= maxd && --ch_1 && imod != pimod) { + if (dat[i + l] == dat[i + l - dif]) { + var nl = 0; + for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl) + ; + if (nl > l) { + l = nl, d = dif; + if (nl > maxn) + break; + var mmd = Math.min(dif, nl - 2); + var md = 0; + for (var j = 0; j < mmd; ++j) { + var ti = i - dif + j + 32768 & 32767; + var pti = prev[ti]; + var cd = ti - pti + 32768 & 32767; + if (cd > md) + md = cd, pimod = ti; + } + } + } + imod = pimod, pimod = prev[imod]; + dif += imod - pimod + 32768 & 32767; + } + } + if (d) { + syms[li++] = 268435456 | revfl[l] << 18 | revfd[d]; + var lin = revfl[l] & 31, din = revfd[d] & 31; + eb += fleb[lin] + fdeb[din]; + ++lf[257 + lin]; + ++df[din]; + wi = i + l; + ++lc_1; + } else { + syms[li++] = dat[i]; + ++lf[dat[i]]; + } + } + } + pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos); + if (!lst && pos & 7) + pos = wfblk(w, pos + 1, et); + } + return slc(o, 0, pre + shft(pos) + post); +}; +var crct = /* @__PURE__ */ (function() { + var t = new Int32Array(256); + for (var i = 0; i < 256; ++i) { + var c = i, k = 9; + while (--k) + c = (c & 1 && -306674912) ^ c >>> 1; + t[i] = c; + } + return t; +})(); +var crc = function() { + var c = -1; + return { + p: function(d) { + var cr = c; + for (var i = 0; i < d.length; ++i) + cr = crct[cr & 255 ^ d[i]] ^ cr >>> 8; + c = cr; + }, + d: function() { + return ~c; + } + }; +}; +var dopt = function(dat, opt, pre, post, st) { + return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 12 + opt.mem, pre, post, !st); +}; +var mrg = function(a, b) { + var o = {}; + for (var k in a) + o[k] = a[k]; + for (var k in b) + o[k] = b[k]; + return o; +}; +var wcln = function(fn, fnStr, td2) { + var dt = fn(); + var st = fn.toString(); + var ks = st.slice(st.indexOf("[") + 1, st.lastIndexOf("]")).replace(/\s+/g, "").split(","); + for (var i = 0; i < dt.length; ++i) { + var v = dt[i], k = ks[i]; + if (typeof v == "function") { + fnStr += ";" + k + "="; + var st_1 = v.toString(); + if (v.prototype) { + if (st_1.indexOf("[native code]") != -1) { + var spInd = st_1.indexOf(" ", 8) + 1; + fnStr += st_1.slice(spInd, st_1.indexOf("(", spInd)); + } else { + fnStr += st_1; + for (var t in v.prototype) + fnStr += ";" + k + ".prototype." + t + "=" + v.prototype[t].toString(); + } + } else + fnStr += st_1; + } else + td2[k] = v; + } + return [fnStr, td2]; +}; +var ch = []; +var cbfs = function(v) { + var tl = []; + for (var k in v) { + if (v[k].buffer) { + tl.push((v[k] = new v[k].constructor(v[k])).buffer); + } + } + return tl; +}; +var wrkr = function(fns, init, id, cb) { + var _a2; + if (!ch[id]) { + var fnStr = "", td_1 = {}, m = fns.length - 1; + for (var i = 0; i < m; ++i) + _a2 = wcln(fns[i], fnStr, td_1), fnStr = _a2[0], td_1 = _a2[1]; + ch[id] = wcln(fns[m], fnStr, td_1); + } + var td2 = mrg({}, ch[id][1]); + return wk(ch[id][0] + ";onmessage=function(e){for(var k in e.data)self[k]=e.data[k];onmessage=" + init.toString() + "}", id, td2, cbfs(td2), cb); +}; +var bDflt = function() { + return [u8, u16, u32, fleb, fdeb, clim, revfl, revfd, flm, flt, fdm, fdt, rev, deo, et, hMap, wbits, wbits16, hTree, ln, lc, clen, wfblk, wblk, shft, slc, dflt, dopt, deflateSync, pbf]; +}; +var pbf = function(msg) { + return postMessage(msg, [msg.buffer]); +}; +var cbify = function(dat, opts, fns, init, id, cb) { + var w = wrkr(fns, init, id, function(err2, dat2) { + w.terminate(); + cb(err2, dat2); + }); + w.postMessage([dat, opts], opts.consume ? [dat.buffer] : []); + return function() { + w.terminate(); + }; +}; +var b2 = function(d, b) { + return d[b] | d[b + 1] << 8; +}; +var b4 = function(d, b) { + return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0; +}; +var b8 = function(d, b) { + return b4(d, b) + b4(d, b + 4) * 4294967296; +}; +var wbytes = function(d, b, v) { + for (; v; ++b) + d[b] = v, v >>>= 8; +}; +function deflate(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != "function") + err(7); + return cbify(data, opts, [ + bDflt + ], function(ev) { + return pbf(deflateSync(ev.data[0], ev.data[1])); + }, 0, cb); +} +function deflateSync(data, opts) { + return dopt(data, opts || {}, 0, 0); +} +function inflateSync(data, out) { + return inflt(data, out); +} +var fltn = function(d, p, t, o) { + for (var k in d) { + var val = d[k], n = p + k, op = o; + if (Array.isArray(val)) + op = mrg(o, val[1]), val = val[0]; + if (val instanceof u8) + t[n] = [val, op]; + else { + t[n += "/"] = [new u8(0), op]; + fltn(val, n, t, o); + } + } +}; +var te = typeof TextEncoder != "undefined" && /* @__PURE__ */ new TextEncoder(); +var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder(); +var tds = 0; +try { + td.decode(et, { stream: true }); + tds = 1; +} catch (e) { +} +var dutf8 = function(d) { + for (var r = "", i = 0; ; ) { + var c = d[i++]; + var eb = (c > 127) + (c > 223) + (c > 239); + if (i + eb > d.length) + return [r, slc(d, i - 1)]; + if (!eb) + r += String.fromCharCode(c); + else if (eb == 3) { + c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | d[i++] & 63) - 65536, r += String.fromCharCode(55296 | c >> 10, 56320 | c & 1023); + } else if (eb & 1) + r += String.fromCharCode((c & 31) << 6 | d[i++] & 63); + else + r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | d[i++] & 63); + } +}; +function strToU8(str, latin1) { + if (latin1) { + var ar_1 = new u8(str.length); + for (var i = 0; i < str.length; ++i) + ar_1[i] = str.charCodeAt(i); + return ar_1; + } + if (te) + return te.encode(str); + var l = str.length; + var ar = new u8(str.length + (str.length >> 1)); + var ai = 0; + var w = function(v) { + ar[ai++] = v; + }; + for (var i = 0; i < l; ++i) { + if (ai + 5 > ar.length) { + var n = new u8(ai + 8 + (l - i << 1)); + n.set(ar); + ar = n; + } + var c = str.charCodeAt(i); + if (c < 128 || latin1) + w(c); + else if (c < 2048) + w(192 | c >> 6), w(128 | c & 63); + else if (c > 55295 && c < 57344) + c = 65536 + (c & 1023 << 10) | str.charCodeAt(++i) & 1023, w(240 | c >> 18), w(128 | c >> 12 & 63), w(128 | c >> 6 & 63), w(128 | c & 63); + else + w(224 | c >> 12), w(128 | c >> 6 & 63), w(128 | c & 63); + } + return slc(ar, 0, ai); +} +function strFromU8(dat, latin1) { + if (latin1) { + var r = ""; + for (var i = 0; i < dat.length; i += 16384) + r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384)); + return r; + } else if (td) + return td.decode(dat); + else { + var _a2 = dutf8(dat), out = _a2[0], ext = _a2[1]; + if (ext.length) + err(8); + return out; + } +} +var slzh = function(d, b) { + return b + 30 + b2(d, b + 26) + b2(d, b + 28); +}; +var zh = function(d, b, z) { + var fnl = b2(d, b + 28), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl, bs = b4(d, b + 20); + var _a2 = z && bs == 4294967295 ? z64e(d, es) : [bs, b4(d, b + 24), b4(d, b + 42)], sc = _a2[0], su = _a2[1], off = _a2[2]; + return [b2(d, b + 10), sc, su, fn, es + b2(d, b + 30) + b2(d, b + 32), off]; +}; +var z64e = function(d, b) { + for (; b2(d, b) != 1; b += 4 + b2(d, b + 2)) + ; + return [b8(d, b + 12), b8(d, b + 4), b8(d, b + 20)]; +}; +var exfl = function(ex) { + var le = 0; + if (ex) { + for (var k in ex) { + var l = ex[k].length; + if (l > 65535) + err(9); + le += l + 4; + } + } + return le; +}; +var wzh = function(d, b, f, fn, u, c, ce, co) { + var fl2 = fn.length, ex = f.extra, col = co && co.length; + var exl = exfl(ex); + wbytes(d, b, ce != null ? 33639248 : 67324752), b += 4; + if (ce != null) + d[b++] = 20, d[b++] = f.os; + d[b] = 20, b += 2; + d[b++] = f.flag << 1 | (c < 0 && 8), d[b++] = u && 8; + d[b++] = f.compression & 255, d[b++] = f.compression >> 8; + var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980; + if (y < 0 || y > 119) + err(10); + wbytes(d, b, y << 25 | dt.getMonth() + 1 << 21 | dt.getDate() << 16 | dt.getHours() << 11 | dt.getMinutes() << 5 | dt.getSeconds() >>> 1), b += 4; + if (c != -1) { + wbytes(d, b, f.crc); + wbytes(d, b + 4, c < 0 ? -c - 2 : c); + wbytes(d, b + 8, f.size); + } + wbytes(d, b + 12, fl2); + wbytes(d, b + 14, exl), b += 16; + if (ce != null) { + wbytes(d, b, col); + wbytes(d, b + 6, f.attrs); + wbytes(d, b + 10, ce), b += 14; + } + d.set(fn, b); + b += fl2; + if (exl) { + for (var k in ex) { + var exf = ex[k], l = exf.length; + wbytes(d, b, +k); + wbytes(d, b + 2, l); + d.set(exf, b + 4), b += 4 + l; + } + } + if (col) + d.set(co, b), b += col; + return b; +}; +var wzf = function(o, b, c, d, e) { + wbytes(o, b, 101010256); + wbytes(o, b + 8, c); + wbytes(o, b + 10, c); + wbytes(o, b + 12, d); + wbytes(o, b + 16, e); +}; +function zip(data, opts, cb) { + if (!cb) + cb = opts, opts = {}; + if (typeof cb != "function") + err(7); + var r = {}; + fltn(data, "", r, opts); + var k = Object.keys(r); + var lft = k.length, o = 0, tot = 0; + var slft = lft, files = new Array(lft); + var term = []; + var tAll = function() { + for (var i2 = 0; i2 < term.length; ++i2) + term[i2](); + }; + var cbd = function(a, b) { + mt(function() { + cb(a, b); + }); + }; + mt(function() { + cbd = cb; + }); + var cbf = function() { + var out = new u8(tot + 22), oe = o, cdl = tot - o; + tot = 0; + for (var i2 = 0; i2 < slft; ++i2) { + var f = files[i2]; + try { + var l = f.c.length; + wzh(out, tot, f, f.f, f.u, l); + var badd = 30 + f.f.length + exfl(f.extra); + var loc = tot + badd; + out.set(f.c, loc); + wzh(out, o, f, f.f, f.u, l, tot, f.m), o += 16 + badd + (f.m ? f.m.length : 0), tot = loc + l; + } catch (e) { + return cbd(e, null); + } + } + wzf(out, o, files.length, cdl, oe); + cbd(null, out); + }; + if (!lft) + cbf(); + var _loop_1 = function(i2) { + var fn = k[i2]; + var _a2 = r[fn], file = _a2[0], p = _a2[1]; + var c = crc(), size = file.length; + c.p(file); + var f = strToU8(fn), s = f.length; + var com = p.comment, m = com && strToU8(com), ms = m && m.length; + var exl = exfl(p.extra); + var compression = p.level == 0 ? 0 : 8; + var cbl = function(e, d) { + if (e) { + tAll(); + cbd(e, null); + } else { + var l = d.length; + files[i2] = mrg(p, { + size, + crc: c.d(), + c: d, + f, + m, + u: s != fn.length || m && com.length != ms, + compression + }); + o += 30 + s + exl + l; + tot += 76 + 2 * (s + exl) + (ms || 0) + l; + if (!--lft) + cbf(); + } + }; + if (s > 65535) + cbl(err(11, 0, 1), null); + if (!compression) + cbl(null, file); + else if (size < 16e4) { + try { + cbl(null, deflateSync(file, p)); + } catch (e) { + cbl(e, null); + } + } else + term.push(deflate(file, p, cbl)); + }; + for (var i = 0; i < slft; ++i) { + _loop_1(i); + } + return tAll; +} +var mt = typeof queueMicrotask == "function" ? queueMicrotask : typeof setTimeout == "function" ? setTimeout : function(fn) { + fn(); +}; +function unzipSync(data, opts) { + var files = {}; + var e = data.length - 22; + for (; b4(data, e) != 101010256; --e) { + if (!e || data.length - e > 65558) + err(13); + } + ; + var c = b2(data, e + 8); + if (!c) + return {}; + var o = b4(data, e + 16); + var z = o == 4294967295 || c == 65535; + if (z) { + var ze = b4(data, e - 12); + z = b4(data, ze) == 101075792; + if (z) { + c = b4(data, ze + 32); + o = b4(data, ze + 48); + } + } + var fltr = opts && opts.filter; + for (var i = 0; i < c; ++i) { + var _a2 = zh(data, o, z), c_2 = _a2[0], sc = _a2[1], su = _a2[2], fn = _a2[3], no = _a2[4], off = _a2[5], b = slzh(data, off); + o = no; + if (!fltr || fltr({ + name: fn, + size: sc, + originalSize: su, + compression: c_2 + })) { + if (!c_2) + files[fn] = slc(data, b, b + sc); + else if (c_2 == 8) + files[fn] = inflateSync(data.subarray(b, b + sc), new u8(su)); + else + err(14, "unknown compression type " + c_2); + } + } + return files; +} + +// src/features/textbundle/logic.ts +function transformMarkdownLinks(content, resolver) { + content = content.replace(/!\[\[([^\]]+)\]\]/g, (match, link) => { + const [path, alias] = link.split("|"); + const resolvedName = resolver.resolveAsset(path); + if (resolvedName) { + return `![${alias || resolvedName}](assets/${resolvedName})`; + } + return match; + }); + content = content.replace(/\[\[([^\]]+)\]\]/g, (match, link) => { + const [path, alias] = link.split("|"); + const notePath = resolver.resolveNote(path); + if (notePath) { + const parts = notePath.split("/"); + const bundleName = parts[parts.length - 2] || ""; + const decodedBundle = decodeURIComponent(bundleName); + const basename = decodedBundle.replace(".textbundle", "").split(" - ").pop() || "Note"; + return `[${alias || basename}](${notePath})`; + } + const assetName = resolver.resolveAsset(path); + if (assetName) { + return `[${alias || assetName}](assets/${assetName})`; + } + return match; + }); + return content; +} + +// src/features/textbundle/packer.ts +var TextBundlePacker = class { + constructor(app) { + this.app = app; + } + /** + * Zips the context into a TextBundle (single) or TextPack (multiple bundles) blob. + */ + async pack(context) { + const zipData = {}; + if (context.notes.length === 1) { + const note = context.notes[0]; + await this.buildBundleData(note, context, zipData, ""); + } else { + const usedNames = /* @__PURE__ */ new Set(); + const bundleMap = /* @__PURE__ */ new Map(); + for (const note of context.notes) { + let baseName = note.basename; + let bundleName = `${baseName}.textbundle`; + let counter = 1; + while (usedNames.has(bundleName)) { + bundleName = `${baseName} (${counter}).textbundle`; + counter++; + } + usedNames.add(bundleName); + bundleMap.set(note.path, bundleName); + } + for (const note of context.notes) { + const bundleName = bundleMap.get(note.path); + const bundleData = {}; + await this.buildBundleData(note, context, bundleData, "", bundleMap); + zipData[bundleName] = bundleData; + } + } + return new Promise((resolve, reject) => { + zip(zipData, (err2, data) => { + if (err2) reject(err2); + else resolve(data); + }); + }); + } + /** + * Builds the internal structure of a single TextBundle. + */ + async buildBundleData(note, context, target, prefix, bundleMap) { + var _a2, _b2; + const info = { + "version": 2, + "type": "net.daringfireball.markdown", + "title": note.basename, + "origin_vault": this.app.vault.getName(), + "origin_path": note.path, + "export_timestamp": (/* @__PURE__ */ new Date()).toISOString() + }; + target[`${prefix}info.json`] = strToU8(JSON.stringify(info, null, 2)); + const assetsObj = {}; + const contentRaw = await this.app.vault.read(note); + const embeds = ((_a2 = this.app.metadataCache.getFileCache(note)) == null ? void 0 : _a2.embeds) || []; + const links = ((_b2 = this.app.metadataCache.getFileCache(note)) == null ? void 0 : _b2.links) || []; + for (const mention of [...embeds, ...links]) { + const assetFile = this.app.metadataCache.getFirstLinkpathDest(mention.link, note.path); + if (assetFile instanceof import_obsidian3.TFile && context.assetMap.has(assetFile.path)) { + const bundleAssetName = context.assetMap.get(assetFile.path); + const assetData = await this.app.vault.readBinary(assetFile); + assetsObj[bundleAssetName] = new Uint8Array(assetData); + } + } + if (Object.keys(assetsObj).length > 0) { + target[`${prefix}assets`] = assetsObj; + } + const resolver = { + resolveAsset: (link) => { + const assetFile = this.app.metadataCache.getFirstLinkpathDest(link, note.path); + if (assetFile instanceof import_obsidian3.TFile) { + const ext = assetFile.extension.toLowerCase(); + if (ext === "md" || ext === "markdown") return null; + return context.assetMap.get(assetFile.path) || assetFile.name; + } + return null; + }, + resolveNote: (link) => { + const targetFile = this.app.metadataCache.getFirstLinkpathDest(link, note.path); + if (targetFile instanceof import_obsidian3.TFile) { + if (bundleMap && bundleMap.has(targetFile.path)) { + const bundleName = bundleMap.get(targetFile.path); + const encodedName = encodeURIComponent(bundleName); + return `../${encodedName}/text.md`; + } + } + return null; + } + }; + const content = transformMarkdownLinks(contentRaw, resolver); + target[`${prefix}text.md`] = strToU8(content); + } +}; + +// src/features/textbundle/importer.ts +var import_obsidian4 = require("obsidian"); +var TextBundleImporter = class { + constructor(app, settings, system) { + this.app = app; + this.settings = settings; + this.system = system; + } + /** + * Entry point for ZIP import. + */ + async importZip(data, targetPath, sourceName) { + try { + const unzipped = unzipSync(new Uint8Array(data)); + await this.processUnzipped(unzipped, targetPath, sourceName); + new import_obsidian4.Notice("Alchemist: Import successful"); + } catch (e) { + console.error("Alchemist: Import failed", e); + new import_obsidian4.Notice("Alchemist: Import failed. Check console for details."); + } + } + async processUnzipped(unzipped, targetPath, sourceName) { + const allKeys = Object.keys(unzipped); + const bundleFolders = /* @__PURE__ */ new Set(); + allKeys.forEach((k) => { + const match = k.match(/(.*\.textbundle)\//); + if (match) bundleFolders.add(match[1]); + }); + if (bundleFolders.size === 0) { + await this.importSingleBundle(unzipped, targetPath, sourceName); + } else { + new import_obsidian4.Notice(`Alchemist: Importing ${bundleFolders.size} notes from TextPack...`); + for (const folder of bundleFolders) { + const prefix = `${folder}/`; + const bundleFiles = {}; + for (const key of allKeys) { + if (key.startsWith(prefix)) { + bundleFiles[key.replace(prefix, "")] = unzipped[key]; + } + } + const cleanName = folder.replace(".textbundle", ""); + await this.importSingleBundle(bundleFiles, targetPath, cleanName); + } + } + } + async importSingleBundle(files, targetPath, sourceName) { + const allKeys = Object.keys(files); + const textKey = allKeys.find( + (k) => k.endsWith("text.md") || k.endsWith("text.markdown") || k.endsWith("text.txt") || k === "text.md" || k === "text.markdown" || k === "text.txt" + ); + if (!textKey) return; + const textData = files[textKey]; + let content = strFromU8(textData); + const importRoot = targetPath || this.settings.defaultImportPath || "/"; + let noteName = sourceName ? `${sourceName}.md` : `Imported_Note.md`; + let finalImportFolder = (0, import_obsidian4.normalizePath)(importRoot); + const infoKey = allKeys.find((k) => k === "info.json"); + if (infoKey) { + try { + const info = JSON.parse(strFromU8(files[infoKey])); + if (info.title) noteName = `${info.title}.md`; + if (info.origin_path && this.settings.restoreFolderStructure) { + const relativeDir = this.system.path.dirname(info.origin_path); + if (relativeDir !== ".") { + finalImportFolder = (0, import_obsidian4.normalizePath)(`${importRoot}/${relativeDir}`); + } + } + } catch (e) { + } + } + await this.ensureFolder(finalImportFolder); + const attachmentFolderPath = (0, import_obsidian4.normalizePath)(`${finalImportFolder}/media`); + await this.ensureFolder(attachmentFolderPath); + const assetsBase = "assets/"; + const assetRenameMap = /* @__PURE__ */ new Map(); + for (const [path, assetData] of Object.entries(files)) { + if (path.startsWith(assetsBase) && path !== assetsBase) { + const originalFileName = path.replace(assetsBase, ""); + const actualFileName = await this.importAssetWithSafety(originalFileName, assetData, attachmentFolderPath); + if (actualFileName !== originalFileName) { + assetRenameMap.set(originalFileName, actualFileName); + } + } + } + content = this.reverseTransformLinks(content); + for (const [oldName, newName] of assetRenameMap.entries()) { + const escapedOldName = oldName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const linkRegex = new RegExp(`\\[\\[media/${escapedOldName}(\\|[^\\]]+)?\\]\\]`, "g"); + content = content.replace(linkRegex, (match, alias) => { + return `[[media/${newName}${alias || ""}]]`; + }); + } + await this.createNoteWithSafety(finalImportFolder, noteName, content); + } + async importAssetWithSafety(fileName, data, folderPath) { + await this.ensureFolder(folderPath); + let actualName = fileName; + let fullPath = (0, import_obsidian4.normalizePath)(`${folderPath}/${actualName}`); + let counter = 1; + const nameParts = fileName.split("."); + const ext = nameParts.pop(); + const base = nameParts.join("."); + while (await this.app.vault.adapter.exists(fullPath)) { + const existingData = await this.app.vault.adapter.readBinary(fullPath); + if (this.areBuffersEqual(new Uint8Array(existingData), data)) { + return actualName; + } + actualName = `${base} (${counter}).${ext}`; + fullPath = (0, import_obsidian4.normalizePath)(`${folderPath}/${actualName}`); + counter++; + } + await this.app.vault.createBinary(fullPath, data.buffer); + return actualName; + } + areBuffersEqual(buf1, buf2) { + if (buf1.length !== buf2.length) return false; + for (let i = 0; i < buf1.length; i++) { + if (buf1[i] !== buf2[i]) return false; + } + return true; + } + async createNoteWithSafety(folderPath, fileName, content) { + let finalPath = (0, import_obsidian4.normalizePath)(`${folderPath}/${fileName}`); + let counter = 1; + const nameParts = fileName.split("."); + const ext = nameParts.pop(); + const base = nameParts.join("."); + while (this.app.vault.getAbstractFileByPath(finalPath)) { + if (this.settings.conflictStrategy === "skip") return; + if (this.settings.conflictStrategy === "overwrite") { + const existing = this.app.vault.getAbstractFileByPath(finalPath); + if (existing instanceof import_obsidian4.TFile) { + await this.app.vault.modify(existing, content); + } + return; + } + finalPath = (0, import_obsidian4.normalizePath)(`${folderPath}/${base} (${counter}).${ext}`); + counter++; + } + await this.app.vault.create(finalPath, content); + } + async ensureFolder(path) { + if (!path || path === "/" || path === ".") return; + const normalized = (0, import_obsidian4.normalizePath)(path); + if (this.app.vault.getAbstractFileByPath(normalized)) return; + const parts = normalized.split("/"); + let currentPath = ""; + for (const part of parts) { + currentPath = currentPath ? `${currentPath}/${part}` : part; + if (!this.app.vault.getAbstractFileByPath(currentPath)) { + await this.app.vault.createFolder(currentPath); + } + } + } + getAttachmentFolder() { + var _a2, _b2; + return ((_b2 = (_a2 = this.app.vault).getConfig) == null ? void 0 : _b2.call(_a2, "attachmentFolderPath")) || ""; + } + reverseTransformLinks(content) { + content = content.replace(/!\[([^\]]*)\]\(assets\/([^\)]+)\)/g, (match, alt, filename) => { + return alt ? `![[media/${filename}|${alt}]]` : `![[media/${filename}]]`; + }); + content = content.replace(/\[([^\]]+)\]\(assets\/([^\)]+)\)/g, (match, text, filename) => { + return text === filename ? `[[media/${filename}]]` : `[[media/${filename}|${text}]]`; + }); + content = content.replace(/\[([^\]]+)\]\(\.\.\/([^/]+)\/text\.(md|markdown|txt)\)/g, (match, text, folderName) => { + const decodedBundle = decodeURIComponent(folderName); + const bundleBase = decodedBundle.replace(/\.textbundle$/i, ""); + const noteName = bundleBase.replace(/ \(\d+\)$/, ""); + return text === noteName ? `[[${noteName}]]` : `[[${noteName}|${text}]]`; + }); + return content; + } +}; + +// src/features/textbundle/TextBundleModule.ts +var TextBundleModule = class { + constructor() { + this.id = "textbundle"; + } + async load(context) { + this.context = context; + this.collector = new TextBundleFeature(context.app, context.settings); + this.packer = new TextBundlePacker(context.app); + this.importer = new TextBundleImporter(context.app, context.settings, context.system); + this.registerCommands(); + this.registerEvents(); + this.registerRibbonIcons(); + } + async unload() { + } + async onSettingsChange(newSettings) { + this.context.settings = newSettings; + } + registerRibbonIcons() { + this.context.plugin.addRibbonIcon("package-plus", "Alchemist: Import TextBundle", () => { + if (!this.context.settings.enableTextBundle) { + new import_obsidian5.Notice("TextBundle module is disabled in settings."); + return; + } + this.runImport(); + }); + } + registerCommands() { + this.context.plugin.addCommand({ + id: "import-textbundle", + name: "Import TextBundle", + callback: () => { + if (!this.context.settings.enableTextBundle) return; + this.runImport(); + } + }); + this.context.plugin.addCommand({ + id: "export-current-textbundle", + name: "Export current file as TextBundle", + checkCallback: (checking) => { + if (!this.context.settings.enableTextBundle) return false; + const activeFile = this.context.app.workspace.getActiveFile(); + if (activeFile) { + if (!checking) this.runExport(activeFile); + return true; + } + return false; + } + }); + } + registerEvents() { + this.context.plugin.registerEvent( + this.context.app.workspace.on("file-menu", (menu, abstractFile) => { + if (!this.context.settings.enableTextBundle) return; + if (abstractFile instanceof import_obsidian5.TFile && abstractFile.extension === "md") { + menu.addItem((item) => { + item.setTitle("Alchemist: Export as TextBundle").setIcon("package").onClick(() => this.runExport(abstractFile)); + }); + } else if (abstractFile instanceof import_obsidian5.TFolder) { + menu.addItem((item) => { + item.setTitle("Alchemist: Export folder as TextBundle").setIcon("package").onClick(async () => { + const files = []; + const collect = (f) => { + if (f instanceof import_obsidian5.TFile && f.extension === "md") files.push(f); + else if (f instanceof import_obsidian5.TFolder) f.children.forEach(collect); + }; + collect(abstractFile); + if (files.length === 0) { + new import_obsidian5.Notice("No markdown files found in this folder."); + return; + } + const result = await this.context.system.showOpenDialog({ + title: "Select Destination for Bulk Export", + defaultPath: this.context.settings.lastDialogPath, + properties: ["openDirectory", "createDirectory"] + }); + if (!result.canceled && result.filePaths.length > 0) { + const targetDir = result.filePaths[0]; + this.context.settings.lastDialogPath = targetDir; + await this.context.plugin.saveSettings(); + new import_obsidian5.Notice(`Bulk Exporting ${files.length} notes...`); + let successCount = 0; + for (const f of files) { + try { + const context = await this.collector.collectResources(f); + const blob = await this.packer.pack(context); + const extension = this.context.settings.compressionFormat || "textbundle"; + const fullPath = this.context.system.path.join(targetDir, `${f.basename}.${extension}`); + this.context.system.fs.writeFileSync(fullPath, Buffer.from(blob)); + successCount++; + } catch (e) { + console.error(`Export failed for ${f.name}:`, e); + } + } + new import_obsidian5.Notice(`Successfully exported ${successCount}/${files.length} notes to ${targetDir}`); + } + }); + }); + menu.addItem((item) => { + item.setTitle("Alchemist: Import into here").setIcon("package-plus").onClick(() => this.runImport(abstractFile.path)); + }); + } + }) + ); + } + async runImport(targetPath) { + var _a2; + const result = await this.context.system.showOpenDialog({ + title: targetPath ? `Import into ${targetPath}` : "Import TextBundle", + defaultPath: this.context.settings.lastDialogPath, + filters: [{ name: "TextBundle", extensions: ["textbundle", "zip", "textpack"] }], + properties: ["openFile"] + }); + if (!result.canceled && result.filePaths.length > 0) { + const filePath = result.filePaths[0]; + this.context.settings.lastDialogPath = this.context.system.path.dirname(filePath); + await this.context.plugin.saveSettings(); + const sourceName = ((_a2 = filePath.split(/[\\/]/).pop()) == null ? void 0 : _a2.replace(/\.(zip|textpack|textbundle)$/i, "")) || "Imported_Note"; + try { + const data = this.context.system.fs.readFileSync(filePath); + await this.importer.importZip(data, targetPath, sourceName); + new import_obsidian5.Notice("Successfully imported TextBundle"); + } catch (e) { + console.error("Alchemist Import Error:", e); + new import_obsidian5.Notice(`Import failed: ${e.message}`); + } + } + } + async runExport(file) { + try { + const context = await this.collector.collectResources(file); + const blob = await this.packer.pack(context); + const extension = this.context.settings.compressionFormat || "textbundle"; + const result = await this.context.system.showSaveDialog({ + title: "Save TextBundle", + defaultPath: this.context.system.path.join(this.context.settings.lastDialogPath, `${file.basename}.${extension}`), + filters: [{ name: "TextBundle", extensions: [extension, "zip"] }] + }); + if (!result.canceled && result.filePath) { + this.context.settings.lastDialogPath = this.context.system.path.dirname(result.filePath); + await this.context.plugin.saveSettings(); + this.context.system.fs.writeFileSync(result.filePath, Buffer.from(blob)); + new import_obsidian5.Notice(`Successfully exported: ${file.basename}`); + } + } catch (e) { + console.error("Alchemist Export Error:", e); + new import_obsidian5.Notice(`Export failed: ${e.message}`); + } + } +}; + +// src/features/paste-cleaner/SmartPasteModule.ts +var import_obsidian6 = require("obsidian"); + +// src/features/paste-cleaner/logic.ts +var BLACKLIST = [ + "utm_", + "fbclid", + "gclid", + "yclid", + "msclkid", + "mc_cid", + "mc_eid", + "_hsenc", + "_hsmi", + "sca_esv", + "sxsrf", + "ei", + "biw", + "bih", + "oq", + "gs_lp", + "sclient", + "ved", + "uact" +]; +function stripTrackers(input) { + const urlRegex = /(https?:\/\/[^\s"'>]+)/g; + return input.replace(urlRegex, (url) => { + try { + const decodedUrl = url.replace(/&/g, "&"); + const urlObj = new URL(decodedUrl); + const params = urlObj.searchParams; + const toRemove = []; + params.forEach((_, key) => { + if (BLACKLIST.some((b) => key.toLowerCase().startsWith(b))) { + toRemove.push(key); + } + }); + if (toRemove.length > 0) { + toRemove.forEach((k) => params.delete(k)); + return urlObj.toString(); + } + return url; + } catch (e) { + return url; + } + }); +} + +// src/features/paste-cleaner/SmartPasteModule.ts +var SmartPasteModule = class { + constructor() { + this.id = "smart-paste"; + } + async load(context) { + this.context = context; + this.registerPasteHandler(); + this.registerCommands(); + } + async unload() { + } + async onSettingsChange(newSettings) { + this.context.settings = newSettings; + } + registerCommands() { + this.context.plugin.addCommand({ + id: "clean-trackers-in-document", + name: "Clean trackers in current document", + editorCallback: (editor) => { + const content = editor.getValue(); + const cleaned = stripTrackers(content); + if (content !== cleaned) { + editor.setValue(cleaned); + new import_obsidian6.Notice("Alchemist: Document cleaned from trackers"); + } else { + new import_obsidian6.Notice("Alchemist: No trackers found"); + } + } + }); + } + registerPasteHandler() { + this.context.plugin.registerEvent( + this.context.app.workspace.on("editor-paste", async (evt, editor) => { + var _a2; + if (!this.context.settings.enableSmartPaste) return; + const clipboardData = evt.clipboardData; + if (!clipboardData) return; + const text = ((_a2 = clipboardData.getData("text/plain")) == null ? void 0 : _a2.trim()) || ""; + const urlRegex = /^(https?:\/\/[^\s"'>]+)$/; + if (text.match(urlRegex) && this.context.settings.stripTrackingParameters) { + const cleanUrl = stripTrackers(text); + if (cleanUrl !== text) { + evt.preventDefault(); + editor.replaceSelection(cleanUrl); + new import_obsidian6.Notice("Alchemist: URL cleaned"); + } + } + }) + ); + } +}; + +// src/features/dataview-export/DataviewModule.ts +var import_obsidian7 = require("obsidian"); + +// src/features/dataview-export/logic.ts +function escapeCsvCell(text) { + if (!text) return ""; + let result = text.trim(); + if (result.includes('"')) { + result = result.replace(/"/g, '""'); + } + if (result.includes(",") || result.includes("\n") || result.includes('"')) { + result = `"${result}"`; + } + return result; +} + +// src/features/dataview-export/DataviewModule.ts +var DataviewModule = class { + constructor() { + this.id = "dataview-export"; + this.observer = null; + this.injectTimeout = null; + } + async load(context) { + this.context = context; + this.setupGlobalObserver(); + this.start(); + } + async unload() { + this.stop(); + } + async onSettingsChange(newSettings) { + const wasEnabled = this.context.settings.enableDataviewExport; + this.context.settings = newSettings; + if (wasEnabled !== newSettings.enableDataviewExport) { + if (newSettings.enableDataviewExport) this.start(); + else this.stop(); + } + } + setupGlobalObserver() { + this.observer = new MutationObserver(() => { + if (!this.context.settings.enableDataviewExport) return; + if (this.injectTimeout) clearTimeout(this.injectTimeout); + this.injectTimeout = setTimeout(() => { + this.injectAll(); + }, 300); + }); + } + start() { + if (this.context.settings.enableDataviewExport && this.observer) { + this.observer.observe(document.body, { childList: true, subtree: true }); + this.injectAll(); + } + } + stop() { + if (this.observer) { + this.observer.disconnect(); + } + if (this.injectTimeout) clearTimeout(this.injectTimeout); + document.querySelectorAll(".alchemist-export-btn").forEach((btn) => btn.remove()); + } + injectAll() { + var _a2, _b2; + const isDataviewEnabled = (_b2 = (_a2 = this.context.app.plugins) == null ? void 0 : _a2.enabledPlugins) == null ? void 0 : _b2.has("dataview"); + if (!isDataviewEnabled) return; + const containers = document.querySelectorAll(".block-language-dataview, .dataview.table-view-table, .dataview-container"); + containers.forEach((c) => this.injectButton(c)); + } + injectButton(container) { + if (container.querySelector(".alchemist-export-btn")) return; + if (!container.querySelector("table") && !container.classList.contains("block-language-dataview")) return; + const btn = document.createElement("button"); + btn.className = "alchemist-export-btn clickable-icon"; + btn.innerText = "\u{1F4BE} CSV"; + btn.style.cssText = "position: absolute; right: 10px; top: 10px; z-index: 100; font-size: 0.7em; opacity: 0.6;"; + btn.addEventListener("mouseenter", () => btn.style.opacity = "1"); + btn.addEventListener("mouseleave", () => btn.style.opacity = "0.6"); + btn.onclick = (e) => { + e.preventDefault(); + e.stopPropagation(); + this.exportTable(container); + }; + container.appendChild(btn); + if (getComputedStyle(container).position === "static") { + container.style.position = "relative"; + } + } + async exportTable(el) { + const table = el.querySelector("table"); + if (!table) { + new import_obsidian7.Notice("No table found to export"); + return; + } + const rows = Array.from(table.querySelectorAll("tr")); + const csvRows = rows.map((row) => { + const cells = Array.from(row.querySelectorAll("th, td")); + return cells.map((cell) => escapeCsvCell(cell.innerText)).join(","); + }); + const sourceFile = this.context.app.workspace.getActiveFile(); + csvRows.push(""); + csvRows.push(`"Source","[[${(sourceFile == null ? void 0 : sourceFile.path) || "unknown"}]]"`); + csvRows.push(`"Exported","${(/* @__PURE__ */ new Date()).toLocaleString()}"`); + await this.handleSave(csvRows.join("\n")); + } + async handleSave(content) { + const settings = this.context.settings; + if (settings.dataviewExportStrategy === "vault") { + const folderPath = (0, import_obsidian7.normalizePath)(settings.dataviewVaultPath || "Exports"); + await this.ensureFolder(folderPath); + const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"); + const fileName = `dataview_export_${timestamp}.csv`; + const fullPath = `${folderPath}/${fileName}`; + await this.context.app.vault.create(fullPath, content); + new import_obsidian7.Notice(`CSV Saved to Vault: ${fullPath}`); + } else { + const result = await this.context.system.showSaveDialog({ + title: "Export Dataview to CSV", + defaultPath: this.context.system.path.join(this.context.settings.lastDialogPath, "dataview_export.csv"), + filters: [{ name: "CSV", extensions: ["csv"] }] + }); + if (!result.canceled && result.filePath) { + this.context.settings.lastDialogPath = this.context.system.path.dirname(result.filePath); + await this.context.plugin.saveSettings(); + this.context.system.fs.writeFileSync(result.filePath, content); + new import_obsidian7.Notice("CSV Exported Successfully"); + } + } + } + async ensureFolder(path) { + const folder = this.context.app.vault.getAbstractFileByPath(path); + if (folder instanceof import_obsidian7.TFolder) return; + await this.context.app.vault.createFolder(path); + } +}; + +// src/features/audio-converter/AudioModule.ts +var import_obsidian8 = require("obsidian"); +var import_child_process = require("child_process"); + +// src/features/audio-converter/logic.ts +function getFfmpegArgs(inputPath, outputPath, format, metadata) { + const args = ["-i", inputPath]; + if (metadata.title) args.push("-metadata", `title=${metadata.title}`); + if (metadata.artist) args.push("-metadata", `artist=${metadata.artist}`); + if (metadata.date) args.push("-metadata", `date=${metadata.date}`); + if (metadata.genre) args.push("-metadata", `genre=${metadata.genre}`); + if (metadata.album) args.push("-metadata", `album=${metadata.album}`); + if (format === "mp3") { + args.push("-c:a", "libmp3lame", "-q:a", "2"); + } else if (format === "wav") { + args.push("-c:a", "pcm_s16le"); + } else if (format === "ogg") { + args.push("-c:a", "libvorbis", "-q:a", "4"); + } else if (format === "flac") { + args.push("-c:a", "flac"); + } else if (format === "m4a") { + args.push("-c:a", "aac", "-b:a", "192k"); + } + args.push("-y", outputPath); + return args; +} + +// src/features/audio-converter/AudioModule.ts +var AudioModule = class { + constructor() { + this.id = "audio-converter"; + this.statusBarItem = null; + } + async load(context) { + this.context = context; + this.statusBarItem = this.context.plugin.addStatusBarItem(); + if (this.statusBarItem) this.statusBarItem.hide(); + this.registerEvents(); + } + async unload() { + } + async onSettingsChange(newSettings) { + this.context.settings = newSettings; + } + registerEvents() { + this.context.plugin.registerEvent( + this.context.app.workspace.on("file-menu", (menu, abstractFile) => { + if (!this.context.settings.enableAudioConverter) return; + const format = this.context.settings.defaultAudioOutputFormat || "mp3"; + if (abstractFile instanceof import_obsidian8.TFile) { + const ext = abstractFile.extension.toLowerCase(); + const audioExtensions = ["webm", "ogg", "wav", "mp3", "m4a", "flac", "aac", "opus"]; + if (audioExtensions.includes(ext) && ext !== format) { + menu.addItem((item) => { + item.setTitle(`Alchemist: Convert to ${format.toUpperCase()}`).setIcon("music").onClick(() => this.runConversion([abstractFile], format)); + }); + } + } + }) + ); + this.context.plugin.registerEvent( + this.context.app.workspace.on("files-menu", (menu, files) => { + if (!this.context.settings.enableAudioConverter) return; + const audioExtensions = ["webm", "ogg", "wav", "mp3", "m4a", "flac", "aac", "opus"]; + const audioFiles = files.filter((f) => f instanceof import_obsidian8.TFile && audioExtensions.includes(f.extension.toLowerCase()) && f.extension.toLowerCase() !== format); + if (audioFiles.length <= 1) return; + const format = this.context.settings.defaultAudioOutputFormat || "mp3"; + menu.addItem((item) => { + item.setTitle(`Alchemist: Convert ${audioFiles.length} files to ${format.toUpperCase()}`).setIcon("music").onClick(() => this.runConversion(audioFiles, format)); + }); + }) + ); + } + async runConversion(files, format) { + if (files.length === 0) return; + const total = files.length; + let processed = 0; + if (this.statusBarItem) { + this.statusBarItem.show(); + this.updateStatus(processed, total); + } + new import_obsidian8.Notice(`Alchemist: Converting ${total} file(s)...`); + for (const file of files) { + try { + const metadata = await this.extractMetadata(file); + await this.convert(file, format, metadata); + processed++; + this.updateStatus(processed, total); + } catch (e) { + console.error(`Alchemist Audio Error (${file.name}):`, e); + new import_obsidian8.Notice(`Conversion failed for ${file.name}: ${e.message}`); + } + } + if (this.statusBarItem) this.statusBarItem.hide(); + new import_obsidian8.Notice(`Alchemist: Finished processing ${processed}/${total} files.`); + } + updateStatus(current, total) { + if (!this.statusBarItem) return; + this.statusBarItem.setText(`\u{1F9EA} Alchemist: ${current}/${total} [${Math.round(current / total * 100)}%]`); + } + async extractMetadata(file) { + const metadata = { + title: file.basename, + artist: this.context.settings.defaultAudioArtist, + album: this.context.settings.defaultAudioAlbum, + genre: this.context.settings.defaultAudioGenre, + date: (/* @__PURE__ */ new Date()).getFullYear().toString() + }; + const mdPath = file.path.replace(/\.[^/.]+$/, ".md"); + const mdFile = this.context.app.vault.getAbstractFileByPath(mdPath); + if (mdFile instanceof import_obsidian8.TFile) { + const cache = this.context.app.metadataCache.getFileCache(mdFile); + const frontmatter = cache == null ? void 0 : cache.frontmatter; + if (frontmatter) { + if (frontmatter.title) metadata.title = frontmatter.title; + if (frontmatter.artist) metadata.artist = frontmatter.artist; + if (frontmatter.album) metadata.album = frontmatter.album; + if (frontmatter.genre) metadata.genre = frontmatter.genre; + if (frontmatter.date) metadata.date = String(frontmatter.date); + if (!frontmatter.genre && frontmatter.tags) { + const tags = Array.isArray(frontmatter.tags) ? frontmatter.tags : [frontmatter.tags]; + if (tags.length > 0) metadata.genre = tags[0]; + } + } + } + return metadata; + } + async convert(file, format, metadata) { + return new Promise(async (resolve, reject) => { + const system = this.context.system; + const app = this.context.app; + const settings = this.context.settings; + const adapter = app.vault.adapter; + const basePath = adapter.getBasePath(); + const inputPath = system.path.join(basePath, file.path); + const tempOutputPath = system.path.join(system.os.tmpdir(), `alchemist_${Date.now()}.${format}`); + const args = getFfmpegArgs(inputPath, tempOutputPath, format, metadata); + const child = (0, import_child_process.spawn)("ffmpeg", args); + let stderr = ""; + child.stderr.on("data", (data) => { + stderr += data.toString(); + }); + child.on("close", async (code) => { + if (code === 0) { + try { + const data = system.fs.readFileSync(tempOutputPath); + const outputName = file.basename + "." + format; + let finalVaultPath; + switch (settings.targetFolderStrategy) { + case "specific": { + const folder = settings.specificTargetFolder || ""; + finalVaultPath = (0, import_obsidian8.normalizePath)(`${folder}/${outputName}`); + if (folder) { + const existing = app.vault.getAbstractFileByPath(folder); + if (!existing) await app.vault.createFolder(folder); + } + break; + } + case "dialog": { + const result = await system.showSaveDialog({ + title: "Save Converted Audio", + defaultPath: system.path.join(settings.lastDialogPath, outputName), + filters: [{ name: format.toUpperCase(), extensions: [format] }] + }); + if (result.canceled || !result.filePath) { + system.fs.unlinkSync(tempOutputPath); + resolve(); + return; + } + settings.lastDialogPath = system.path.dirname(result.filePath); + await this.context.plugin.saveSettings(); + system.fs.writeFileSync(result.filePath, data); + system.fs.unlinkSync(tempOutputPath); + if (settings.deleteOriginalWebM && file.extension === "webm") { + await app.vault.trash(file, true); + } + resolve(); + return; + } + default: + finalVaultPath = file.path.replace(new RegExp(`\\.${file.extension}$`), `.${format}`); + } + const existingFile = app.vault.getAbstractFileByPath(finalVaultPath); + if (existingFile instanceof import_obsidian8.TFile) { + await app.vault.modifyBinary(existingFile, data.buffer); + } else { + await app.vault.createBinary(finalVaultPath, data.buffer); + } + if (settings.deleteOriginalWebM && file.extension === "webm") { + await app.vault.trash(file, true); + } + system.fs.unlinkSync(tempOutputPath); + resolve(); + } catch (e) { + reject(e); + } + } else { + reject(new Error(`FFmpeg failed: ${stderr}`)); + } + }); + child.on("error", (err2) => reject(err2)); + }); + } +}; + +// main.ts +var AlchemistPlugin = class extends import_obsidian9.Plugin { + constructor() { + super(...arguments); + this.modules = []; + this.systemAdapter = new ElectronSystemAdapter(); + } + async onload() { + console.log("Loading Alchemist (Modular Purity Protocol)..."); + await this.loadSettings(); + this.addSettingTab(new AlchemistSettingTab(this.app, this)); + const context = { + app: this.app, + settings: this.settings, + system: this.systemAdapter, + plugin: this + }; + this.modules = [ + new TextBundleModule(), + new SmartPasteModule(), + new DataviewModule(), + new AudioModule() + ]; + for (const module2 of this.modules) { + try { + await module2.load(context); + console.log(`Alchemist: Module [${module2.id}] loaded`); + } catch (e) { + console.error(`Alchemist: Failed to load module [${module2.id}]`, e); + } + } + console.log("Alchemist: Modular Purity Protocol initiated"); + } + async onunload() { + for (const module2 of this.modules) { + await module2.unload(); + } + console.log("Alchemist: Modular Purity Protocol terminated"); + } + async loadSettings() { + this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + } + async saveSettings() { + await this.saveData(this.settings); + for (const module2 of this.modules) { + await module2.onSettingsChange(this.settings); + } + } +}; diff --git a/dist/manifest.json b/dist/manifest.json new file mode 100644 index 0000000..11aee97 --- /dev/null +++ b/dist/manifest.json @@ -0,0 +1,10 @@ +{ + "id": "obsidian-alchemist", + "name": "Alchemist", + "version": "1.0.0", + "minAppVersion": "0.15.0", + "description": "Modular super-plugin for TextBundle, Audio conversion, and Dataview exports.", + "author": "Kharizma & Latreia", + "authorUrl": "https://github.com/bonifat", + "isDesktopOnly": true +} diff --git a/dist/styles.css b/dist/styles.css new file mode 100644 index 0000000..10e0f63 --- /dev/null +++ b/dist/styles.css @@ -0,0 +1,17 @@ +/* Alchemist Styles */ + +.alchemist-export-btn { + opacity: 0.6; + transition: opacity 0.2s ease-in-out; + background: var(--interactive-accent); + color: var(--text-on-accent); + border: none; + border-radius: 4px; + padding: 2px 6px; + cursor: pointer; +} + +.alchemist-export-btn:hover { + opacity: 1; + background: var(--interactive-accent-hover); +} diff --git a/esbuild.config.mjs b/esbuild.config.mjs new file mode 100644 index 0000000..641a321 --- /dev/null +++ b/esbuild.config.mjs @@ -0,0 +1,48 @@ +import esbuild from "esbuild"; +import process from "process"; +import builtins from "builtin-modules"; + +const banner = +`/* +THIS IS A GENERATED/BUNDLED FILE BY ESBUILD +if you want to view the source, please visit the github repository of this plugin +*/ +`; + +const prod = (process.argv[2] === "production"); + +const context = await esbuild.context({ + banner: { + js: banner, + }, + entryPoints: ["main.ts"], + bundle: true, + external: [ + "obsidian", + "electron", + "@codemirror/autocomplete", + "@codemirror/collab", + "@codemirror/commands", + "@codemirror/language", + "@codemirror/lint", + "@codemirror/search", + "@codemirror/state", + "@codemirror/view", + "@lezer/common", + "@lezer/highlight", + "@lezer/lr", + ...builtins], + format: "cjs", + target: "es2018", + logLevel: "info", + sourcemap: prod ? false : "inline", + treeShaking: true, + outfile: "dist/main.js", +}); + +if (prod) { + await context.rebuild(); + process.exit(0); +} else { + await context.watch(); +} diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..bc60c28 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,10 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + testMatch: ['**/__tests__/**/*.test.ts'], + moduleNameMapper: { + '^obsidian$': '/../../node_modules/obsidian/obsidian.d.ts' + }, + verbose: true +}; diff --git a/main.ts b/main.ts new file mode 100644 index 0000000..4960bae --- /dev/null +++ b/main.ts @@ -0,0 +1,67 @@ +import { Plugin } from 'obsidian'; +import { AlchemistSettings, DEFAULT_SETTINGS, AlchemistSettingTab } from './settings'; +import { IAlchemistModule, AlchemistContext } from './src/core/IAlchemistModule'; +import { ElectronSystemAdapter } from './src/core/SystemAdapter'; + +// Modules +import { TextBundleModule } from './src/features/textbundle/TextBundleModule'; +import { SmartPasteModule } from './src/features/paste-cleaner/SmartPasteModule'; +import { DataviewModule } from './src/features/dataview-export/DataviewModule'; +import { AudioModule } from './src/features/audio-converter/AudioModule'; + +export default class AlchemistPlugin extends Plugin { + settings!: AlchemistSettings; + private modules: IAlchemistModule[] = []; + private systemAdapter = new ElectronSystemAdapter(); + + async onload() { + console.log('Loading Alchemist (Modular Purity Protocol)...'); + await this.loadSettings(); + this.addSettingTab(new AlchemistSettingTab(this.app, this)); + + const context: AlchemistContext = { + app: this.app, + settings: this.settings, + system: this.systemAdapter, + plugin: this + }; + + // Initialize Modules + this.modules = [ + new TextBundleModule(), + new SmartPasteModule(), + new DataviewModule(), + new AudioModule() + ]; + + for (const module of this.modules) { + try { + await module.load(context); + console.log(`Alchemist: Module [${module.id}] loaded`); + } catch (e) { + console.error(`Alchemist: Failed to load module [${module.id}]`, e); + } + } + + console.log('Alchemist: Modular Purity Protocol initiated'); + } + + async onunload() { + for (const module of this.modules) { + await module.unload(); + } + console.log('Alchemist: Modular Purity Protocol terminated'); + } + + async loadSettings() { + this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + } + + async saveSettings() { + await this.saveData(this.settings); + // Notify all modules about settings change + for (const module of this.modules) { + await module.onSettingsChange(this.settings); + } + } +} diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..11aee97 --- /dev/null +++ b/manifest.json @@ -0,0 +1,10 @@ +{ + "id": "obsidian-alchemist", + "name": "Alchemist", + "version": "1.0.0", + "minAppVersion": "0.15.0", + "description": "Modular super-plugin for TextBundle, Audio conversion, and Dataview exports.", + "author": "Kharizma & Latreia", + "authorUrl": "https://github.com/bonifat", + "isDesktopOnly": true +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..ed918ed --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6056 @@ +{ + "name": "obsidian-alchemist", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "obsidian-alchemist", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "fflate": "^0.7.3" + }, + "devDependencies": { + "@types/jest": "^30.0.0", + "@types/node": "^16.11.21", + "@typescript-eslint/eslint-plugin": "^5.10.1", + "@typescript-eslint/parser": "^5.10.1", + "builtin-modules": "^3.2.0", + "esbuild": "^0.28.0", + "jest": "^30.3.0", + "obsidian": "latest", + "ts-jest": "^29.4.9", + "tslib": "2.3.1", + "typescript": "^5.9.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@codemirror/state": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.0.tgz", + "integrity": "sha512-MwBHVK60IiIHDcoMet78lxt6iw5gJOGSbNbOIVBHWVXIH4/Nq1+GQgLLGgI1KlnN86WDXsPudVaqYHKBIx7Eyw==", + "dev": true, + "peer": true, + "dependencies": { + "@marijn/find-cluster-break": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.38.6", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.6.tgz", + "integrity": "sha512-qiS0z1bKs5WOvHIAC0Cybmv4AJSkAXgX5aD6Mqd2epSLlVJsQl8NG23jCVouIgkh4All/mrbdsf2UOLFnJw0tw==", + "dev": true, + "peer": true, + "dependencies": { + "@codemirror/state": "^6.5.0", + "crelt": "^1.0.6", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/core/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "optional": true + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "optional": true + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "optional": true + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", + "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", + "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", + "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", + "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", + "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", + "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", + "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", + "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", + "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", + "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", + "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", + "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", + "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", + "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", + "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", + "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", + "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", + "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", + "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", + "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", + "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", + "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", + "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", + "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", + "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", + "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "peer": true, + "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" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "peer": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "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==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "peer": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.3.0.tgz", + "integrity": "sha512-PAwCvFJ4696XP2qZj+LAn1BWjZaJ6RjG6c7/lkMaUJnkyMS34ucuIsfqYvfskVNvUI27R/u4P1HMYFnlVXG/Ww==", + "dev": true, + "dependencies": { + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "jest-message-util": "30.3.0", + "jest-util": "30.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/core": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.3.0.tgz", + "integrity": "sha512-U5mVPsBxLSO6xYbf+tgkymLx+iAhvZX43/xI1+ej2ZOPnPdkdO1CzDmFKh2mZBn2s4XZixszHeQnzp1gm/DIxw==", + "dev": true, + "dependencies": { + "@jest/console": "30.3.0", + "@jest/pattern": "30.0.1", + "@jest/reporters": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.3.0", + "jest-config": "30.3.0", + "jest-haste-map": "30.3.0", + "jest-message-util": "30.3.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.3.0", + "jest-resolve-dependencies": "30.3.0", + "jest-runner": "30.3.0", + "jest-runtime": "30.3.0", + "jest-snapshot": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "jest-watcher": "30.3.0", + "pretty-format": "30.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/diff-sequences": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.3.0.tgz", + "integrity": "sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==", + "dev": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.3.0.tgz", + "integrity": "sha512-SlLSF4Be735yQXyh2+mctBOzNDx5s5uLv88/j8Qn1wH679PDcwy67+YdADn8NJnGjzlXtN62asGH/T4vWOkfaw==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "jest-mock": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.3.0.tgz", + "integrity": "sha512-76Nlh4xJxk2D/9URCn3wFi98d2hb19uWE1idLsTt2ywhvdOldbw3S570hBgn25P4ICUZ/cBjybrBex2g17IDbg==", + "dev": true, + "dependencies": { + "expect": "30.3.0", + "jest-snapshot": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.3.0.tgz", + "integrity": "sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.3.0.tgz", + "integrity": "sha512-WUQDs8SOP9URStX1DzhD425CqbN/HxUYCTwVrT8sTVBfMvFqYt/s61EK5T05qnHu0po6RitXIvP9otZxYDzTGQ==", + "dev": true, + "dependencies": { + "@jest/types": "30.3.0", + "@sinonjs/fake-timers": "^15.0.0", + "@types/node": "*", + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-util": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.3.0.tgz", + "integrity": "sha512-+owLCBBdfpgL3HU+BD5etr1SvbXpSitJK0is1kiYjJxAAJggYMRQz5hSdd5pq1sSggfxPbw2ld71pt4x5wwViA==", + "dev": true, + "dependencies": { + "@jest/environment": "30.3.0", + "@jest/expect": "30.3.0", + "@jest/types": "30.3.0", + "jest-mock": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.3.0.tgz", + "integrity": "sha512-a09z89S+PkQnL055bVj8+pe2Caed2PBOaczHcXCykW5ngxX9EWx/1uAwncxc/HiU0oZqfwseMjyhxgRjS49qPw==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "@jridgewell/trace-mapping": "^0.3.25", + "@types/node": "*", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^5.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "30.3.0", + "jest-util": "30.3.0", + "jest-worker": "30.3.0", + "slash": "^3.0.0", + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.3.0.tgz", + "integrity": "sha512-ORbRN9sf5PP82v3FXNSwmO1OTDR2vzR2YTaR+E3VkSBZ8zadQE6IqYdYEeFH1NIkeB2HIGdF02dapb6K0Mj05g==", + "dev": true, + "dependencies": { + "@jest/types": "30.3.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "callsites": "^3.1.0", + "graceful-fs": "^4.2.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.3.0.tgz", + "integrity": "sha512-e/52nJGuD74AKTSe0P4y5wFRlaXP0qmrS17rqOMHeSwm278VyNyXE3gFO/4DTGF9w+65ra3lo3VKj0LBrzmgdQ==", + "dev": true, + "dependencies": { + "@jest/console": "30.3.0", + "@jest/types": "30.3.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.3.0.tgz", + "integrity": "sha512-dgbWy9b8QDlQeRZcv7LNF+/jFiiYHTKho1xirauZ7kVwY7avjFF6uTT0RqlgudB5OuIPagFdVtfFMosjVbk1eA==", + "dev": true, + "dependencies": { + "@jest/test-result": "30.3.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.3.0.tgz", + "integrity": "sha512-TLKY33fSLVd/lKB2YI1pH69ijyUblO/BQvCj566YvnwuzoTNr648iE0j22vRvVNk2HsPwByPxATg3MleS3gf5A==", + "dev": true, + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.3.0", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.1", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.3.0", + "jest-regex-util": "30.0.1", + "jest-util": "30.3.0", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/types": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.3.0.tgz", + "integrity": "sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==", + "dev": true, + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@marijn/find-cluster-break": { + "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==", + "dev": true, + "peer": true + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "15.3.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.3.2.tgz", + "integrity": "sha512-mrn35Jl2pCpns+mE3HaZa1yPN5EYCRgiMI+135COjr2hr8Cls9DXqIZ57vZe2cz7y2XVSq92tcs6kGQcT1J8Rw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tybys/wasm-util/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "optional": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/codemirror": { + "version": "5.60.8", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.8.tgz", + "integrity": "sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==", + "dev": true, + "dependencies": { + "@types/tern": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "16.11.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.21.tgz", + "integrity": "sha512-Pf8M1XD9i1ksZEcCP8vuSNwooJ/bZapNmIzpmsMaL+jMI+8mEYU3PKvs+xDNuQcJWF/x24WzY4qxLtB0zNow9A==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "node_modules/@types/tern": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", + "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peer": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "peer": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "peer": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.3.0.tgz", + "integrity": "sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==", + "dev": true, + "dependencies": { + "@jest/transform": "30.3.0", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^7.0.1", + "babel-preset-jest": "30.3.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "dev": true, + "workspaces": [ + "test/babel-8" + ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.3.0.tgz", + "integrity": "sha512-+TRkByhsws6sfPjVaitzadk1I0F5sPvOVUH5tyTSzhePpsGIVrdeunHSw/C36QeocS95OOk8lunc4rlu5Anwsg==", + "dev": true, + "dependencies": { + "@types/babel__core": "^7.20.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.3.0.tgz", + "integrity": "sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "30.3.0", + "babel-preset-current-node-syntax": "^1.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-beta.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.20.tgz", + "integrity": "sha512-1AaXxEPfXT+GvTBJFuy4yXVHWJBXa4OdbIebGN/wX5DlsIkU0+wzGnd2lOzokSk51d5LUmqjgBLRLlypLUqInQ==", + "dev": true, + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001788", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", + "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", + "integrity": "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==", + "dev": true + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "dev": true, + "peer": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "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==", + "dev": true, + "peer": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.340", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.340.tgz", + "integrity": "sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/esbuild": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", + "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.0", + "@esbuild/android-arm": "0.28.0", + "@esbuild/android-arm64": "0.28.0", + "@esbuild/android-x64": "0.28.0", + "@esbuild/darwin-arm64": "0.28.0", + "@esbuild/darwin-x64": "0.28.0", + "@esbuild/freebsd-arm64": "0.28.0", + "@esbuild/freebsd-x64": "0.28.0", + "@esbuild/linux-arm": "0.28.0", + "@esbuild/linux-arm64": "0.28.0", + "@esbuild/linux-ia32": "0.28.0", + "@esbuild/linux-loong64": "0.28.0", + "@esbuild/linux-mips64el": "0.28.0", + "@esbuild/linux-ppc64": "0.28.0", + "@esbuild/linux-riscv64": "0.28.0", + "@esbuild/linux-s390x": "0.28.0", + "@esbuild/linux-x64": "0.28.0", + "@esbuild/netbsd-arm64": "0.28.0", + "@esbuild/netbsd-x64": "0.28.0", + "@esbuild/openbsd-arm64": "0.28.0", + "@esbuild/openbsd-x64": "0.28.0", + "@esbuild/openharmony-arm64": "0.28.0", + "@esbuild/sunos-x64": "0.28.0", + "@esbuild/win32-arm64": "0.28.0", + "@esbuild/win32-ia32": "0.28.0", + "@esbuild/win32-x64": "0.28.0" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "peer": true, + "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" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "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==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "peer": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "peer": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.3.0.tgz", + "integrity": "sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "30.3.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.3.0", + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-util": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/fast-deep-equal": { + "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==", + "dev": true, + "peer": true + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "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==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "peer": true + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fflate": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", + "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==" + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "peer": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "peer": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "peer": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "peer": true + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "peer": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "peer": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/handlebars": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", + "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "peer": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "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==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.3.0.tgz", + "integrity": "sha512-AkXIIFcaazymvey2i/+F94XRnM6TsVLZDhBMLsd1Sf/W0wzsvvpjeyUrCZD6HGG4SDYPgDJDBKeiJTBb10WzMg==", + "dev": true, + "dependencies": { + "@jest/core": "30.3.0", + "@jest/types": "30.3.0", + "import-local": "^3.2.0", + "jest-cli": "30.3.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.3.0.tgz", + "integrity": "sha512-B/7Cny6cV5At6M25EWDgf9S617lHivamL8vl6KEpJqkStauzcG4e+WPfDgMMF+H4FVH4A2PLRyvgDJan4441QA==", + "dev": true, + "dependencies": { + "execa": "^5.1.1", + "jest-util": "30.3.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-circus": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.3.0.tgz", + "integrity": "sha512-PyXq5szeSfR/4f1lYqCmmQjh0vqDkURUYi9N6whnHjlRz4IUQfMcXkGLeEoiJtxtyPqgUaUUfyQlApXWBSN1RA==", + "dev": true, + "dependencies": { + "@jest/environment": "30.3.0", + "@jest/expect": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.3.0", + "jest-matcher-utils": "30.3.0", + "jest-message-util": "30.3.0", + "jest-runtime": "30.3.0", + "jest-snapshot": "30.3.0", + "jest-util": "30.3.0", + "p-limit": "^3.1.0", + "pretty-format": "30.3.0", + "pure-rand": "^7.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-cli": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.3.0.tgz", + "integrity": "sha512-l6Tqx+j1fDXJEW5bqYykDQQ7mQg+9mhWXtnj+tQZrTWYHyHoi6Be8HPumDSA+UiX2/2buEgjA58iJzdj146uCw==", + "dev": true, + "dependencies": { + "@jest/core": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/types": "30.3.0", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "yargs": "^17.7.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.3.0.tgz", + "integrity": "sha512-WPMAkMAtNDY9P/oKObtsRG/6KTrhtgPJoBTmk20uDn4Uy6/3EJnnaZJre/FMT1KVRx8cve1r7/FlMIOfRVWL4w==", + "dev": true, + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/get-type": "30.1.0", + "@jest/pattern": "30.0.1", + "@jest/test-sequencer": "30.3.0", + "@jest/types": "30.3.0", + "babel-jest": "30.3.0", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "jest-circus": "30.3.0", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.3.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.3.0", + "jest-runner": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "parse-json": "^5.2.0", + "pretty-format": "30.3.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "esbuild-register": ">=3.4.0", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esbuild-register": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/jest-config/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-diff": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.3.0.tgz", + "integrity": "sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==", + "dev": true, + "dependencies": { + "@jest/diff-sequences": "30.3.0", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", + "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", + "dev": true, + "dependencies": { + "detect-newline": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-each": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.3.0.tgz", + "integrity": "sha512-V8eMndg/aZ+3LnCJgSm13IxS5XSBM22QSZc9BtPK8Dek6pm+hfUNfwBdvsB3d342bo1q7wnSkC38zjX259qZNA==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "chalk": "^4.1.2", + "jest-util": "30.3.0", + "pretty-format": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.3.0.tgz", + "integrity": "sha512-4i6HItw/JSiJVsC5q0hnKIe/hbYfZLVG9YJ/0pU9Hz2n/9qZe3Rhn5s5CUZA5ORZlcdT/vmAXRMyONXJwPrmYQ==", + "dev": true, + "dependencies": { + "@jest/environment": "30.3.0", + "@jest/fake-timers": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "jest-mock": "30.3.0", + "jest-util": "30.3.0", + "jest-validate": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.3.0.tgz", + "integrity": "sha512-mMi2oqG4KRU0R9QEtscl87JzMXfUhbKaFqOxmjb2CKcbHcUGFrJCBWHmnTiUqi6JcnzoBlO4rWfpdl2k/RfLCA==", + "dev": true, + "dependencies": { + "@jest/types": "30.3.0", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.3.0", + "jest-worker": "30.3.0", + "picomatch": "^4.0.3", + "walker": "^1.0.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" + } + }, + "node_modules/jest-haste-map/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-leak-detector": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.3.0.tgz", + "integrity": "sha512-cuKmUUGIjfXZAiGJ7TbEMx0bcqNdPPI6P1V+7aF+m/FUJqFDxkFR4JqkTu8ZOiU5AaX/x0hZ20KaaIPXQzbMGQ==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.1.0", + "pretty-format": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.3.0.tgz", + "integrity": "sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.3.0", + "pretty-format": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.3.0.tgz", + "integrity": "sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.3.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3", + "pretty-format": "30.3.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-mock": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.3.0.tgz", + "integrity": "sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==", + "dev": true, + "dependencies": { + "@jest/types": "30.3.0", + "@types/node": "*", + "jest-util": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.3.0.tgz", + "integrity": "sha512-NRtTAHQlpd15F9rUR36jqwelbrDV/dY4vzNte3S2kxCKUJRYNd5/6nTSbYiak1VX5g8IoFF23Uj5TURkUW8O5g==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.3.0", + "jest-pnp-resolver": "^1.2.3", + "jest-util": "30.3.0", + "jest-validate": "30.3.0", + "slash": "^3.0.0", + "unrs-resolver": "^1.7.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.3.0.tgz", + "integrity": "sha512-9ev8s3YN6Hsyz9LV75XUwkCVFlwPbaFn6Wp75qnI0wzAINYWY8Fb3+6y59Rwd3QaS3kKXffHXsZMziMavfz/nw==", + "dev": true, + "dependencies": { + "jest-regex-util": "30.0.1", + "jest-snapshot": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runner": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.3.0.tgz", + "integrity": "sha512-gDv6C9LGKWDPLia9TSzZwf4h3kMQCqyTpq+95PODnTRDO0g9os48XIYYkS6D236vjpBir2fF63YmJFtqkS5Duw==", + "dev": true, + "dependencies": { + "@jest/console": "30.3.0", + "@jest/environment": "30.3.0", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.3.0", + "jest-haste-map": "30.3.0", + "jest-leak-detector": "30.3.0", + "jest-message-util": "30.3.0", + "jest-resolve": "30.3.0", + "jest-runtime": "30.3.0", + "jest-util": "30.3.0", + "jest-watcher": "30.3.0", + "jest-worker": "30.3.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.3.0.tgz", + "integrity": "sha512-CgC+hIBJbuh78HEffkhNKcbXAytQViplcl8xupqeIWyKQF50kCQA8J7GeJCkjisC6hpnC9Muf8jV5RdtdFbGng==", + "dev": true, + "dependencies": { + "@jest/environment": "30.3.0", + "@jest/fake-timers": "30.3.0", + "@jest/globals": "30.3.0", + "@jest/source-map": "30.0.1", + "@jest/test-result": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.1.0", + "collect-v8-coverage": "^1.0.2", + "glob": "^10.5.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.3.0", + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.3.0", + "jest-snapshot": "30.3.0", + "jest-util": "30.3.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runtime/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-snapshot": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.3.0.tgz", + "integrity": "sha512-f14c7atpb4O2DeNhwcvS810Y63wEn8O1HqK/luJ4F6M4NjvxmAKQwBUWjbExUtMxWJQ0wVgmCKymeJK6NZMnfQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.3.0", + "@jest/get-type": "30.1.0", + "@jest/snapshot-utils": "30.3.0", + "@jest/transform": "30.3.0", + "@jest/types": "30.3.0", + "babel-preset-current-node-syntax": "^1.2.0", + "chalk": "^4.1.2", + "expect": "30.3.0", + "graceful-fs": "^4.2.11", + "jest-diff": "30.3.0", + "jest-matcher-utils": "30.3.0", + "jest-message-util": "30.3.0", + "jest-util": "30.3.0", + "pretty-format": "30.3.0", + "semver": "^7.7.2", + "synckit": "^0.11.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.3.0.tgz", + "integrity": "sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==", + "dev": true, + "dependencies": { + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-validate": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.3.0.tgz", + "integrity": "sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.3.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.3.0.tgz", + "integrity": "sha512-PJ1d9ThtTR8aMiBWUdcownq9mDdLXsQzJayTk4kmaBRHKvwNQn+ANveuhEBUyNI2hR1TVhvQ8D5kHubbzBHR/w==", + "dev": true, + "dependencies": { + "@jest/test-result": "30.3.0", + "@jest/types": "30.3.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "jest-util": "30.3.0", + "string-length": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-worker": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.3.0.tgz", + "integrity": "sha512-DrCKkaQwHexjRUFTmPzs7sHQe0TSj9nvDALKGdwmK5mW9v7j90BudWirKAJHt3QQ9Dhrg1F7DogPzhChppkJpQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.3.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "peer": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "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==", + "dev": true, + "peer": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "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==", + "dev": true, + "peer": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "peer": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "peer": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "peer": true + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.37", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", + "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/obsidian": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.12.3.tgz", + "integrity": "sha512-HxWqe763dOqzXjnNiHmAJTRERN8KILBSqxDSEqbeSr7W8R8Jxezzbca+nz1LiiqXnMpM8lV2jzAezw3CZ4xNUw==", + "dev": true, + "dependencies": { + "@types/codemirror": "5.60.8", + "moment": "2.29.4" + }, + "peerDependencies": { + "@codemirror/state": "6.5.0", + "@codemirror/view": "6.38.6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "peer": true, + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "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==", + "dev": true, + "peer": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, + "node_modules/parent-module": { + "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==", + "dev": true, + "peer": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", + "integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "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==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-mod": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", + "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==", + "dev": true, + "peer": true + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/synckit": { + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "peer": true + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-jest": { + "version": "29.4.9", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.9.tgz", + "integrity": "sha512-LTb9496gYPMCqjeDLdPrKuXtncudeV1yRZnF4Wo5l3SFi0RYEnYRNgMrFIdg+FHvfzjCyQk1cLncWVqiSX+EvQ==", + "dev": true, + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.9", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.7.4", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <7" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "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" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "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==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "dev": true, + "peer": true + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..6498ee9 --- /dev/null +++ b/package.json @@ -0,0 +1,39 @@ +{ + "name": "obsidian-alchemist", + "version": "1.0.0", + "description": "The Alchemist: A modular super-plugin for TextBundle, Audio conversion, and Data purity.", + "main": "main.js", + "scripts": { + "dev": "node esbuild.config.mjs", + "build": "tsc -noEmit && node esbuild.config.mjs production && cp manifest.json styles.css dist/", + "test": "jest", + "version": "node version-bump.mjs && git add manifest.json versions.json" + }, + "keywords": [ + "obsidian", + "obsidian-plugin", + "textbundle", + "audio", + "converter", + "dataview", + "cleaner" + ], + "author": "Kharizma & Latreia", + "license": "MIT", + "devDependencies": { + "@types/jest": "^30.0.0", + "@types/node": "^16.11.21", + "@typescript-eslint/eslint-plugin": "^5.10.1", + "@typescript-eslint/parser": "^5.10.1", + "builtin-modules": "^3.2.0", + "esbuild": "^0.28.0", + "jest": "^30.3.0", + "obsidian": "latest", + "ts-jest": "^29.4.9", + "tslib": "2.3.1", + "typescript": "^5.9.3" + }, + "dependencies": { + "fflate": "^0.7.3" + } +} diff --git a/settings.ts b/settings.ts new file mode 100644 index 0000000..e46f848 --- /dev/null +++ b/settings.ts @@ -0,0 +1,405 @@ +import { App, PluginSettingTab, Setting } from 'obsidian'; +import AlchemistPlugin from './main'; + +export interface AlchemistSettings { + // Global Feature Toggles + enableTextBundle: boolean; + enableAudioConverter: boolean; + enableDataviewExport: boolean; + enableSmartPaste: boolean; + + // Global Persistence + lastDialogPath: string; + + // Module 1: TextBundle + defaultImportPath: string; + includeImages: boolean; + includeAudio: boolean; + includeVideo: boolean; + includePDF: boolean; + recursionDepth: number; + compressionFormat: 'zip' | 'textpack' | 'textbundle'; + conflictStrategy: 'skip' | 'overwrite' | 'rename'; + restoreFolderStructure: boolean; + + // Module 2: Audio Converter + targetFolderStrategy: 'source' | 'specific' | 'dialog'; + specificTargetFolder: string; + deleteOriginalWebM: boolean; + defaultAudioOutputFormat: 'mp3' | 'wav' | 'ogg' | 'm4a' | 'flac'; + defaultAudioArtist: string; + defaultAudioAlbum: string; + defaultAudioGenre: string; + + // Module 3: Dataview + dataviewExportStrategy: 'vault' | 'dialog'; + dataviewVaultPath: string; + + // Module 4: Smart Paste + stripTrackingParameters: boolean; + cleanMsoHtml: boolean; +} + +export const DEFAULT_SETTINGS: AlchemistSettings = { + enableTextBundle: true, + enableAudioConverter: true, + enableDataviewExport: true, + enableSmartPaste: true, + + lastDialogPath: '', + + defaultImportPath: '', + includeImages: true, + includeAudio: true, + includeVideo: true, + includePDF: true, + recursionDepth: 0, + compressionFormat: 'zip', + conflictStrategy: 'rename', + restoreFolderStructure: true, + + targetFolderStrategy: 'source', + specificTargetFolder: '', + deleteOriginalWebM: false, + defaultAudioOutputFormat: 'mp3', + defaultAudioArtist: 'Alchemist', + defaultAudioAlbum: 'Obsidian Vault', + defaultAudioGenre: 'Voice Note', + + dataviewExportStrategy: 'dialog', + dataviewVaultPath: 'Exports', + + stripTrackingParameters: true, + cleanMsoHtml: true, +} + +export class AlchemistSettingTab extends PluginSettingTab { + plugin: AlchemistPlugin; + + constructor(app: App, plugin: AlchemistPlugin) { + super(app, plugin); + this.plugin = plugin; + } + + display(): void { + const { containerEl } = this; + containerEl.empty(); + containerEl.createEl('h2', { text: 'Alchemist: Central Command' }); + + // --- SECTION: GLOBAL --- + containerEl.createEl('h3', { text: 'Core Modules' }); + + new Setting(containerEl) + .setName('Enable TextBundle') + .setDesc('Export/Import notes as TextBundle.') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.enableTextBundle) + .onChange(async (value) => { + this.plugin.settings.enableTextBundle = value; + await this.plugin.saveSettings(); + this.display(); + })); + + new Setting(containerEl) + .setName('Enable Audio Converter') + .setDesc('Convert WebM recordings to MP3/WAV/OGG (Desktop).') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.enableAudioConverter) + .onChange(async (value) => { + this.plugin.settings.enableAudioConverter = value; + await this.plugin.saveSettings(); + this.display(); + })); + + new Setting(containerEl) + .setName('Enable Dataview Export') + .setDesc('Add CSV export button to Dataview tables.') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.enableDataviewExport) + .onChange(async (value) => { + this.plugin.settings.enableDataviewExport = value; + await this.plugin.saveSettings(); + this.display(); + })); + + new Setting(containerEl) + .setName('Enable Smart Paste') + .setDesc('Clean clipboard content from trackers and junk HTML.') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.enableSmartPaste) + .onChange(async (value) => { + this.plugin.settings.enableSmartPaste = value; + await this.plugin.saveSettings(); + this.display(); + })); + + // --- SECTION: TEXTBUNDLE --- + if (this.plugin.settings.enableTextBundle) { + containerEl.createEl('h3', { text: 'TextBundle Strategy' }); + + new Setting(containerEl) + .setName('Default Import Path') + .setDesc('Folder where TextBundles will be unpacked by default.') + .addText(text => text + .setPlaceholder('e.g. Imports/TextBundle') + .setValue(this.plugin.settings.defaultImportPath) + .onChange(async (value) => { + this.plugin.settings.defaultImportPath = value; + await this.plugin.saveSettings(); + })); + + new Setting(containerEl) + .setName('Include Images') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.includeImages) + .onChange(async (value) => { + this.plugin.settings.includeImages = value; + await this.plugin.saveSettings(); + })); + + new Setting(containerEl) + .setName('Include Audio') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.includeAudio) + .onChange(async (value) => { + this.plugin.settings.includeAudio = value; + await this.plugin.saveSettings(); + })); + + new Setting(containerEl) + .setName('Include Video') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.includeVideo) + .onChange(async (value) => { + this.plugin.settings.includeVideo = value; + await this.plugin.saveSettings(); + })); + + new Setting(containerEl) + .setName('Include PDFs') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.includePDF) + .onChange(async (value) => { + this.plugin.settings.includePDF = value; + await this.plugin.saveSettings(); + })); + + new Setting(containerEl) + .setName('Recursion Depth') + .setDesc('How many levels of linked notes to include (0 = current note only).') + .addSlider(slider => slider + .setLimits(0, 5, 1) + .setValue(this.plugin.settings.recursionDepth) + .setDynamicTooltip() + .onChange(async (value) => { + this.plugin.settings.recursionDepth = value; + await this.plugin.saveSettings(); + })); + + new Setting(containerEl) + .setName('Compression Format') + .setDesc('Target file extension for exports.') + .addDropdown(dropdown => dropdown + .addOption('zip', '.zip (Standard)') + .addOption('textbundle', '.textbundle') + .addOption('textpack', '.textpack') + .setValue(this.plugin.settings.compressionFormat) + .onChange(async (value: any) => { + this.plugin.settings.compressionFormat = value; + await this.plugin.saveSettings(); + })); + + new Setting(containerEl) + .setName('Conflict Strategy') + .setDesc('What to do if a file with the same name already exists during import.') + .addDropdown(dropdown => dropdown + .addOption('rename', 'Auto-rename (Versioning)') + .addOption('skip', 'Skip Existing') + .addOption('overwrite', 'Overwrite (CAUTION)') + .setValue(this.plugin.settings.conflictStrategy) + .onChange(async (value: any) => { + this.plugin.settings.conflictStrategy = value; + await this.plugin.saveSettings(); + })); + + new Setting(containerEl) + .setName('Restore Folder Structure') + .setDesc('Try to recreate the original vault path using metadata.') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.restoreFolderStructure) + .onChange(async (value) => { + this.plugin.settings.restoreFolderStructure = value; + await this.plugin.saveSettings(); + })); + } + + // --- SECTION: AUDIO --- + if (this.plugin.settings.enableAudioConverter) { + containerEl.createEl('h3', { text: 'Audio Transformation' }); + + new Setting(containerEl) + .setName('Target Folder Strategy') + .setDesc('Where to save converted files.') + .addDropdown(dropdown => dropdown + .addOption('source', 'Same as source') + .addOption('specific', 'Specific folder') + .addOption('dialog', 'Always ask with dialog') + .setValue(this.plugin.settings.targetFolderStrategy) + .onChange(async (value: any) => { + this.plugin.settings.targetFolderStrategy = value; + await this.plugin.saveSettings(); + this.display(); // Refresh to show/hide specific folder setting + })); + + if (this.plugin.settings.targetFolderStrategy === 'specific') { + new Setting(containerEl) + .setName('Specific Target Folder') + .addText(text => text + .setValue(this.plugin.settings.specificTargetFolder) + .onChange(async (value) => { + this.plugin.settings.specificTargetFolder = value; + await this.plugin.saveSettings(); + })); + } + + new Setting(containerEl) + .setName('Default Output Format') + .setDesc('Target format for audio conversion.') + .addDropdown(dropdown => dropdown + .addOption('mp3', 'MP3') + .addOption('wav', 'WAV') + .addOption('ogg', 'OGG') + .addOption('m4a', 'M4A') + .addOption('flac', 'FLAC') + .setValue(this.plugin.settings.defaultAudioOutputFormat) + .onChange(async (value: any) => { + this.plugin.settings.defaultAudioOutputFormat = value; + await this.plugin.saveSettings(); + this.display(); + })); + + new Setting(containerEl) + .setName('Delete original WebM') + .setDesc('Remove the original file after successful conversion.') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.deleteOriginalWebM) + .onChange(async (value) => { + this.plugin.settings.deleteOriginalWebM = value; + await this.plugin.saveSettings(); + })); + + containerEl.createEl('h4', { text: 'Default Metadata' }); + + new Setting(containerEl) + .setName('Default Artist') + .addText(text => text + .setValue(this.plugin.settings.defaultAudioArtist) + .onChange(async (value) => { + this.plugin.settings.defaultAudioArtist = value; + await this.plugin.saveSettings(); + })); + + new Setting(containerEl) + .setName('Default Album') + .addText(text => text + .setValue(this.plugin.settings.defaultAudioAlbum) + .onChange(async (value) => { + this.plugin.settings.defaultAudioAlbum = value; + await this.plugin.saveSettings(); + })); + + new Setting(containerEl) + .setName('Default Genre') + .addText(text => text + .setValue(this.plugin.settings.defaultAudioGenre) + .onChange(async (value) => { + this.plugin.settings.defaultAudioGenre = value; + await this.plugin.saveSettings(); + })); + } + + // --- SECTION: DATAVIEW --- + if (this.plugin.settings.enableDataviewExport) { + containerEl.createEl('h3', { text: 'Dataview Export' }); + + new Setting(containerEl) + .setName('Export Strategy') + .setDesc('How to handle CSV generation.') + .addDropdown(dropdown => dropdown + .addOption('dialog', 'System Save Dialog') + .addOption('vault', 'Silent Save to Vault') + .setValue(this.plugin.settings.dataviewExportStrategy) + .onChange(async (value: any) => { + this.plugin.settings.dataviewExportStrategy = value; + await this.plugin.saveSettings(); + this.display(); + })); + + if (this.plugin.settings.dataviewExportStrategy === 'vault') { + new Setting(containerEl) + .setName('Vault Target Folder') + .setDesc('Folder where Dataview CSVs will be saved.') + .addText(text => text + .setPlaceholder('Exports') + .setValue(this.plugin.settings.dataviewVaultPath) + .onChange(async (value) => { + this.plugin.settings.dataviewVaultPath = value; + await this.plugin.saveSettings(); + })); + } + } + + // --- SECTION: SMART PASTE --- + if (this.plugin.settings.enableSmartPaste) { + containerEl.createEl('h3', { text: 'Hygiene & Sanitization (Paste)' }); + + new Setting(containerEl) + .setName('Strip Marketing Trackers') + .setDesc('Remove UTM, fbclid, and other trackers from pasted URLs.') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.stripTrackingParameters) + .onChange(async (value) => { + this.plugin.settings.stripTrackingParameters = value; + await this.plugin.saveSettings(); + })); + + new Setting(containerEl) + .setName('Clean HTML Artifacts') + .setDesc('Remove proprietary meta-tags from Google Docs/MS Office pastes.') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.cleanMsoHtml) + .onChange(async (value) => { + this.plugin.settings.cleanMsoHtml = value; + await this.plugin.saveSettings(); + })); + } + + // --- SECTION: SUPPORT --- + containerEl.createEl('hr'); + const supportDiv = containerEl.createDiv({ cls: 'alchemist-support-container' }); + supportDiv.style.textAlign = 'center'; + supportDiv.style.padding = '20px'; + + supportDiv.createEl('h3', { text: 'Support the Alchemist' }); + supportDiv.createEl('p', { text: 'If you find this tool useful, consider supporting its development.' }); + + const buttonsDiv = supportDiv.createDiv(); + buttonsDiv.style.display = 'flex'; + buttonsDiv.style.justifyContent = 'center'; + buttonsDiv.style.gap = '15px'; + + const kofiBtn = buttonsDiv.createEl('a', { + href: 'https://ko-fi.com/kharizma', + cls: 'alchemist-donate-btn' + }); + kofiBtn.innerText = 'Buy me a coffee'; + kofiBtn.style.cssText = 'background: #29abe0; color: white; padding: 8px 15px; border-radius: 5px; text-decoration: none; font-weight: bold;'; + + const boostyBtn = buttonsDiv.createEl('a', { + href: 'https://boosty.to/kharizma', + cls: 'alchemist-donate-btn' + }); + boostyBtn.innerText = 'Support on Boosty'; + boostyBtn.style.cssText = 'background: #f15f2c; color: white; padding: 8px 15px; border-radius: 5px; text-decoration: none; font-weight: bold;'; + } +} diff --git a/src/core/IAlchemistModule.ts b/src/core/IAlchemistModule.ts new file mode 100644 index 0000000..95fd467 --- /dev/null +++ b/src/core/IAlchemistModule.ts @@ -0,0 +1,23 @@ +import { AlchemistSettings } from '../../settings'; + +export interface AlchemistContext { + app: any; // Obsidian App + settings: AlchemistSettings; + system: ISystemAdapter; + plugin: any; // AlchemistPlugin +} + +export interface IAlchemistModule { + id: string; + load(context: AlchemistContext): Promise; + unload(): Promise; + onSettingsChange(newSettings: AlchemistSettings): Promise; +} + +export interface ISystemAdapter { + fs: any; + path: any; + os: any; + showSaveDialog(options: any): Promise<{ canceled: boolean; filePath?: string }>; + showOpenDialog(options: any): Promise<{ canceled: boolean; filePaths: string[] }>; +} diff --git a/src/core/SystemAdapter.ts b/src/core/SystemAdapter.ts new file mode 100644 index 0000000..4291af9 --- /dev/null +++ b/src/core/SystemAdapter.ts @@ -0,0 +1,31 @@ +import { ISystemAdapter } from './IAlchemistModule'; + +export class ElectronSystemAdapter implements ISystemAdapter { + public fs: any; + public path: any; + public os: any; + private dialog: any; + + constructor() { + const electron = (window as any).require('electron'); + let remote: any; + try { + remote = (window as any).require('@electron/remote'); + } catch (e) { + remote = electron.remote; + } + + this.dialog = remote ? remote.dialog : electron.dialog; + this.fs = (window as any).require('fs'); + this.path = (window as any).require('path'); + this.os = (window as any).require('os'); + } + + async showSaveDialog(options: any): Promise<{ canceled: boolean; filePath?: string }> { + return await this.dialog.showSaveDialog(options); + } + + async showOpenDialog(options: any): Promise<{ canceled: boolean; filePaths: string[] }> { + return await this.dialog.showOpenDialog(options); + } +} diff --git a/src/core/__tests__/SystemAdapter.test.ts b/src/core/__tests__/SystemAdapter.test.ts new file mode 100644 index 0000000..4b470be --- /dev/null +++ b/src/core/__tests__/SystemAdapter.test.ts @@ -0,0 +1,36 @@ +import { ISystemAdapter } from '../IAlchemistModule'; + +export class MockSystemAdapter implements ISystemAdapter { + public fs = { + writeFileSync: jest.fn(), + readFileSync: jest.fn(), + existsSync: jest.fn(), + mkdirSync: jest.fn(), + }; + public path = { + join: (...args: string[]) => args.join('/'), + dirname: (p: string) => p.split('/').slice(0, -1).join('/'), + basename: (p: string) => p.split('/').pop(), + isAbsolute: (p: string) => p.startsWith('/'), + }; + public os = { + tmpdir: () => '/tmp', + platform: () => 'linux', + }; + + async showSaveDialog(options: any) { + return { canceled: false, filePath: '/tmp/test.txt' }; + } + + async showOpenDialog(options: any) { + return { canceled: false, filePaths: ['/tmp/test.txt'] }; + } +} + +describe('SystemAdapter Smoke Test', () => { + it('should be able to instantiate MockSystemAdapter', () => { + const adapter = new MockSystemAdapter(); + expect(adapter).toBeDefined(); + expect(adapter.path.join('a', 'b')).toBe('a/b'); + }); +}); diff --git a/src/features/audio-converter/AudioModule.ts b/src/features/audio-converter/AudioModule.ts new file mode 100644 index 0000000..59c062c --- /dev/null +++ b/src/features/audio-converter/AudioModule.ts @@ -0,0 +1,222 @@ +import { TFile, Notice, normalizePath, FileSystemAdapter } from 'obsidian'; +import { spawn } from 'child_process'; +import { IAlchemistModule, AlchemistContext } from '../../core/IAlchemistModule'; +import { AlchemistSettings } from '../../../settings'; +import { getFfmpegArgs, AudioMetadata } from './logic'; + +export class AudioModule implements IAlchemistModule { + public id = 'audio-converter'; + private context!: AlchemistContext; + private statusBarItem: HTMLElement | null = null; + + async load(context: AlchemistContext): Promise { + this.context = context; + this.statusBarItem = this.context.plugin.addStatusBarItem(); + if (this.statusBarItem) this.statusBarItem.hide(); + this.registerEvents(); + } + + async unload(): Promise { + // Events are cleaned up automatically + } + + async onSettingsChange(newSettings: AlchemistSettings): Promise { + this.context.settings = newSettings; + } + + private registerEvents() { + // Single file menu + this.context.plugin.registerEvent( + this.context.app.workspace.on('file-menu', (menu: any, abstractFile: any) => { + if (!this.context.settings.enableAudioConverter) return; + const format = this.context.settings.defaultAudioOutputFormat || 'mp3'; + + if (abstractFile instanceof TFile) { + const ext = abstractFile.extension.toLowerCase(); + const audioExtensions = ['webm', 'ogg', 'wav', 'mp3', 'm4a', 'flac', 'aac', 'opus']; + + if (audioExtensions.includes(ext) && ext !== format) { + menu.addItem((item: any) => { + item + .setTitle(`Alchemist: Convert to ${format.toUpperCase()}`) + .setIcon('music') + .onClick(() => this.runConversion([abstractFile], format)); + }); + } + } + }) + ); + + // Multiple files menu + this.context.plugin.registerEvent( + this.context.app.workspace.on('files-menu', (menu: any, files: any[]) => { + if (!this.context.settings.enableAudioConverter) return; + const audioExtensions = ['webm', 'ogg', 'wav', 'mp3', 'm4a', 'flac', 'aac', 'opus']; + const audioFiles = files.filter(f => f instanceof TFile && audioExtensions.includes(f.extension.toLowerCase()) && f.extension.toLowerCase() !== format); + if (audioFiles.length <= 1) return; + + const format = this.context.settings.defaultAudioOutputFormat || 'mp3'; + menu.addItem((item: any) => { + item + .setTitle(`Alchemist: Convert ${audioFiles.length} files to ${format.toUpperCase()}`) + .setIcon('music') + .onClick(() => this.runConversion(audioFiles, format)); + }); + }) + ); + } + + private async runConversion(files: TFile[], format: string) { + if (files.length === 0) return; + + const total = files.length; + let processed = 0; + + if (this.statusBarItem) { + this.statusBarItem.show(); + this.updateStatus(processed, total); + } + + new Notice(`Alchemist: Converting ${total} file(s)...`); + + for (const file of files) { + try { + const metadata = await this.extractMetadata(file); + await this.convert(file, format, metadata); + processed++; + this.updateStatus(processed, total); + } catch (e) { + console.error(`Alchemist Audio Error (${file.name}):`, e); + new Notice(`Conversion failed for ${file.name}: ${(e as Error).message}`); + } + } + + if (this.statusBarItem) this.statusBarItem.hide(); + new Notice(`Alchemist: Finished processing ${processed}/${total} files.`); + } + + private updateStatus(current: number, total: number) { + if (!this.statusBarItem) return; + this.statusBarItem.setText(`๐Ÿงช Alchemist: ${current}/${total} [${Math.round((current / total) * 100)}%]`); + } + + private async extractMetadata(file: TFile): Promise { + const metadata: AudioMetadata = { + title: file.basename, + artist: this.context.settings.defaultAudioArtist, + album: this.context.settings.defaultAudioAlbum, + genre: this.context.settings.defaultAudioGenre, + date: new Date().getFullYear().toString() + }; + + // Try to find a companion .md file with the same name + const mdPath = file.path.replace(/\.[^/.]+$/, ".md"); + const mdFile = this.context.app.vault.getAbstractFileByPath(mdPath); + + if (mdFile instanceof TFile) { + const cache = this.context.app.metadataCache.getFileCache(mdFile); + const frontmatter = cache?.frontmatter; + + if (frontmatter) { + if (frontmatter.title) metadata.title = frontmatter.title; + if (frontmatter.artist) metadata.artist = frontmatter.artist; + if (frontmatter.album) metadata.album = frontmatter.album; + if (frontmatter.genre) metadata.genre = frontmatter.genre; + if (frontmatter.date) metadata.date = String(frontmatter.date); + + // Fallback for tags -> genre + if (!frontmatter.genre && frontmatter.tags) { + const tags = Array.isArray(frontmatter.tags) ? frontmatter.tags : [frontmatter.tags]; + if (tags.length > 0) metadata.genre = tags[0]; + } + } + } + + return metadata; + } + + private async convert(file: TFile, format: string, metadata: AudioMetadata): Promise { + return new Promise(async (resolve, reject) => { + const system = this.context.system; + const app = this.context.app; + const settings = this.context.settings; + + const adapter = app.vault.adapter as FileSystemAdapter; + const basePath = adapter.getBasePath(); + const inputPath = system.path.join(basePath, file.path); + + const tempOutputPath = system.path.join(system.os.tmpdir(), `alchemist_${Date.now()}.${format}`); + const args = getFfmpegArgs(inputPath, tempOutputPath, format, metadata); + + const child = spawn('ffmpeg', args); + + let stderr = ''; + child.stderr.on('data', (data) => { stderr += data.toString(); }); + + child.on('close', async (code) => { + if (code === 0) { + try { + const data = system.fs.readFileSync(tempOutputPath); + const outputName = file.basename + '.' + format; + let finalVaultPath: string; + + switch (settings.targetFolderStrategy) { + case 'specific': { + const folder = settings.specificTargetFolder || ''; + finalVaultPath = normalizePath(`${folder}/${outputName}`); + if (folder) { + const existing = app.vault.getAbstractFileByPath(folder); + if (!existing) await app.vault.createFolder(folder); + } + break; + } + case 'dialog': { + const result = await system.showSaveDialog({ + title: 'Save Converted Audio', + defaultPath: system.path.join(settings.lastDialogPath, outputName), + filters: [{ name: format.toUpperCase(), extensions: [format] }] + }); + if (result.canceled || !result.filePath) { + system.fs.unlinkSync(tempOutputPath); + resolve(); + return; + } + settings.lastDialogPath = system.path.dirname(result.filePath); + await this.context.plugin.saveSettings(); + system.fs.writeFileSync(result.filePath, data); + system.fs.unlinkSync(tempOutputPath); + if (settings.deleteOriginalWebM && file.extension === 'webm') { + await app.vault.trash(file, true); + } + resolve(); + return; + } + default: // 'source' + finalVaultPath = file.path.replace(new RegExp(`\\.${file.extension}$`), `.${format}`); + } + + const existingFile = app.vault.getAbstractFileByPath(finalVaultPath); + if (existingFile instanceof TFile) { + await app.vault.modifyBinary(existingFile, data.buffer); + } else { + await app.vault.createBinary(finalVaultPath, data.buffer); + } + + if (settings.deleteOriginalWebM && file.extension === 'webm') { + await app.vault.trash(file, true); + } + + system.fs.unlinkSync(tempOutputPath); + resolve(); + } catch (e) { + reject(e); + } + } else { + reject(new Error(`FFmpeg failed: ${stderr}`)); + } + }); + + child.on('error', (err) => reject(err)); + }); + } +} diff --git a/src/features/audio-converter/__tests__/logic.test.ts b/src/features/audio-converter/__tests__/logic.test.ts new file mode 100644 index 0000000..a726a40 --- /dev/null +++ b/src/features/audio-converter/__tests__/logic.test.ts @@ -0,0 +1,27 @@ +import { getFfmpegArgs } from '../logic'; + +describe('Audio Logic: getFfmpegArgs', () => { + it('should generate basic args for mp3', () => { + const args = getFfmpegArgs('input.webm', 'output.mp3', 'mp3', {}); + expect(args).toContain('input.webm'); + expect(args).toContain('output.mp3'); + expect(args).toContain('libmp3lame'); + }); + + it('should include metadata args if provided', () => { + const metadata = { title: 'Test Title', artist: 'Test Artist' }; + const args = getFfmpegArgs('in.wav', 'out.mp3', 'mp3', metadata); + expect(args).toContain('title=Test Title'); + expect(args).toContain('artist=Test Artist'); + }); + + it('should set overwrite flag', () => { + const args = getFfmpegArgs('in.wav', 'out.wav', 'wav', {}); + expect(args).toContain('-y'); + }); + + it('should use pcm_s16le for wav', () => { + const args = getFfmpegArgs('in.webm', 'out.wav', 'wav', {}); + expect(args).toContain('pcm_s16le'); + }); +}); diff --git a/src/features/audio-converter/logic.ts b/src/features/audio-converter/logic.ts new file mode 100644 index 0000000..eaae111 --- /dev/null +++ b/src/features/audio-converter/logic.ts @@ -0,0 +1,47 @@ +/** + * Pure logic for Audio Converter FFmpeg command generation. + * Zero dependencies on Obsidian API or System. + */ + +export interface AudioMetadata { + title?: string; + artist?: string; + date?: string; + genre?: string; + album?: string; +} + +/** + * Generates the FFmpeg command arguments for conversion and metadata injection. + */ +export function getFfmpegArgs( + inputPath: string, + outputPath: string, + format: string, + metadata: AudioMetadata +): string[] { + const args = ['-i', inputPath]; + + // Metadata injection + if (metadata.title) args.push('-metadata', `title=${metadata.title}`); + if (metadata.artist) args.push('-metadata', `artist=${metadata.artist}`); + if (metadata.date) args.push('-metadata', `date=${metadata.date}`); + if (metadata.genre) args.push('-metadata', `genre=${metadata.genre}`); + if (metadata.album) args.push('-metadata', `album=${metadata.album}`); + + // Codec settings based on target format + if (format === 'mp3') { + args.push('-c:a', 'libmp3lame', '-q:a', '2'); + } else if (format === 'wav') { + args.push('-c:a', 'pcm_s16le'); + } else if (format === 'ogg') { + args.push('-c:a', 'libvorbis', '-q:a', '4'); + } else if (format === 'flac') { + args.push('-c:a', 'flac'); + } else if (format === 'm4a') { + args.push('-c:a', 'aac', '-b:a', '192k'); + } + + args.push('-y', outputPath); + return args; +} diff --git a/src/features/dataview-export/DataviewModule.ts b/src/features/dataview-export/DataviewModule.ts new file mode 100644 index 0000000..aa12694 --- /dev/null +++ b/src/features/dataview-export/DataviewModule.ts @@ -0,0 +1,146 @@ +import { Notice, TFile, TFolder, normalizePath } from 'obsidian'; +import { IAlchemistModule, AlchemistContext } from '../../core/IAlchemistModule'; +import { AlchemistSettings } from '../../../settings'; +import { escapeCsvCell } from './logic'; + +export class DataviewModule implements IAlchemistModule { + public id = 'dataview-export'; + private context!: AlchemistContext; + private observer: MutationObserver | null = null; + private injectTimeout: NodeJS.Timeout | null = null; + + async load(context: AlchemistContext): Promise { + this.context = context; + this.setupGlobalObserver(); + this.start(); + } + + async unload(): Promise { + this.stop(); + } + + async onSettingsChange(newSettings: AlchemistSettings): Promise { + const wasEnabled = this.context.settings.enableDataviewExport; + this.context.settings = newSettings; + + if (wasEnabled !== newSettings.enableDataviewExport) { + if (newSettings.enableDataviewExport) this.start(); + else this.stop(); + } + } + + private setupGlobalObserver() { + this.observer = new MutationObserver(() => { + if (!this.context.settings.enableDataviewExport) return; + + if (this.injectTimeout) clearTimeout(this.injectTimeout); + this.injectTimeout = setTimeout(() => { + this.injectAll(); + }, 300); + }); + } + + private start() { + if (this.context.settings.enableDataviewExport && this.observer) { + this.observer.observe(document.body, { childList: true, subtree: true }); + this.injectAll(); + } + } + + private stop() { + if (this.observer) { + this.observer.disconnect(); + } + if (this.injectTimeout) clearTimeout(this.injectTimeout); + document.querySelectorAll('.alchemist-export-btn').forEach(btn => btn.remove()); + } + + private injectAll() { + const isDataviewEnabled = (this.context.app as any).plugins?.enabledPlugins?.has('dataview'); + if (!isDataviewEnabled) return; + + const containers = document.querySelectorAll('.block-language-dataview, .dataview.table-view-table, .dataview-container'); + containers.forEach(c => this.injectButton(c as HTMLElement)); + } + + private injectButton(container: HTMLElement) { + if (container.querySelector('.alchemist-export-btn')) return; + if (!container.querySelector('table') && !container.classList.contains('block-language-dataview')) return; + + const btn = document.createElement('button'); + btn.className = 'alchemist-export-btn clickable-icon'; + btn.innerText = '๐Ÿ’พ CSV'; + btn.style.cssText = 'position: absolute; right: 10px; top: 10px; z-index: 100; font-size: 0.7em; opacity: 0.6;'; + + btn.addEventListener('mouseenter', () => btn.style.opacity = '1'); + btn.addEventListener('mouseleave', () => btn.style.opacity = '0.6'); + + btn.onclick = (e) => { + e.preventDefault(); + e.stopPropagation(); + this.exportTable(container); + }; + + container.appendChild(btn); + if (getComputedStyle(container).position === 'static') { + container.style.position = 'relative'; + } + } + + private async exportTable(el: HTMLElement) { + const table = el.querySelector('table'); + if (!table) { + new Notice('No table found to export'); + return; + } + + const rows = Array.from(table.querySelectorAll('tr')); + const csvRows = rows.map(row => { + const cells = Array.from(row.querySelectorAll('th, td')); + return cells.map(cell => escapeCsvCell((cell as HTMLElement).innerText)).join(','); + }); + + const sourceFile = this.context.app.workspace.getActiveFile(); + csvRows.push(''); // Empty row separation + csvRows.push(`"Source","[[${sourceFile?.path || 'unknown'}]]"`); + csvRows.push(`"Exported","${new Date().toLocaleString()}"`); + + await this.handleSave(csvRows.join('\n')); + } + + private async handleSave(content: string) { + const settings = this.context.settings; + + if (settings.dataviewExportStrategy === 'vault') { + const folderPath = normalizePath(settings.dataviewVaultPath || 'Exports'); + await this.ensureFolder(folderPath); + + const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); + const fileName = `dataview_export_${timestamp}.csv`; + const fullPath = `${folderPath}/${fileName}`; + + await this.context.app.vault.create(fullPath, content); + new Notice(`CSV Saved to Vault: ${fullPath}`); + } else { + const result = await this.context.system.showSaveDialog({ + title: 'Export Dataview to CSV', + defaultPath: this.context.system.path.join(this.context.settings.lastDialogPath, 'dataview_export.csv'), + filters: [{ name: 'CSV', extensions: ['csv'] }] + }); + + if (!result.canceled && result.filePath) { + this.context.settings.lastDialogPath = this.context.system.path.dirname(result.filePath); + await this.context.plugin.saveSettings(); + this.context.system.fs.writeFileSync(result.filePath, content); + new Notice('CSV Exported Successfully'); + } + } + } + + private async ensureFolder(path: string) { + const folder = this.context.app.vault.getAbstractFileByPath(path); + if (folder instanceof TFolder) return; + + await this.context.app.vault.createFolder(path); + } +} diff --git a/src/features/dataview-export/__tests__/logic.test.ts b/src/features/dataview-export/__tests__/logic.test.ts new file mode 100644 index 0000000..dedcfc0 --- /dev/null +++ b/src/features/dataview-export/__tests__/logic.test.ts @@ -0,0 +1,31 @@ +import { escapeCsvCell, arrayToCsv } from '../logic'; + +describe('Dataview Logic: escapeCsvCell', () => { + it('should escape double quotes', () => { + expect(escapeCsvCell('Hello "World"')).toBe('"Hello ""World"""'); + }); + + it('should wrap in quotes if contains comma', () => { + expect(escapeCsvCell('Hello, World')).toBe('"Hello, World"'); + }); + + it('should wrap in quotes if contains newline', () => { + expect(escapeCsvCell('Line 1\nLine 2')).toBe('"Line 1\nLine 2"'); + }); + + it('should return empty string for null/undefined', () => { + expect(escapeCsvCell('')).toBe(''); + }); +}); + +describe('Dataview Logic: arrayToCsv', () => { + it('should convert 2D array to CSV', () => { + const data = [ + ['Name', 'Age'], + ['Alice', '30'], + ['Bob, the Great', '25'] + ]; + const expected = 'Name,Age\nAlice,30\n"Bob, the Great",25'; + expect(arrayToCsv(data)).toBe(expected); + }); +}); diff --git a/src/features/dataview-export/logic.ts b/src/features/dataview-export/logic.ts new file mode 100644 index 0000000..55e6264 --- /dev/null +++ b/src/features/dataview-export/logic.ts @@ -0,0 +1,26 @@ +/** + * Pure logic for Dataview CSV export. + * Zero dependencies on DOM or Obsidian API. + */ + +/** + * Escapes a cell value for RFC-4180 CSV compliance. + */ +export function escapeCsvCell(text: string): string { + if (!text) return ''; + let result = text.trim(); + if (result.includes('"')) { + result = result.replace(/"/g, '""'); + } + if (result.includes(',') || result.includes('\n') || result.includes('"')) { + result = `"${result}"`; + } + return result; +} + +/** + * Converts a 2D array of strings into a CSV string. + */ +export function arrayToCsv(data: string[][]): string { + return data.map(row => row.map(escapeCsvCell).join(',')).join('\n'); +} diff --git a/src/features/paste-cleaner/SmartPasteModule.ts b/src/features/paste-cleaner/SmartPasteModule.ts new file mode 100644 index 0000000..712629b --- /dev/null +++ b/src/features/paste-cleaner/SmartPasteModule.ts @@ -0,0 +1,68 @@ +import { Editor, htmlToMarkdown, Notice } from 'obsidian'; +import { IAlchemistModule, AlchemistContext } from '../../core/IAlchemistModule'; +import { AlchemistSettings } from '../../../settings'; +import { containsTrackers, stripTrackers, purifyHtmlStructure } from './logic'; + +export class SmartPasteModule implements IAlchemistModule { + public id = 'smart-paste'; + private context!: AlchemistContext; + + async load(context: AlchemistContext): Promise { + this.context = context; + this.registerPasteHandler(); + this.registerCommands(); + } + + async unload(): Promise { + // Commands and events are automatically cleaned up if registered via plugin + } + + async onSettingsChange(newSettings: AlchemistSettings): Promise { + this.context.settings = newSettings; + } + + private registerCommands() { + this.context.plugin.addCommand({ + id: 'clean-trackers-in-document', + name: 'Clean trackers in current document', + editorCallback: (editor: Editor) => { + const content = editor.getValue(); + const cleaned = stripTrackers(content); + if (content !== cleaned) { + editor.setValue(cleaned); + new Notice('Alchemist: Document cleaned from trackers'); + } else { + new Notice('Alchemist: No trackers found'); + } + } + }); + } + + private registerPasteHandler() { + this.context.plugin.registerEvent( + this.context.app.workspace.on('editor-paste', async (evt: ClipboardEvent, editor: Editor) => { + if (!this.context.settings.enableSmartPaste) return; + + const clipboardData = evt.clipboardData; + if (!clipboardData) return; + + const text = clipboardData.getData('text/plain')?.trim() || ''; + + // SURGICAL INTERCEPTION: Only intercept pure URLs + const urlRegex = /^(https?:\/\/[^\s"'>]+)$/; + if (text.match(urlRegex) && this.context.settings.stripTrackingParameters) { + const cleanUrl = stripTrackers(text); + if (cleanUrl !== text) { + evt.preventDefault(); + editor.replaceSelection(cleanUrl); + new Notice('Alchemist: URL cleaned'); + } + } + + // Note: We no longer intercept rich HTML pastes to avoid breaking + // Obsidian's native formatting (like code blocks or auto-linking). + // Users can use the "Clean trackers in current document" command instead. + }) + ); + } +} diff --git a/src/features/paste-cleaner/__tests__/logic.test.ts b/src/features/paste-cleaner/__tests__/logic.test.ts new file mode 100644 index 0000000..f26cce1 --- /dev/null +++ b/src/features/paste-cleaner/__tests__/logic.test.ts @@ -0,0 +1,41 @@ +import { containsTrackers, stripTrackers, purifyHtmlStructure } from '../logic'; + +describe('SmartPaste Logic: stripTrackers', () => { + it('should remove UTM parameters', () => { + const url = 'https://example.com/page?utm_source=google&utm_medium=cpc&id=123'; + const expected = 'https://example.com/page?id=123'; + expect(stripTrackers(url)).toBe(expected); + }); + + it('should remove fbclid', () => { + const url = 'https://example.com/?fbclid=IwAR123'; + const expected = 'https://example.com/'; + expect(stripTrackers(url)).toBe(expected); + }); + + it('should handle multiple URLs in text', () => { + const text = 'Check out https://site1.com?utm_source=x and https://site2.com?gclid=y'; + const expected = 'Check out https://site1.com/ and https://site2.com/'; + expect(stripTrackers(text)).toBe(expected); + }); + + it('should handle & entities', () => { + const url = 'https://example.com/?a=1&utm_source=2'; + const expected = 'https://example.com/?a=1'; + expect(stripTrackers(url)).toBe(expected); + }); +}); + +describe('SmartPaste Logic: purifyHtmlStructure', () => { + it('should remove docs-internal-guid', () => { + const html = 'Hello'; + const expected = 'Hello'; + expect(purifyHtmlStructure(html)).toBe(expected); + }); + + it('should remove zero-width spaces', () => { + const html = 'H\u200Bello'; + const expected = 'Hello'; + expect(purifyHtmlStructure(html)).toBe(expected); + }); +}); diff --git a/src/features/paste-cleaner/logic.ts b/src/features/paste-cleaner/logic.ts new file mode 100644 index 0000000..054360d --- /dev/null +++ b/src/features/paste-cleaner/logic.ts @@ -0,0 +1,70 @@ +/** + * Pure logic for Smart Paste cleaning. + * Zero dependencies on Obsidian API. + */ + +const BLACKLIST = [ + 'utm_', 'fbclid', 'gclid', 'yclid', 'msclkid', 'mc_cid', 'mc_eid', + '_hsenc', '_hsmi', 'sca_esv', 'sxsrf', 'ei', 'biw', 'bih', 'oq', + 'gs_lp', 'sclient', 'ved', 'uact' +]; + +/** + * Checks if a string contains any tracking parameters. + */ +export function containsTrackers(input: string): boolean { + if (!input) return false; + return BLACKLIST.some(b => input.toLowerCase().includes(b)); +} + +/** + * Strips tracking parameters from all URLs found in the text. + */ +export function stripTrackers(input: string): string { + const urlRegex = /(https?:\/\/[^\s"'>]+)/g; + + return input.replace(urlRegex, (url) => { + try { + // Handle HTML encoded entities + const decodedUrl = url.replace(/&/g, '&'); + const urlObj = new URL(decodedUrl); + const params = urlObj.searchParams; + + const toRemove: string[] = []; + params.forEach((_, key) => { + if (BLACKLIST.some(b => key.toLowerCase().startsWith(b))) { + toRemove.push(key); + } + }); + + if (toRemove.length > 0) { + toRemove.forEach(k => params.delete(k)); + return urlObj.toString(); + } + return url; + } catch (e) { + return url; + } + }); +} + +/** + * Sanitizes HTML content structure and removes invisible trackers. + * (Note: Uses DOMParser which is available in Obsidian/Electron but not in pure Node) + */ +export function purifyHtmlStructure(html: string): string { + // Structural Cleaning (MS Office / Google Docs noise) + let content = html; + + // Remove zero-width spaces + content = content.replace(/[\u200B-\u200D\uFEFF]/g, ''); + + // Clean specific junk IDs and styles + content = content.replace(/\sid="docs-internal-guid-[^"]*"/g, ''); + content = content.replace(/\sstyle="[^"]*"/g, ''); + + // Remove double spaces and non-breaking spaces + content = content.replace(/ /g, ' ').replace(/\s\s+/g, ' '); + + return content.trim(); +} diff --git a/src/features/textbundle/TextBundleModule.ts b/src/features/textbundle/TextBundleModule.ts new file mode 100644 index 0000000..3e39e9f --- /dev/null +++ b/src/features/textbundle/TextBundleModule.ts @@ -0,0 +1,191 @@ +import { TFile, TFolder, Notice } from 'obsidian'; +import { IAlchemistModule, AlchemistContext } from '../../core/IAlchemistModule'; +import { AlchemistSettings } from '../../../settings'; +import { TextBundleFeature } from './collector'; +import { TextBundlePacker } from './packer'; +import { TextBundleImporter } from './importer'; + +export class TextBundleModule implements IAlchemistModule { + public id = 'textbundle'; + private context!: AlchemistContext; + + private collector!: TextBundleFeature; + private packer!: TextBundlePacker; + private importer!: TextBundleImporter; + + async load(context: AlchemistContext): Promise { + this.context = context; + this.collector = new TextBundleFeature(context.app, context.settings); + this.packer = new TextBundlePacker(context.app); + this.importer = new TextBundleImporter(context.app, context.settings, context.system); + + this.registerCommands(); + this.registerEvents(); + this.registerRibbonIcons(); + } + + async unload(): Promise { + // Clean up if necessary + } + + async onSettingsChange(newSettings: AlchemistSettings): Promise { + this.context.settings = newSettings; + } + + private registerRibbonIcons() { + this.context.plugin.addRibbonIcon('package-plus', 'Alchemist: Import TextBundle', () => { + if (!this.context.settings.enableTextBundle) { + new Notice('TextBundle module is disabled in settings.'); + return; + } + this.runImport(); + }); + } + + private registerCommands() { + this.context.plugin.addCommand({ + id: 'import-textbundle', + name: 'Import TextBundle', + callback: () => { + if (!this.context.settings.enableTextBundle) return; + this.runImport(); + } + }); + + this.context.plugin.addCommand({ + id: 'export-current-textbundle', + name: 'Export current file as TextBundle', + checkCallback: (checking: boolean) => { + if (!this.context.settings.enableTextBundle) return false; + const activeFile = this.context.app.workspace.getActiveFile(); + if (activeFile) { + if (!checking) this.runExport(activeFile); + return true; + } + return false; + } + }); + } + + private registerEvents() { + this.context.plugin.registerEvent( + this.context.app.workspace.on('file-menu', (menu: any, abstractFile: any) => { + if (!this.context.settings.enableTextBundle) return; + + if (abstractFile instanceof TFile && abstractFile.extension === 'md') { + menu.addItem((item: any) => { + item + .setTitle('Alchemist: Export as TextBundle') + .setIcon('package') + .onClick(() => this.runExport(abstractFile)); + }); + } else if (abstractFile instanceof TFolder) { + menu.addItem((item: any) => { + item + .setTitle('Alchemist: Export folder as TextBundle') + .setIcon('package') + .onClick(async () => { + const files: TFile[] = []; + const collect = (f: any) => { + if (f instanceof TFile && f.extension === 'md') files.push(f); + else if (f instanceof TFolder) f.children.forEach(collect); + }; + collect(abstractFile); + + if (files.length === 0) { + new Notice('No markdown files found in this folder.'); + return; + } + + // Bulk Export Strategy: Ask for a folder once + const result = await this.context.system.showOpenDialog({ + title: 'Select Destination for Bulk Export', + defaultPath: this.context.settings.lastDialogPath, + properties: ['openDirectory', 'createDirectory'] + }); + + if (!result.canceled && result.filePaths.length > 0) { + const targetDir = result.filePaths[0]; + this.context.settings.lastDialogPath = targetDir; + await this.context.plugin.saveSettings(); + + new Notice(`Bulk Exporting ${files.length} notes...`); + let successCount = 0; + for (const f of files) { + try { + const context = await this.collector.collectResources(f); + const blob = await this.packer.pack(context); + const extension = this.context.settings.compressionFormat || 'textbundle'; + const fullPath = this.context.system.path.join(targetDir, `${f.basename}.${extension}`); + + this.context.system.fs.writeFileSync(fullPath, Buffer.from(blob)); + successCount++; + } catch (e) { + console.error(`Export failed for ${f.name}:`, e); + } + } + new Notice(`Successfully exported ${successCount}/${files.length} notes to ${targetDir}`); + } + }); + }); + + menu.addItem((item: any) => { + item + .setTitle('Alchemist: Import into here') + .setIcon('package-plus') + .onClick(() => this.runImport(abstractFile.path)); + }); + } + }) + ); + } + + private async runImport(targetPath?: string) { + const result = await this.context.system.showOpenDialog({ + title: targetPath ? `Import into ${targetPath}` : 'Import TextBundle', + defaultPath: this.context.settings.lastDialogPath, + filters: [{ name: 'TextBundle', extensions: ['textbundle', 'zip', 'textpack'] }], + properties: ['openFile'] + }); + + if (!result.canceled && result.filePaths.length > 0) { + const filePath = result.filePaths[0]; + this.context.settings.lastDialogPath = this.context.system.path.dirname(filePath); + await this.context.plugin.saveSettings(); + const sourceName = filePath.split(/[\\/]/).pop()?.replace(/\.(zip|textpack|textbundle)$/i, '') || 'Imported_Note'; + + try { + const data = this.context.system.fs.readFileSync(filePath); + await this.importer.importZip(data, targetPath, sourceName); + new Notice('Successfully imported TextBundle'); + } catch (e) { + console.error('Alchemist Import Error:', e); + new Notice(`Import failed: ${(e as Error).message}`); + } + } + } + + private async runExport(file: TFile) { + try { + const context = await this.collector.collectResources(file); + const blob = await this.packer.pack(context); + const extension = this.context.settings.compressionFormat || 'textbundle'; + + const result = await this.context.system.showSaveDialog({ + title: 'Save TextBundle', + defaultPath: this.context.system.path.join(this.context.settings.lastDialogPath, `${file.basename}.${extension}`), + filters: [{ name: 'TextBundle', extensions: [extension, 'zip'] }] + }); + + if (!result.canceled && result.filePath) { + this.context.settings.lastDialogPath = this.context.system.path.dirname(result.filePath); + await this.context.plugin.saveSettings(); + this.context.system.fs.writeFileSync(result.filePath, Buffer.from(blob)); + new Notice(`Successfully exported: ${file.basename}`); + } + } catch (e) { + console.error('Alchemist Export Error:', e); + new Notice(`Export failed: ${(e as Error).message}`); + } + } +} diff --git a/src/features/textbundle/__tests__/logic.test.ts b/src/features/textbundle/__tests__/logic.test.ts new file mode 100644 index 0000000..502a14f --- /dev/null +++ b/src/features/textbundle/__tests__/logic.test.ts @@ -0,0 +1,44 @@ +import { transformMarkdownLinks, LinkResolver } from '../logic'; + +describe('TextBundle Logic: transformMarkdownLinks', () => { + const mockResolver: LinkResolver = { + resolveAsset: (link: string) => { + if (link === 'image.png') return 'image.png'; + if (link === 'photo') return 'real_photo.jpg'; + return null; + }, + resolveNote: (link: string) => { + if (link === 'Other Note') return '../Other Note.textbundle/text.md'; + return null; + } + }; + + it('should transform simple embeds', () => { + const input = 'Check this out: ![[image.png]]'; + const expected = 'Check this out: ![image.png](assets/image.png)'; + expect(transformMarkdownLinks(input, mockResolver)).toBe(expected); + }); + + it('should transform embeds with aliases', () => { + const input = 'Check this out: ![[photo|My Cool Photo]]'; + const expected = 'Check this out: ![My Cool Photo](assets/real_photo.jpg)'; + expect(transformMarkdownLinks(input, mockResolver)).toBe(expected); + }); + + it('should transform regular links to assets', () => { + const input = 'Download [[image.png]]'; + const expected = 'Download [image.png](assets/image.png)'; + expect(transformMarkdownLinks(input, mockResolver)).toBe(expected); + }); + + it('should transform links to other notes in TextPack', () => { + const input = 'See [[Other Note]]'; + const expected = 'See [Other Note](../Other Note.textbundle/text.md)'; + expect(transformMarkdownLinks(input, mockResolver)).toBe(expected); + }); + + it('should not transform unknown links', () => { + const input = 'See [[Unknown Note]] and ![[unknown.png]]'; + expect(transformMarkdownLinks(input, mockResolver)).toBe(input); + }); +}); diff --git a/src/features/textbundle/collector.ts b/src/features/textbundle/collector.ts new file mode 100644 index 0000000..52b195f --- /dev/null +++ b/src/features/textbundle/collector.ts @@ -0,0 +1,105 @@ +import { TFile, App } from 'obsidian'; +import { AlchemistSettings } from '../../../settings'; + +export interface TextBundleContext { + visitedFiles: Set; + assetMap: Map; // originalPath -> bundleName + assets: Map; // bundleName -> TFile + notes: TFile[]; +} + +export class TextBundleFeature { + app: App; + settings: AlchemistSettings; + + constructor(app: App, settings: AlchemistSettings) { + this.app = app; + this.settings = settings; + } + + /** + * Collects all files (note itself + assets + linked notes) for TextBundle export. + */ + async collectResources(startFile: TFile): Promise { + const context: TextBundleContext = { + visitedFiles: new Set(), + assetMap: new Map(), + assets: new Map(), + notes: [] + }; + + await this.traverse(startFile, context, 0); + return context; + } + + private async traverse(file: TFile, context: TextBundleContext, depth: number) { + if (context.visitedFiles.has(file.path)) return; + context.visitedFiles.add(file.path); + + if (file.extension === 'md') { + context.notes.push(file); + + const cache = this.app.metadataCache.getFileCache(file); + if (!cache) return; + + // Collect embeds (images, pdfs, audio, etc.) + if (cache.embeds) { + for (const embed of cache.embeds) { + const assetFile = this.app.metadataCache.getFirstLinkpathDest(embed.link, file.path); + if (assetFile instanceof TFile && this.shouldIncludeAsset(assetFile)) { + this.addAssetToContext(assetFile, context); + } + } + } + + // Collect links (other notes) if recursion depth allows + if (depth < this.settings.recursionDepth && cache.links) { + for (const link of cache.links) { + const linkedFile = this.app.metadataCache.getFirstLinkpathDest(link.link, file.path); + if (linkedFile instanceof TFile && linkedFile.extension === 'md') { + await this.traverse(linkedFile, context, depth + 1); + } + } + } + } else { + // If it's not a markdown file, it's an asset itself + if (this.shouldIncludeAsset(file)) { + this.addAssetToContext(file, context); + } + } + } + + private addAssetToContext(file: TFile, context: TextBundleContext) { + if (context.assetMap.has(file.path)) return; + + let bundleName = file.name; + let counter = 1; + const nameParts = file.name.split('.'); + const ext = nameParts.pop(); + const base = nameParts.join('.'); + + while (context.assets.has(bundleName)) { + bundleName = `${base}_${counter}.${ext}`; + counter++; + } + + context.assetMap.set(file.path, bundleName); + context.assets.set(bundleName, file); + } + + private shouldIncludeAsset(file: TFile): boolean { + const ext = file.extension.toLowerCase(); + if (ext === 'md' || ext === 'markdown') return false; + const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'svg', 'webp', 'bmp', 'tiff']; + const audioExtensions = ['mp3', 'wav', 'ogg', 'm4a', 'flac', 'webm', 'opus']; + const videoExtensions = ['mp4', 'webm', 'mkv', 'avi', 'mov']; + const pdfExtensions = ['pdf']; + + if (imageExtensions.includes(ext)) return this.settings.includeImages; + if (audioExtensions.includes(ext)) return this.settings.includeAudio; + if (videoExtensions.includes(ext)) return this.settings.includeVideo; + if (pdfExtensions.includes(ext)) return this.settings.includePDF; + + return true; // Include other types by default if not specifically filtered + } +} diff --git a/src/features/textbundle/importer.ts b/src/features/textbundle/importer.ts new file mode 100644 index 0000000..265dcf2 --- /dev/null +++ b/src/features/textbundle/importer.ts @@ -0,0 +1,233 @@ +import { App, TFile, TFolder, normalizePath, Notice } from 'obsidian'; +import * as fflate from 'fflate'; +import { AlchemistSettings } from '../../../settings'; +import { ISystemAdapter } from '../../core/IAlchemistModule'; + +export class TextBundleImporter { + app: App; + settings: AlchemistSettings; + system: ISystemAdapter; + + constructor(app: App, settings: AlchemistSettings, system: ISystemAdapter) { + this.app = app; + this.settings = settings; + this.system = system; + } + + /** + * Entry point for ZIP import. + */ + async importZip(data: ArrayBuffer, targetPath?: string, sourceName?: string) { + try { + const unzipped = fflate.unzipSync(new Uint8Array(data)); + await this.processUnzipped(unzipped, targetPath, sourceName); + new Notice('Alchemist: Import successful'); + } catch (e) { + console.error('Alchemist: Import failed', e); + new Notice('Alchemist: Import failed. Check console for details.'); + } + } + + private async processUnzipped(unzipped: Record, targetPath?: string, sourceName?: string) { + const allKeys = Object.keys(unzipped); + + // Identify bundles (.textbundle folders) + const bundleFolders = new Set(); + allKeys.forEach(k => { + const match = k.match(/(.*\.textbundle)\//); + if (match) bundleFolders.add(match[1]); + }); + + if (bundleFolders.size === 0) { + // Flat structure + await this.importSingleBundle(unzipped, targetPath, sourceName); + } else { + // TextPack structure + new Notice(`Alchemist: Importing ${bundleFolders.size} notes from TextPack...`); + for (const folder of bundleFolders) { + const prefix = `${folder}/`; + const bundleFiles: Record = {}; + for (const key of allKeys) { + if (key.startsWith(prefix)) { + bundleFiles[key.replace(prefix, '')] = unzipped[key]; + } + } + const cleanName = folder.replace('.textbundle', ''); + await this.importSingleBundle(bundleFiles, targetPath, cleanName); + } + } + } + + private async importSingleBundle(files: Record, targetPath?: string, sourceName?: string) { + const allKeys = Object.keys(files); + + const textKey = allKeys.find(k => + k.endsWith('text.md') || k.endsWith('text.markdown') || k.endsWith('text.txt') || + k === 'text.md' || k === 'text.markdown' || k === 'text.txt' + ); + + if (!textKey) return; + + const textData = files[textKey]; + let content = fflate.strFromU8(textData); + + const importRoot = targetPath || this.settings.defaultImportPath || '/'; + + let noteName = sourceName ? `${sourceName}.md` : `Imported_Note.md`; + let finalImportFolder = normalizePath(importRoot); + + // 1. Read info.json FIRST to determine structure + const infoKey = allKeys.find(k => k === 'info.json'); + if (infoKey) { + try { + const info = JSON.parse(fflate.strFromU8(files[infoKey])); + if (info.title) noteName = `${info.title}.md`; + + if (info.origin_path && this.settings.restoreFolderStructure) { + const relativeDir = this.system.path.dirname(info.origin_path); + if (relativeDir !== '.') { + finalImportFolder = normalizePath(`${importRoot}/${relativeDir}`); + } + } + } catch (e) {} + } + + await this.ensureFolder(finalImportFolder); + // Put assets in a central "media" folder within the import root (or relative root) + const attachmentFolderPath = normalizePath(`${finalImportFolder}/media`); + await this.ensureFolder(attachmentFolderPath); + + const assetsBase = 'assets/'; + const assetRenameMap = new Map(); + + // 2. Import Assets + for (const [path, assetData] of Object.entries(files)) { + if (path.startsWith(assetsBase) && path !== assetsBase) { + const originalFileName = path.replace(assetsBase, ''); + const actualFileName = await this.importAssetWithSafety(originalFileName, assetData, attachmentFolderPath); + + if (actualFileName !== originalFileName) { + assetRenameMap.set(originalFileName, actualFileName); + } + } + } + + // 3. Link Restoration + content = this.reverseTransformLinks(content); + + for (const [oldName, newName] of assetRenameMap.entries()) { + const escapedOldName = oldName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const linkRegex = new RegExp(`\\[\\[media/${escapedOldName}(\\|[^\\]]+)?\\]\\]`, 'g'); + content = content.replace(linkRegex, (match, alias) => { + return `[[media/${newName}${alias || ''}]]`; + }); + } + + await this.createNoteWithSafety(finalImportFolder, noteName, content); + } + + private async importAssetWithSafety(fileName: string, data: Uint8Array, folderPath: string): Promise { + await this.ensureFolder(folderPath); + + let actualName = fileName; + let fullPath = normalizePath(`${folderPath}/${actualName}`); + let counter = 1; + + const nameParts = fileName.split('.'); + const ext = nameParts.pop(); + const base = nameParts.join('.'); + + while (await this.app.vault.adapter.exists(fullPath)) { + const existingData = await this.app.vault.adapter.readBinary(fullPath); + + // If identical, reuse + if (this.areBuffersEqual(new Uint8Array(existingData), data)) { + return actualName; + } + + // Otherwise rename + actualName = `${base} (${counter}).${ext}`; + fullPath = normalizePath(`${folderPath}/${actualName}`); + counter++; + } + + await this.app.vault.createBinary(fullPath, data.buffer as ArrayBuffer); + return actualName; + } + + private areBuffersEqual(buf1: Uint8Array, buf2: Uint8Array): boolean { + if (buf1.length !== buf2.length) return false; + for (let i = 0; i < buf1.length; i++) { + if (buf1[i] !== buf2[i]) return false; + } + return true; + } + + private async createNoteWithSafety(folderPath: string, fileName: string, content: string) { + let finalPath = normalizePath(`${folderPath}/${fileName}`); + let counter = 1; + + const nameParts = fileName.split('.'); + const ext = nameParts.pop(); + const base = nameParts.join('.'); + + while (this.app.vault.getAbstractFileByPath(finalPath)) { + if (this.settings.conflictStrategy === 'skip') return; + if (this.settings.conflictStrategy === 'overwrite') { + const existing = this.app.vault.getAbstractFileByPath(finalPath); + if (existing instanceof TFile) { + await this.app.vault.modify(existing, content); + } + return; + } + // Default or rename strategy + finalPath = normalizePath(`${folderPath}/${base} (${counter}).${ext}`); + counter++; + } + + await this.app.vault.create(finalPath, content); + } + + private async ensureFolder(path: string) { + if (!path || path === '/' || path === '.') return; + const normalized = normalizePath(path); + if (this.app.vault.getAbstractFileByPath(normalized)) return; + + const parts = normalized.split('/'); + let currentPath = ''; + for (const part of parts) { + currentPath = currentPath ? `${currentPath}/${part}` : part; + if (!this.app.vault.getAbstractFileByPath(currentPath)) { + await this.app.vault.createFolder(currentPath); + } + } + } + + private getAttachmentFolder(): string { + return (this.app.vault as any).getConfig?.('attachmentFolderPath') || ''; + } + + private reverseTransformLinks(content: string): string { + // 1. Embeds: ![alt](assets/filename) -> ![[media/filename|alt]] + content = content.replace(/!\[([^\]]*)\]\(assets\/([^\)]+)\)/g, (match, alt, filename) => { + return alt ? `![[media/${filename}|${alt}]]` : `![[media/${filename}]]`; + }); + + // 2. Links: [text](assets/filename) -> [[media/filename|text]] + content = content.replace(/\[([^\]]+)\]\(assets\/([^\)]+)\)/g, (match, text, filename) => { + return text === filename ? `[[media/${filename}]]` : `[[media/${filename}|${text}]]`; + }); + + // 3. Cross-Bundle Links: [Label](../BundleName.textbundle/text.md) -> [[NoteName|Label]] + content = content.replace(/\[([^\]]+)\]\(\.\.\/([^/]+)\/text\.(md|markdown|txt)\)/g, (match, text, folderName) => { + const decodedBundle = decodeURIComponent(folderName); + const bundleBase = decodedBundle.replace(/\.textbundle$/i, ''); + // Handle collision suffixes like "Note (1)" + const noteName = bundleBase.replace(/ \(\d+\)$/, ''); + + return text === noteName ? `[[${noteName}]]` : `[[${noteName}|${text}]]`; + }); + + return content; + } +} diff --git a/src/features/textbundle/logic.ts b/src/features/textbundle/logic.ts new file mode 100644 index 0000000..68e9a43 --- /dev/null +++ b/src/features/textbundle/logic.ts @@ -0,0 +1,53 @@ +/** + * Pure functions for TextBundle processing. + * These functions have ZERO dependencies on Obsidian API. + */ + +export interface LinkResolver { + resolveAsset(link: string): string | null; // Returns bundle asset name if found + resolveNote(link: string): string | null; // Returns relative path to other note if found +} + +/** + * Transforms Obsidian-style links [[link]] and ![[embed]] to Markdown-style [link](assets/link) + */ +export function transformMarkdownLinks( + content: string, + resolver: LinkResolver +): string { + // 1. Transform Embeds ![[link]] or ![[link|alias]] + content = content.replace(/!\[\[([^\]]+)\]\]/g, (match, link) => { + const [path, alias] = link.split('|'); + const resolvedName = resolver.resolveAsset(path); + + if (resolvedName) { + return `![${alias || resolvedName}](assets/${resolvedName})`; + } + return match; + }); + + // 2. Transform Regular Links [[link]] or [[link|alias]] + content = content.replace(/\[\[([^\]]+)\]\]/g, (match, link) => { + const [path, alias] = link.split('|'); + + // 1. Try resolving as another note in TextPack FIRST + const notePath = resolver.resolveNote(path); + if (notePath) { + const parts = notePath.split('/'); + const bundleName = parts[parts.length - 2] || ''; + const decodedBundle = decodeURIComponent(bundleName); + const basename = decodedBundle.replace('.textbundle', '').split(' - ').pop() || 'Note'; + return `[${alias || basename}](${notePath})`; + } + + // 2. Try resolving as asset + const assetName = resolver.resolveAsset(path); + if (assetName) { + return `[${alias || assetName}](assets/${assetName})`; + } + + return match; + }); + + return content; +} diff --git a/src/features/textbundle/packer.ts b/src/features/textbundle/packer.ts new file mode 100644 index 0000000..0c34e54 --- /dev/null +++ b/src/features/textbundle/packer.ts @@ -0,0 +1,121 @@ +import { TFile, App, normalizePath } from 'obsidian'; +import * as fflate from 'fflate'; +import { TextBundleContext } from './collector'; +import { transformMarkdownLinks, LinkResolver } from './logic'; + +export class TextBundlePacker { + app: App; + + constructor(app: App) { + this.app = app; + } + + /** + * Zips the context into a TextBundle (single) or TextPack (multiple bundles) blob. + */ + async pack(context: TextBundleContext): Promise { + const zipData: any = {}; + + if (context.notes.length === 1) { + // Standard TextBundle (flat structure) + const note = context.notes[0]; + await this.buildBundleData(note, context, zipData, ""); + } else { + // TextPack structure (ZIP of bundles) + const usedNames = new Set(); + const bundleMap = new Map(); + + // First pass: generate unique names + for (const note of context.notes) { + let baseName = note.basename; + let bundleName = `${baseName}.textbundle`; + let counter = 1; + while (usedNames.has(bundleName)) { + bundleName = `${baseName} (${counter}).textbundle`; + counter++; + } + usedNames.add(bundleName); + bundleMap.set(note.path, bundleName); + } + + // Second pass: build data + for (const note of context.notes) { + const bundleName = bundleMap.get(note.path)!; + const bundleData: any = {}; + await this.buildBundleData(note, context, bundleData, "", bundleMap); + zipData[bundleName] = bundleData; + } + } + + return new Promise((resolve, reject) => { + fflate.zip(zipData, (err, data) => { + if (err) reject(err); + else resolve(data); + }); + }); + } + + /** + * Builds the internal structure of a single TextBundle. + */ + private async buildBundleData(note: TFile, context: TextBundleContext, target: any, prefix: string, bundleMap?: Map) { + // 1. info.json (with Traceability โ€” PLAN.md line 59) + const info = { + "version": 2, + "type": "net.daringfireball.markdown", + "title": note.basename, + "origin_vault": this.app.vault.getName(), + "origin_path": note.path, + "export_timestamp": new Date().toISOString() + }; + target[`${prefix}info.json`] = fflate.strToU8(JSON.stringify(info, null, 2)); + + // 2. assets + const assetsObj: any = {}; + const contentRaw = await this.app.vault.read(note); + + // Find which assets are actually used in THIS note + const embeds = this.app.metadataCache.getFileCache(note)?.embeds || []; + const links = this.app.metadataCache.getFileCache(note)?.links || []; + + for (const mention of [...embeds, ...links]) { + const assetFile = this.app.metadataCache.getFirstLinkpathDest(mention.link, note.path); + if (assetFile instanceof TFile && context.assetMap.has(assetFile.path)) { + const bundleAssetName = context.assetMap.get(assetFile.path)!; + const assetData = await this.app.vault.readBinary(assetFile); + assetsObj[bundleAssetName] = new Uint8Array(assetData); + } + } + + if (Object.keys(assetsObj).length > 0) { + target[`${prefix}assets`] = assetsObj; + } + + // 3. text.md (with transformed links) + const resolver: LinkResolver = { + resolveAsset: (link: string) => { + const assetFile = this.app.metadataCache.getFirstLinkpathDest(link, note.path); + if (assetFile instanceof TFile) { + const ext = assetFile.extension.toLowerCase(); + if (ext === 'md' || ext === 'markdown') return null; + return context.assetMap.get(assetFile.path) || assetFile.name; + } + return null; + }, + resolveNote: (link: string) => { + const targetFile = this.app.metadataCache.getFirstLinkpathDest(link, note.path); + if (targetFile instanceof TFile) { + if (bundleMap && bundleMap.has(targetFile.path)) { + const bundleName = bundleMap.get(targetFile.path)!; + const encodedName = encodeURIComponent(bundleName); + return `../${encodedName}/text.md`; + } + } + return null; + } + }; + + const content = transformMarkdownLinks(contentRaw, resolver); + target[`${prefix}text.md`] = fflate.strToU8(content); + } +} diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..10e0f63 --- /dev/null +++ b/styles.css @@ -0,0 +1,17 @@ +/* Alchemist Styles */ + +.alchemist-export-btn { + opacity: 0.6; + transition: opacity 0.2s ease-in-out; + background: var(--interactive-accent); + color: var(--text-on-accent); + border: none; + border-radius: 4px; + padding: 2px 6px; + cursor: pointer; +} + +.alchemist-export-btn:hover { + opacity: 1; + background: var(--interactive-accent-hover); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..d7daa3b --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,36 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "inlineSourceMap": true, + "inlineSources": true, + "module": "ESNext", + "target": "ES6", + "allowJs": true, + "noImplicitAny": true, + "moduleResolution": "Node", + "importHelpers": true, + "isolatedModules": true, + "strict": true, + "skipLibCheck": true, + "typeRoots": [ + "./node_modules/@types", + "../../node_modules/@types" + ], + "lib": [ + "DOM", + "ES5", + "ES6", + "ES7" + ], + "types": [ + "node" + ] + }, + "include": [ + "**/*.ts" + ], + "exclude": [ + "node_modules", + "**/__tests__/**" + ] +} diff --git a/versions.json b/versions.json new file mode 100644 index 0000000..af9a39e --- /dev/null +++ b/versions.json @@ -0,0 +1,3 @@ +{ + "1.0.0": "0.15.0" +}