From e54a8a3b059eb008c8d26bca454e07f100b8acec Mon Sep 17 00:00:00 2001 From: nan Date: Mon, 20 Apr 2026 12:00:50 +0800 Subject: [PATCH] Initial commit: vitepress-exporter plugin --- .gitignore | 6 + .../plugins/vitepress-exporter/new_method.txt | 134 + README.md | 84 + docs/.vuepress/config.ts | 19 + docs/index.ts | 8 + docs/plugins/canvas-viewer.ts | 7 + esbuild.config.mjs | 76 + main.ts | 1210 ++++++++ main.ts.backup | 1145 ++++++++ manifest.json | 10 + package-lock.json | 2466 +++++++++++++++++ package.json | 32 + pnpm-lock.yaml | 1443 ++++++++++ puppeteer_version.txt | 92 + tsconfig.json | 29 + 15 files changed, 6761 insertions(+) create mode 100644 .gitignore create mode 100644 .obsidian/plugins/vitepress-exporter/new_method.txt create mode 100644 README.md create mode 100644 docs/.vuepress/config.ts create mode 100644 docs/index.ts create mode 100644 docs/plugins/canvas-viewer.ts create mode 100644 esbuild.config.mjs create mode 100644 main.ts create mode 100644 main.ts.backup create mode 100644 manifest.json create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 puppeteer_version.txt create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5e6c0c6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +main.js +main.js.map +*.log +.DS_Store +versions.json diff --git a/.obsidian/plugins/vitepress-exporter/new_method.txt b/.obsidian/plugins/vitepress-exporter/new_method.txt new file mode 100644 index 0000000..0a2d42d --- /dev/null +++ b/.obsidian/plugins/vitepress-exporter/new_method.txt @@ -0,0 +1,134 @@ + // 尝试捕获 Obsidian 原生 Canvas 渲染(通过临时调整视口大小) + async tryNativeCanvasCapture(canvasFile: TFile): Promise { + let uiStyleElement: HTMLStyleElement | null = null; + let sizeStyleElement: HTMLStyleElement | null = null; + let activeLeaf: any = null; + let canvasWrapper: HTMLElement | null = null; + let originalScrollLeft = 0; + let originalScrollTop = 0; + + try { + console.log('🔍 Step 1: Getting active workspace leaf...'); + + // 获取当前活动的 leaf(不创建新窗口) + activeLeaf = this.app.workspace.activeLeaf; + if (!activeLeaf) { + console.log('❌ No active leaf found'); + return null; + } + + console.log('🔍 Step 2: Opening canvas file...'); + await activeLeaf.openFile(canvasFile); + + console.log('⏳ Step 3: Waiting for canvas render...'); + await this.waitForCanvasRender(); + + console.log('🔍 Step 4: Finding canvas DOM...'); + const canvasDom = this.findCanvasDomElement(); + if (!canvasDom) { + console.log('❌ Could not find canvas DOM element'); + return null; + } + + console.log('✅ Found canvas DOM:', canvasDom.className, 'Size:', (canvasDom as any).offsetWidth, 'x', (canvasDom as any).offsetHeight); + + console.log('🎨 Step 5: Hiding Canvas UI elements...'); + uiStyleElement = this.hideCanvasUIElements(); + + console.log('📐 Step 6: Calculating canvas content size...'); + const contentSize = this.getCanvasContentSize(canvasDom); + + // 获取 canvasWrapper + if ((canvasDom as HTMLElement).classList.contains('canvas-wrapper')) { + canvasWrapper = canvasDom as HTMLElement; + } else { + canvasWrapper = canvasDom.querySelector('.canvas-wrapper') as HTMLElement; + } + + if (!canvasWrapper) { + console.log('❌ Could not find canvas wrapper'); + return null; + } + + // 保存原始滚动位置 + originalScrollLeft = canvasWrapper.scrollLeft; + originalScrollTop = canvasWrapper.scrollTop; + + console.log(`📏 Original wrapper size: ${(canvasDom as any).offsetWidth}x${(canvasDom as any).offsetHeight}`); + console.log(`📏 Content size: ${contentSize.width}x${contentSize.height}`); + + // 临时调整 canvas wrapper 大小以适应所有内容 + console.log('🔧 Temporarily resizing canvas wrapper to fit all content...'); + sizeStyleElement = document.createElement('style'); + sizeStyleElement.id = 'canvas-export-resize'; + sizeStyleElement.textContent = ` + /* 临时调整 canvas wrapper 大小 */ + .canvas-wrapper { + width: ${contentSize.width + 100}px !important; + height: ${contentSize.height + 100}px !important; + max-width: ${contentSize.width + 100}px !important; + max-height: ${contentSize.height + 100}px !important; + overflow: visible !important; + } + + /* 确保画布内容区域也扩展 */ + .canvas-view-content { + width: ${contentSize.width + 100}px !important; + height: ${contentSize.height + 100}px !important; + } + `; + document.head.appendChild(sizeStyleElement); + + // 等待样式应用 + await new Promise(resolve => setTimeout(resolve, 100)); + + // 重置滚动位置 + canvasWrapper.scrollLeft = 0; + canvasWrapper.scrollTop = 0; + + // 等待布局更新 + await new Promise(resolve => setTimeout(resolve, 200)); + + console.log('📸 Step 7: Capturing canvas...'); + // @ts-ignore + const domToImage = require('dom-to-image-more'); + + const dataUrl = await domToImage.toPng(canvasDom, { + backgroundColor: '#ffffff', + quality: 1, + width: contentSize.width, + height: contentSize.height, + cacheBust: true + }); + + const imageData = this.dataUrlToUint8Array(dataUrl); + + console.log('✅ Capture successful!'); + + return imageData; + + } catch (error) { + console.error('❌ Native canvas capture failed:', error); + return null; + } finally { + // 清理临时调整大小的样式 + if (sizeStyleElement && sizeStyleElement.parentNode) { + sizeStyleElement.parentNode.removeChild(sizeStyleElement); + console.log('🧹 Removed temporary resize styles'); + } + + if (uiStyleElement && uiStyleElement.parentNode) { + uiStyleElement.parentNode.removeChild(uiStyleElement); + console.log('🧹 Cleaned up UI hiding styles'); + } + + // 恢复滚动位置 + if (canvasWrapper) { + canvasWrapper.scrollLeft = originalScrollLeft; + canvasWrapper.scrollTop = originalScrollTop; + console.log('🔄 Restored original scroll position'); + } + + console.log('🧹 Cleanup complete'); + } + } diff --git a/README.md b/README.md new file mode 100644 index 0000000..93e7c9b --- /dev/null +++ b/README.md @@ -0,0 +1,84 @@ +# VitePress Exporter - Obsidian Plugin + +## 功能 + +这个 Obsidian 插件用于自动化发布 Obsidian 笔记到 VitePress 网站: + +- ✅ 将当前 markdown 文件导出到 `docs/` 目录 +- ✅ 自动复制引用的资源文件到 `docs/assets/` 目录 +- ✅ 更新 markdown 中的资源路径 +- 🚧 Canvas 文件渲染(待实现) + +## 安装 + +插件已经安装在这个项目的 `.obsidian/plugins/vitepress-exporter/` 目录下。 + +1. 在 Obsidian 中打开这个项目 +2. 进入设置 → 第三方插件 +3. 启用 "VitePress Exporter" 插件 + +## 使用 + +### 方式 1:命令面板 +1. 打开一个 markdown 文件 +2. 按 `Ctrl+P` (或 `Cmd+P`) 打开命令面板 +3. 输入 "Export to VitePress" +4. 选择 "Export current note to VitePress" + +### 方式 2:功能区按钮 +- 点击左侧功能区栏的上传图标按钮 + +### 方式 3:快捷键 +- 可以在 Obsidian 的快捷键设置中为导出命令设置快捷键 + +## 配置 + +在插件设置中可以配置: + +- **Docs path**: 导出的 markdown 文件存放目录(默认:`docs`) +- **Assets path**: 资源文件存放目录(默认:`docs/assets`) + +## 工作流程 + +1. 用户在 Obsidian 中编写笔记 +2. 笔记中引用的资源(图片、PDF 等)可以放在任意位置 +3. 点击导出按钮 +4. 插件自动: + - 将 markdown 文件复制到 `docs/` 目录 + - 扫描并复制所有引用的资源到 `docs/assets/` 目录 + - 更新 markdown 中的资源路径 + +## 当前状态 + +- ✅ 基础插件框架 +- ✅ 文件导出功能 +- ✅ 资源文件自动复制 +- 🚧 Canvas 文件渲染(开发中) + +## Canvas 渲染计划 + +对于 `.canvas` 文件,计划实现的方案: + +1. **方案 A(优先)**:基于 Obsidian 自己的渲染(探索中) +2. **方案 B(备选)**:使用 Headless Browser 手动渲染 JSON Canvas + +## 开发 + +```bash +cd .obsidian/plugins/vitepress-exporter + +# 安装依赖 +npm install + +# 开发模式(自动重新编译) +npm run dev + +# 生产构建 +npm run build +``` + +## 注意事项 + +- 确保项目中有 `docs/` 目录 +- 资源文件会被复制,不会移动原文件 +- 如果目标文件已存在,会被覆盖 diff --git a/docs/.vuepress/config.ts b/docs/.vuepress/config.ts new file mode 100644 index 0000000..c97ba83 --- /dev/null +++ b/docs/.vuepress/config.ts @@ -0,0 +1,19 @@ +import { defaultTheme } from '@vuepress/theme-default'; +import type { DefaultThemeOptions } from '@vuepress/theme-default'; +import type { PluginOptions } from 'vuepress'; + +export default { + title: 'VitePress Demo', + description: 'Demo for VitePress with Canvas Viewer', + + theme: defaultTheme({ + navbar: [ + { + text: 'Home', + link: '/', + }, + ], + }), + + clientConfigFile: 'index.ts', +} satisfies PluginOptions; diff --git a/docs/index.ts b/docs/index.ts new file mode 100644 index 0000000..c904e03 --- /dev/null +++ b/docs/index.ts @@ -0,0 +1,8 @@ +import { defineClientConfig } from '@vuepress/client'; +import { CanvasViewerPlugin } from './plugins/canvas-viewer'; + +export default defineClientConfig({ + enhance({ app, router }) { + app.use(CanvasViewerPlugin); + } +}); diff --git a/docs/plugins/canvas-viewer.ts b/docs/plugins/canvas-viewer.ts new file mode 100644 index 0000000..5496c5b --- /dev/null +++ b/docs/plugins/canvas-viewer.ts @@ -0,0 +1,7 @@ +import type { Plugin } from 'vue'; + +export const CanvasViewerPlugin: Plugin = { + install(app) { + app.component('CanvasViewer', () => import('./components/CanvasViewer.vue')); + } +}; diff --git a/esbuild.config.mjs b/esbuild.config.mjs new file mode 100644 index 0000000..61114cf --- /dev/null +++ b/esbuild.config.mjs @@ -0,0 +1,76 @@ +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'); + +if (prod) { + console.log('Building production bundle...'); + await esbuild.build({ + 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: false, + treeShaking: true, + outfile: 'main.js', + }); + console.log('Production bundle built successfully!'); +} else { + const ctx = 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: 'inline', + treeShaking: true, + outfile: 'main.js', + }); + + await ctx.watch(); +} diff --git a/main.ts b/main.ts new file mode 100644 index 0000000..fcec775 --- /dev/null +++ b/main.ts @@ -0,0 +1,1210 @@ +import { App, Plugin, PluginSettingTab, Setting, TFile, Notice } from 'obsidian'; + +interface VitePressExporterSettings { + docsPath: string; + assetsPath: string; +} + +const DEFAULT_SETTINGS: VitePressExporterSettings = { + docsPath: 'docs', + assetsPath: 'docs/assets' +} + +export default class VitePressExporterPlugin extends Plugin { + settings: VitePressExporterSettings; + + async onload() { + await this.loadSettings(); + + // 添加导出命令 + this.addCommand({ + id: 'export-to-vitepress', + name: 'Export current note to VitePress', + callback: () => { + this.exportCurrentNote(); + } + }); + + // 添加功能区按钮 + this.addRibbonIcon('upload', 'Export to VitePress', () => { + this.exportCurrentNote(); + }); + + // 添加设置面板 + this.addSettingTab(new VitePressExporterSettingTab(this.app, this)); + + console.log('VitePress Exporter plugin loaded'); + } + + onunload() { + console.log('VitePress Exporter plugin unloaded'); + } + + async loadSettings() { + this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + } + + async saveSettings() { + await this.saveData(this.settings); + } + + // 导出当前笔记 + async exportCurrentNote() { + const activeFile = this.app.workspace.getActiveFile(); + + if (!activeFile) { + new Notice('No active file found'); + return; + } + + if (activeFile.extension !== 'md') { + new Notice('Current file is not a markdown file'); + return; + } + + new Notice(`Exporting ${activeFile.name} to VitePress...`); + + try { + await this.exportNote(activeFile); + new Notice(`Successfully exported ${activeFile.name} to VitePress`); + } catch (error) { + console.error('Export failed:', error); + new Notice(`Export failed: ${error.message}`); + } + } + + // 导出单个笔记 + async exportNote(file: TFile) { + const { vault } = this.app; + + // 使用 binary 模式读取文件以保留原始格式(包括行尾空格) + const contentBuffer = await vault.readBinary(file); + const content = new TextDecoder().decode(contentBuffer); + + // 1. 扫描并复制所有资源文件(传入文件对象用于路径解析) + const updatedContent = await this.processAssets(content, file); + + // 2. 处理 canvas 引用(暂时保留,后续实现) + // const finalContent = await this.processCanvases(updatedContent); + + // 3. 写入到 docs 目录(使用 binary 模式保留原始格式) + const docsPath = `${this.settings.docsPath}/${file.name}`; + const updatedBuffer = new TextEncoder().encode(updatedContent); + await vault.adapter.writeBinary(docsPath, updatedBuffer); + + console.log(`Exported ${file.name} to ${docsPath}`); + } + + // 处理资源文件 + async processAssets(content: string, sourceFile: TFile): Promise { + const { vault, metadataCache } = this.app; + + console.log('Processing assets for file:', sourceFile.path); + + // 使用 Obsidian API 获取文件的所有嵌入和链接 + const cache = metadataCache.getCache(sourceFile.path); + + console.log('Cache:', cache); + console.log('Embeds:', cache?.embeds); + console.log('Links:', cache?.links); + + if (!cache) { + console.log('No cache found for file'); + return content; + } + + const assetsToCopy = new Set(); + const canvasFiles = new Set(); + + // 收集嵌入文件(图片等) + if (cache.embeds) { + for (const embed of cache.embeds) { + console.log('Processing embed:', embed); + const resolvedLink = metadataCache.getFirstLinkpathDest(embed.link, sourceFile.path); + console.log('Resolved link for embed:', resolvedLink?.path); + if (resolvedLink) { + // 检查是否是 canvas 文件 + if (resolvedLink.extension === 'canvas') { + canvasFiles.add(resolvedLink.path); + } else { + assetsToCopy.add(resolvedLink.path); + } + } + } + } + + // 收集普通链接(可选,如果也想复制链接的文件) + if (cache.links) { + for (const link of cache.links) { + const resolvedLink = metadataCache.getFirstLinkpathDest(link.link, sourceFile.path); + // 只复制本地文件链接,不包括其他 md 文件 + if (resolvedLink && resolvedLink.extension !== 'md') { + assetsToCopy.add(resolvedLink.path); + } + } + } + + console.log('Assets to copy:', Array.from(assetsToCopy)); + console.log('Canvas files to render:', Array.from(canvasFiles)); + + // 处理 Canvas 文件:渲染为图片 + for (const canvasPath of canvasFiles) { + try { + const canvasFile = vault.getAbstractFileByPath(canvasPath); + if (canvasFile instanceof TFile) { + const renderedImage = await this.renderCanvasToImage(canvasFile); + if (renderedImage) { + const imageFileName = canvasFile.name.replace('.canvas', '.png'); + // 图片保存到 docs/assets/ + const imagePath = `${this.settings.assetsPath}/${imageFileName}`; + + // 确保目标目录存在 + await vault.adapter.mkdir(this.settings.assetsPath); + + // 写入渲染的图片 + await vault.adapter.writeBinary(imagePath, renderedImage); + + // 更新内容中的 canvas 引用,使用相对路径 assets/xxx.png + content = this.updateCanvasLinksInContent(content, canvasFile, canvasPath, imageFileName); + + console.log(`Successfully rendered canvas: ${canvasPath} -> ${imagePath}`); + } + } + } catch (error) { + console.error(`Failed to render canvas ${canvasPath}:`, error); + } + } + + // 复制资源文件到 docs/assets + for (const assetPath of assetsToCopy) { + try { + const sourceFile = vault.getAbstractFileByPath(assetPath); + console.log('Source file for asset:', sourceFile); + + if (sourceFile instanceof TFile) { + // 使用 binary 读取模式来保留文件原始内容 + const assetContent = await vault.readBinary(sourceFile); + const fileName = sourceFile.name; + const destPath = `${this.settings.assetsPath}/${fileName}`; + + console.log('Copying asset:', assetPath, '->', destPath); + + // 确保目标目录存在 + await vault.adapter.mkdir(this.settings.assetsPath); + + // 写入资源文件(使用 binary 模式) + await vault.adapter.writeBinary(destPath, assetContent); + + // 更新内容中的资源路径(使用更智能的替换) + content = this.updateLinksInContent(content, sourceFile, assetPath, fileName); + + console.log(`Successfully copied asset: ${assetPath} -> ${destPath}`); + } + } catch (error) { + console.error(`Failed to copy asset ${assetPath}:`, error); + } + } + + return content; + } + + // 获取原始链接文本 + getOriginalLink(content: string, targetPath: string, sourcePath: string): string | null { + const { metadataCache } = this.app; + + // 尝试多种可能的链接格式 + const possibleFormats = [ + // Wikilink 格式 + new RegExp(`!\\[\\[${this.escapeRegExp(targetPath)}(\\|[^\\]]*)?\\]\\]`, 'g'), + new RegExp(`\\[\\[${this.escapeRegExp(targetPath)}(\\|[^\\]]*)?\\]\\]`, 'g'), + // Markdown 格式 + new RegExp(`!\\[.*?\\]\\(${this.escapeRegExp(targetPath)}\\)`, 'g'), + new RegExp(`\\[.*?\\]\\(${this.escapeRegExp(targetPath)}\\)`, 'g'), + // 相对路径格式 + new RegExp(`!\\[\\[${this.escapeRegExp(this.getRelativePath(targetPath, sourcePath))}(\\|[^\\]]*)?\\]\\]`, 'g'), + ]; + + for (const regex of possibleFormats) { + const match = content.match(regex); + if (match) { + return match[0]; + } + } + + return null; + } + + // 更新内容中的链接 + updateLinksInContent(content: string, sourceFile: TFile, assetPath: string, newFileName: string): string { + // 获取源文件的目录路径 + const sourceDir = sourceFile.path.substring(0, sourceFile.path.lastIndexOf('/')); + if (!sourceDir) return content; + + // 尝试多种可能的路径格式 + const possiblePaths = [ + // 完整路径 + assetPath, + // 相对于源文件的路径 + assetPath.substring(sourceDir.length + 1), + // URL 编码版本 + encodeURI(assetPath), + encodeURI(assetPath.substring(sourceDir.length + 1)), + // 文件名 + sourceFile.name, + encodeURI(sourceFile.name) + ]; + + console.log('Trying to replace links for paths:', possiblePaths); + + // 替换 markdown 格式: ![](path) -> ![](assets/newfile.png) + const markdownRegex = /!\[([^\]]*)\]\(([^)]+)\)/g; + content = content.replace(markdownRegex, (match, alt, path) => { + // 检查这个路径是否匹配我们的目标文件 + for (const testPath of possiblePaths) { + if (path === testPath || path === testPath.replace(/^\//, '')) { + console.log(`Found matching link: ${path} -> ${this.settings.assetsPath}/${newFileName}`); + return `![](${this.settings.assetsPath}/${newFileName})`; + } + } + return match; + }); + + // 替换 wikilink 格式: ![[path]] -> ![[assets/newfile.png]] + const wikilinkRegex = /!\[\[([^\]]+)\]\]/g; + content = content.replace(wikilinkRegex, (match, link) => { + // 移除可能的别名字段 + const cleanLink = link.split('|')[0].trim(); + + for (const testPath of possiblePaths) { + if (cleanLink === testPath || cleanLink === testPath.replace(/^\//, '')) { + console.log(`Found matching wikilink: ${cleanLink} -> ${this.settings.assetsPath}/${newFileName}`); + return `![[${this.settings.assetsPath}/${newFileName}]]`; + } + } + return match; + }); + + return content; + } + + // 辅助函数:转义正则表达式特殊字符 + escapeRegExp(string: string): string { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + + // 辅助函数:获取相对路径 + getRelativePath(targetPath: string, sourcePath: string): string { + // 简化的相对路径计算 + const targetParts = targetPath.split('/'); + const sourceParts = sourcePath.split('/'); + + // 移除文件名 + sourceParts.pop(); + + let commonIndex = 0; + while (commonIndex < Math.min(targetParts.length - 1, sourceParts.length) && + targetParts[commonIndex] === sourceParts[commonIndex]) { + commonIndex++; + } + + const relativeParts = []; + for (let i = commonIndex; i < sourceParts.length; i++) { + relativeParts.push('..'); + } + + return [...relativeParts, ...targetParts.slice(commonIndex)].join('/'); + } + + // 渲染 Canvas 为图片(使用 Obsidian 原生渲染) + async renderCanvasToImage(canvasFile: TFile): Promise { + try { + console.log('🎯 Attempting to render canvas using Obsidian native rendering:', canvasFile.path); + + // 使用 Workspace API 打开 Canvas 并捕获原生渲染 + const nativeImage = await this.tryNativeCanvasCapture(canvasFile); + if (nativeImage) { + console.log('✅ Successfully captured native Obsidian canvas rendering'); + return nativeImage; + } + + console.log('⚠️ Native capture failed, using placeholder'); + // 降级方案:生成占位图 + return this.generatePlaceholderImage(canvasFile); + + } catch (error) { + console.error('❌ Error rendering canvas:', error); + return this.generatePlaceholderImage(canvasFile); + } + } + + + // 隐藏 Canvas UI 元素(用于导出时) + hideCanvasUIElements(): HTMLStyleElement { + const styleElement = document.createElement('style'); + styleElement.id = 'canvas-export-hide-ui'; + styleElement.textContent = ` + /* 隐藏 Canvas 控制按钮 */ + .canvas-control-menu, + .canvas-card-menu, + .canvas-node-menu-button, + .canvas-node:hover .canvas-node-menu-button, + .canvas-controls, + .canvas-help-button { + display: none !important; + } + + /* 移除选中状态的高亮 */ + .canvas-node.is-selected, + .canvas-node.is-focused, + .canvas-edge.is-selected { + box-shadow: none !important; + outline: none !important; + } + + /* 隐藏工具提示和弹出菜单 */ + .tooltip, + .popover, + .modal { + display: none !important; + } + + /* 隐藏滚动条但保留滚动功能 */ + .canvas-view-content::-webkit-scrollbar { + display: none !important; + } + + /* 确保内容不被裁切 */ + .canvas-view-content { + overflow: visible !important; + } + + /* Privacy Mode: 防止卡片内容因缩放被隐藏 */ + .canvas-node-content-hidden { + display: block !important; + opacity: 1 !important; + } + + /* 确保所有卡片内容始终可见 */ + .canvas-node-content { + display: block !important; + opacity: 1 !important; + } + + /* 防止卡片被折叠 */ + .canvas-node .canvas-node-content { + display: block !important; + } + `; + document.head.appendChild(styleElement); + console.log('✅ Canvas UI elements hidden for export (privacy mode enabled)'); + return styleElement; + } + + // 计算实际的 Canvas 内容尺寸和偏移 + getCanvasContentSize(canvasDom: Element): { width: number; height: number; offsetX: number; offsetY: number } { + const nodes = canvasDom.querySelectorAll('.canvas-node'); + console.log(`📐 Found ${nodes.length} canvas nodes`); + + if (nodes.length === 0) { + // 降级方案:使用容器尺寸 + return { + width: (canvasDom as any).offsetWidth || 800, + height: (canvasDom as any).offsetHeight || 600, + offsetX: 0, + offsetY: 0 + }; + } + + // 计算所有节点的边界框 + let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; + + nodes.forEach(node => { + const rect = node.getBoundingClientRect(); + const canvasRect = canvasDom.getBoundingClientRect(); + + // 计算相对于 Canvas 的位置 + const relativeX = rect.left - canvasRect.left; + const relativeY = rect.top - canvasRect.top; + + minX = Math.min(minX, relativeX); + minY = Math.min(minY, relativeY); + maxX = Math.max(maxX, relativeX + rect.width); + maxY = Math.max(maxY, relativeY + rect.height); + }); + + // 添加 padding + const padding = 50; + const offsetX = Math.max(0, minX - padding); + const offsetY = Math.max(0, minY - padding); + const contentWidth = maxX - minX + padding * 2; + const contentHeight = maxY - minY + padding * 2; + + console.log(`📐 Canvas: ${contentWidth}x${contentHeight}, offset: (${offsetX}, ${offsetY})`); + + return { width: contentWidth, height: contentHeight, offsetX, offsetY }; + } + + + // 通过滚动拼接捕获完整 Canvas + async captureCanvasByScrolling( + canvasDom: Element, + contentSize: { width: number; height: number; offsetX: number; offsetY: number } + ): Promise { + try { + // 检查 canvasDom 本身是否就是 wrapper,或者 wrapper 是其子元素 + let canvasWrapper: HTMLElement | null = null; + if ((canvasDom as HTMLElement).classList.contains('canvas-wrapper')) { + console.log('📦 canvasDom itself is the wrapper'); + canvasWrapper = canvasDom as HTMLElement; + } else { + canvasWrapper = canvasDom.querySelector('.canvas-wrapper') as HTMLElement; + if (!canvasWrapper) { + console.log('❌ No canvas wrapper found'); + return null; + } + } + + // 使用 canvasWrapper 获取视口尺寸 + const viewportWidth = canvasWrapper.offsetWidth; + const viewportHeight = canvasWrapper.offsetHeight; + const totalWidth = contentSize.width; + const totalHeight = contentSize.height; + + console.log(`📐 Viewport: ${viewportWidth}x${viewportHeight}, Total: ${totalWidth}x${totalHeight}`); + + // 如果内容小于视口,直接捕获 + if (totalWidth <= viewportWidth && totalHeight <= viewportHeight) { + console.log('📸 Content fits in viewport, single capture'); + return null; // 让降级处理 + } + + // 计算需要分块的数量 + const cols = Math.ceil(totalWidth / viewportWidth); + const rows = Math.ceil(totalHeight / viewportHeight); + console.log(`🧩 Will capture ${cols}x${rows} = ${cols * rows} tiles`); + console.log(`📍 Content offset: (${contentSize.offsetX}, ${contentSize.offsetY})`); + + // 保存原始滚动位置 + const originalScrollLeft = canvasWrapper.scrollLeft; + const originalScrollTop = canvasWrapper.scrollTop; + + // 创建最终拼接的 Canvas + const finalCanvas = document.createElement('canvas'); + finalCanvas.width = totalWidth; + finalCanvas.height = totalHeight; + const ctx = finalCanvas.getContext('2d'); + if (!ctx) { + console.log('❌ Failed to get canvas context'); + return null; + } + + // 填充白色背景 + ctx.fillStyle = '#ffffff'; + ctx.fillRect(0, 0, totalWidth, totalHeight); + + // @ts-ignore + const domToImage = require('dom-to-image-more'); + + // 分块捕获并拼接 + for (let row = 0; row < rows; row++) { + for (let col = 0; col < cols; col++) { + const x = col * viewportWidth; + const y = row * viewportHeight; + + // 滚动到对应位置 (确保从内容起始位置开始) + const targetScrollLeft = Math.max(0, contentSize.offsetX + x); + const targetScrollTop = Math.max(0, contentSize.offsetY + y); + canvasWrapper.scrollLeft = targetScrollLeft; + canvasWrapper.scrollTop = targetScrollTop; + console.log(`🔄 Scrolled to (${targetScrollLeft}, ${targetScrollTop})`); + + // 等待渲染 + await new Promise(resolve => setTimeout(resolve, 150)); + + // 捕获当前视口 + // @ts-ignore + const domToImage = require('dom-to-image-more'); + const tileDataUrl = await domToImage.toPng(canvasWrapper, { + backgroundColor: '#ffffff', + quality: 1, + width: viewportWidth, + height: viewportHeight + }); + + // 加载图片并绘制到最终 Canvas + const img = await this.loadImage(tileDataUrl); + if (img) { + const drawWidth = Math.min(viewportWidth, totalWidth - x); + const drawHeight = Math.min(viewportHeight, totalHeight - y); + ctx.drawImage(img, 0, 0, drawWidth, drawHeight, x, y, drawWidth, drawHeight); + console.log(`✅ Tile [${row},${col}] at (${x},${y}) size ${drawWidth}x${drawHeight}`); + } + if (img) { + const drawWidth = Math.min(viewportWidth, totalWidth - x); + const drawHeight = Math.min(viewportHeight, totalHeight - y); + ctx.drawImage(img, 0, 0, drawWidth, drawHeight, x, y, drawWidth, drawHeight); + console.log(`✅ Tile [${row},${col}] at (${x},${y}) size ${drawWidth}x${drawHeight}`); + } + } + } + + // 恢复滚动位置 + canvasWrapper.scrollLeft = originalScrollLeft; + canvasWrapper.scrollTop = originalScrollTop; + + // 转换为 Uint8Array + const finalDataUrl = finalCanvas.toDataURL('image/png'); + const base64Data = finalDataUrl.split(',')[1]; + const binaryString = atob(base64Data); + const bytes = new Uint8Array(binaryString.length); + + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + + console.log('✅ Stitched canvas complete'); + return bytes; + + } catch (error) { + console.error('❌ Scroll and stitch failed:', error); + return null; + } + } + + // 加载图片 + async loadImage(dataUrl: string): Promise { + return new Promise((resolve) => { + const img = new Image(); + img.onload = () => resolve(img); + img.onerror = () => resolve(null); + img.src = dataUrl; + }); + } + + // 将 DataURL 转换为 Uint8Array + dataUrlToUint8Array(dataUrl: string): Uint8Array { + const base64Data = dataUrl.split(',')[1]; + const binaryString = atob(base64Data); + const bytes = new Uint8Array(binaryString.length); + + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + + return bytes; + } + + // 尝试捕获 Obsidian 原生 Canvas 渲染(通过临时调整视口大小) + async tryNativeCanvasCapture(canvasFile: TFile): Promise { + let uiStyleElement: HTMLStyleElement | null = null; + let sizeStyleElement: HTMLStyleElement | null = null; + let activeLeaf: any = null; + let canvasWrapper: HTMLElement | null = null; + let originalScrollLeft = 0; + let originalScrollTop = 0; + + try { + console.log('🔍 Step 1: Getting active workspace leaf...'); + + // 获取当前活动的 leaf(不创建新窗口) + activeLeaf = this.app.workspace.activeLeaf; + if (!activeLeaf) { + console.log('❌ No active leaf found'); + return null; + } + + console.log('🔍 Step 2: Opening canvas file...'); + await activeLeaf.openFile(canvasFile); + + console.log('⏳ Step 3: Waiting for canvas render...'); + await this.waitForCanvasRender(); + + console.log('🔍 Step 4: Finding canvas DOM...'); + const canvasDom = this.findCanvasDomElement(); + if (!canvasDom) { + console.log('❌ Could not find canvas DOM element'); + return null; + } + + console.log('✅ Found canvas DOM:', canvasDom.className, 'Size:', (canvasDom as any).offsetWidth, 'x', (canvasDom as any).offsetHeight); + + console.log('🎨 Step 5: Hiding Canvas UI elements...'); + uiStyleElement = this.hideCanvasUIElements(); + + console.log('📐 Step 6: Calculating canvas content size...'); + const contentSize = this.getCanvasContentSize(canvasDom); + + // 获取 canvasWrapper + if ((canvasDom as HTMLElement).classList.contains('canvas-wrapper')) { + canvasWrapper = canvasDom as HTMLElement; + } else { + canvasWrapper = canvasDom.querySelector('.canvas-wrapper') as HTMLElement; + } + + if (!canvasWrapper) { + console.log('❌ Could not find canvas wrapper'); + return null; + } + + // 保存原始滚动位置 + originalScrollLeft = canvasWrapper.scrollLeft; + originalScrollTop = canvasWrapper.scrollTop; + + console.log(`📏 Original wrapper size: ${(canvasDom as any).offsetWidth}x${(canvasDom as any).offsetHeight}`); + console.log(`📏 Content size: ${contentSize.width}x${contentSize.height}`); + + // 临时调整 canvas wrapper 大小以适应所有内容 + console.log('🔧 Temporarily resizing canvas wrapper to fit all content...'); + sizeStyleElement = document.createElement('style'); + sizeStyleElement.id = 'canvas-export-resize'; + sizeStyleElement.textContent = ` + /* 临时调整 canvas wrapper 大小 */ + .canvas-wrapper { + width: ${contentSize.width + 100}px !important; + height: ${contentSize.height + 100}px !important; + max-width: ${contentSize.width + 100}px !important; + max-height: ${contentSize.height + 100}px !important; + overflow: visible !important; + } + + /* 确保画布内容区域也扩展 */ + .canvas-view-content { + width: ${contentSize.width + 100}px !important; + height: ${contentSize.height + 100}px !important; + } + `; + document.head.appendChild(sizeStyleElement); + + // 等待样式应用 + await new Promise(resolve => setTimeout(resolve, 100)); + + // 重置滚动位置 + canvasWrapper.scrollLeft = 0; + canvasWrapper.scrollTop = 0; + + // 等待布局更新 + await new Promise(resolve => setTimeout(resolve, 200)); + + console.log('📸 Step 7: Capturing canvas...'); + // @ts-ignore + const domToImage = require('dom-to-image-more'); + + const dataUrl = await domToImage.toPng(canvasDom, { + backgroundColor: '#ffffff', + quality: 1, + width: contentSize.width, + height: contentSize.height, + cacheBust: true + }); + + const imageData = this.dataUrlToUint8Array(dataUrl); + + console.log('✅ Capture successful!'); + + return imageData; + + } catch (error) { + console.error('❌ Native canvas capture failed:', error); + return null; + } finally { + // 清理临时调整大小的样式 + if (sizeStyleElement && sizeStyleElement.parentNode) { + sizeStyleElement.parentNode.removeChild(sizeStyleElement); + console.log('🧹 Removed temporary resize styles'); + } + + if (uiStyleElement && uiStyleElement.parentNode) { + uiStyleElement.parentNode.removeChild(uiStyleElement); + console.log('🧹 Cleaned up UI hiding styles'); + } + + // 恢复滚动位置 + if (canvasWrapper) { + canvasWrapper.scrollLeft = originalScrollLeft; + canvasWrapper.scrollTop = originalScrollTop; + console.log('🔄 Restored original scroll position'); + } + + console.log('🧹 Cleanup complete'); + } + } + + + // 在指定的 leaf 中查找 Canvas DOM 元素 + async findCanvasDomInLeaf(leaf: any): Promise { + console.log('🔍 Searching for canvas DOM in leaf...'); + + // 获取 leaf 的容器 + const container = leaf.containerEl; + if (!container) { + console.log('❌ Leaf has no container'); + return null; + } + + console.log('📦 Leaf container:', container); + + // 在 leaf 容器中查找 Canvas(最多等待 20 秒) + const maxWait = 20000; + const startTime = Date.now(); + + return new Promise(resolve => { + const checkCanvas = () => { + const elapsed = Date.now() - startTime; + + if (elapsed > maxWait) { + console.log('⏰ Canvas render timeout after', maxWait, 'ms'); + resolve(null); + return; + } + + // 尝试多种可能的选择器(在 leaf 容器内搜索) + const selectors = [ + '.canvas-view-content', + '.canvas-wrapper', + '.canvas-container', + '[data-type="canvas"]', + '.canvas-view' + ]; + + for (const selector of selectors) { + const canvas = container.querySelector(selector); + if (canvas) { + const nodes = canvas.querySelectorAll('.canvas-node'); + if (nodes.length > 0) { + console.log(`✅ Found canvas with selector: ${selector} (${elapsed}ms) with ${nodes.length} nodes`); + setTimeout(() => resolve(canvas), 500); + return; + } + } + } + + // 继续等待 + setTimeout(checkCanvas, 100); + }; + + console.log('⏳ Starting to wait for canvas render in leaf...'); + checkCanvas(); + }); + } + // 等待 Canvas 渲染完成 + async waitForCanvasRender(): Promise { + return new Promise(resolve => { + const maxWait = 20000; // 增加到 20 秒(新窗口需要更多时间) + const startTime = Date.now(); + + const checkCanvas = () => { + const elapsed = Date.now() - startTime; + + if (elapsed > maxWait) { + console.log('⏰ Canvas render timeout after', maxWait, 'ms'); + resolve(); + return; + } + + // 尝试多种可能的选择器 + const selectors = [ + '.canvas-view-content', + '.canvas-wrapper', + '.canvas-container', + '[data-type="canvas"]', + '.workspace-leaf-content .canvas-view' + ]; + + for (const selector of selectors) { + const canvas = document.querySelector(selector); + if (canvas) { + // 检查是否有节点 + const nodes = canvas.querySelectorAll('.canvas-node'); + if (nodes.length > 0) { + console.log(`✅ Canvas rendered using selector: ${selector} (${elapsed}ms) with ${nodes.length} nodes`); + // 额外等待确保渲染完全完成 + setTimeout(resolve, 1000); + return; + } + } + // 继续等待 + } + setTimeout(checkCanvas, 100); + }; + + console.log('⏳ Starting to wait for canvas render...'); + checkCanvas(); + }); + } + + // 查找 Canvas DOM 元素 + findCanvasDomElement(): Element | null { + console.log('🔍 Searching for canvas DOM elements...'); + + // 尝试多种可能的选择器 + const selectors = [ + '.canvas-view-content', + '.canvas-wrapper', + '.canvas-container', + '[data-type="canvas"]', + '.workspace-leaf-content .canvas-view', + '.canvas-view' + ]; + + for (const selector of selectors) { + const element = document.querySelector(selector); + if (element) { + console.log('✅ Found canvas element with selector: "' + selector + '"'); + console.log(' Element:', element.tagName, element.className); + // @ts-ignore - HTMLElement 类型扩展 + console.log(' Size:', element.offsetWidth, 'x', element.offsetHeight); + console.log(' Children:', element.children.length); + return element; + } + } + + console.log('❌ No canvas element found'); + return null; + } + + // 从 Canvas JSON 渲染图片 + async renderCanvasFromJSON(canvasFile: TFile): Promise { + try { + console.log('📖 Reading canvas JSON...'); + const { vault } = this.app; + + // 读取 Canvas JSON + const content = await vault.read(canvasFile); + const canvasData = JSON.parse(content); + + console.log('📊 Canvas data:', canvasData); + + // 解析节点和边 + const nodes = canvasData.nodes || []; + const edges = canvasData.edges || []; + + console.log(`📦 Found ${nodes.length} nodes and ${edges.length} edges`); + + if (nodes.length === 0) { + console.log('⚠️ No nodes found in canvas'); + return null; + } + + // 计算画布边界 + let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; + + for (const node of nodes) { + const x = node.x || 0; + const y = node.y || 0; + const width = node.width || 200; + const height = node.height || 100; + + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x + width); + maxY = Math.max(maxY, y + height); + } + + // 添加 padding + const padding = 50; + minX -= padding; + minY -= padding; + maxX += padding; + maxY += padding; + + const canvasWidth = maxX - minX; + const canvasHeight = maxY - minY; + + console.log(`📐 Canvas size: ${canvasWidth} x ${canvasHeight}`); + + // 创建 Canvas + const canvas = document.createElement('canvas'); + canvas.width = canvasWidth; + canvas.height = canvasHeight; + const ctx = canvas.getContext('2d'); + + if (!ctx) { + console.log('❌ Failed to get canvas context'); + return null; + } + + // 填充背景 + ctx.fillStyle = '#ffffff'; + ctx.fillRect(0, 0, canvasWidth, canvasHeight); + + // 绘制边(连接线) + console.log('🔗 Drawing edges...'); + ctx.strokeStyle = '#999999'; + ctx.lineWidth = 2; + + for (const edge of edges) { + const fromNode = nodes.find((n: any) => n.id === edge.fromNode || n.id === edge.from); + const toNode = nodes.find((n: any) => n.id === edge.toNode || n.id === edge.to); + + if (fromNode && toNode) { + const fromX = fromNode.x + (fromNode.width || 200) / 2 - minX; + const fromY = fromNode.y + (fromNode.height || 100) / 2 - minY; + const toX = toNode.x + (toNode.width || 200) / 2 - minX; + const toY = toNode.y + (toNode.height || 100) / 2 - minY; + + ctx.beginPath(); + ctx.moveTo(fromX, fromY); + ctx.lineTo(toX, toY); + ctx.stroke(); + } + } + + // 绘制节点 + console.log('🎨 Drawing nodes...'); + for (const node of nodes) { + await this.drawCanvasNode(ctx, node, minX, minY); + } + + console.log('💾 Converting to Uint8Array...'); + + // 转换为 Uint8Array + const dataUrl = canvas.toDataURL('image/png'); + const base64Data = dataUrl.split(',')[1]; + const binaryString = atob(base64Data); + const bytes = new Uint8Array(binaryString.length); + + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + + return bytes; + + } catch (error) { + console.error('❌ Error rendering canvas from JSON:', error); + return null; + } + } + + // 绘制单个 Canvas 节点 + async drawCanvasNode(ctx: CanvasRenderingContext2D, node: any, offsetX: number, offsetY: number): Promise { + const x = (node.x || 0) - offsetX; + const y = (node.y || 0) - offsetY; + const width = node.width || 200; + const height = node.height || 100; + + console.log(` Drawing node "${node.id}" at (${x}, ${y})`); + + // 设置背景颜色 + let bgColor = '#f0f0f0'; + if (node.color) { + const colorMap: Record = { + '1': '#ff6b6b', + '2': '#4ecdc4', + '3': '#45b7d1', + '4': '#96ceb4', + '5': '#ffeaa7', + '6': '#dfe6e9' + }; + bgColor = colorMap[node.color] || node.color; + } + + // 绘制节点背景 + ctx.fillStyle = bgColor; + ctx.fillRect(x, y, width, height); + + // 绘制边框 + ctx.strokeStyle = '#cccccc'; + ctx.lineWidth = 2; + ctx.strokeRect(x, y, width, height); + + // 绘制文本内容 + if (node.type === 'text' && node.text) { + ctx.fillStyle = '#333333'; + ctx.font = '14px sans-serif'; + ctx.textAlign = 'left'; + ctx.textBaseline = 'top'; + + // 简单的文本换行处理 + const padding = 10; + const maxWidth = width - padding * 2; + const lineHeight = 20; + + this.wrapText(ctx, node.text, x + padding, y + padding, maxWidth, lineHeight); + } else if (node.type === 'file' && node.file) { + ctx.fillStyle = '#333333'; + ctx.font = 'bold 14px sans-serif'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + + // 显示文件名 + const fileName = node.file.split('/').pop(); + ctx.fillText(fileName || node.file, x + width / 2, y + height / 2); + } else if (node.label) { + ctx.fillStyle = '#333333'; + ctx.font = 'bold 16px sans-serif'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText(node.label, x + width / 2, y + height / 2); + } + } + + // 文本换行辅助函数 + wrapText(ctx: CanvasRenderingContext2D, text: string, x: number, y: number, maxWidth: number, lineHeight: number): void { + const words = text.split(' '); + let line = ''; + let currentY = y; + + for (let i = 0; i < words.length; i++) { + const testLine = line + words[i] + ' '; + const metrics = ctx.measureText(testLine); + const testWidth = metrics.width; + + if (testWidth > maxWidth && i > 0) { + ctx.fillText(line, x, currentY); + line = words[i] + ' '; + currentY += lineHeight; + } else { + line = testLine; + } + } + + ctx.fillText(line, x, currentY); + } + + // 生成占位图 + generatePlaceholderImage(canvasFile: TFile): Uint8Array | null { + try { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + + if (!ctx) return null; + + // 设置占位图尺寸 + canvas.width = 800; + canvas.height = 600; + + // 绘制背景 + ctx.fillStyle = '#f0f0f0'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + // 绘制边框 + ctx.strokeStyle = '#ccc'; + ctx.lineWidth = 2; + ctx.strokeRect(10, 10, canvas.width - 20, canvas.height - 20); + + // 绘制文字 + ctx.fillStyle = '#666'; + ctx.font = '24px Arial'; + ctx.textAlign = 'center'; + ctx.fillText('Canvas 占位图', canvas.width / 2, canvas.height / 2 - 20); + + ctx.font = '16px Arial'; + ctx.fillText(canvasFile.name, canvas.width / 2, canvas.height / 2 + 20); + ctx.font = '14px Arial'; + ctx.fillText('(需要手动导出或等待原生渲染支持)', canvas.width / 2, canvas.height / 2 + 50); + + // 转换为 Uint8Array + const dataUrl = canvas.toDataURL('image/png'); + const base64Data = dataUrl.split(',')[1]; + const binaryString = atob(base64Data); + const bytes = new Uint8Array(binaryString.length); + + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + + return bytes; + + } catch (error) { + console.error('Error generating placeholder image:', error); + return null; + } + } + + // 更新内容中的 Canvas 链接 + updateCanvasLinksInContent(content: string, canvasFile: TFile, canvasPath: string, imageFileName: string): string { + // 获取源文件的目录路径 + const sourceDir = canvasFile.path.substring(0, canvasFile.path.lastIndexOf('/')); + if (!sourceDir) return content; + + // 尝试多种可能的路径格式 + const possiblePaths = [ + // 完整路径 + canvasPath, + // 相对于源文件的路径 + canvasPath.substring(sourceDir.length + 1), + // URL 编码版本 + encodeURI(canvasPath), + encodeURI(canvasPath.substring(sourceDir.length + 1)), + // 文件名(包括和不包括 .canvas 扩展名) + canvasFile.name, + canvasFile.name.replace('.canvas', ''), + encodeURI(canvasFile.name), + encodeURI(canvasFile.name.replace('.canvas', '')) + ]; + + console.log('Trying to replace canvas links for paths:', possiblePaths); + + // 替换 markdown 格式: !(canvas) -> + const markdownRegex = /!\[([^\]]*)\]\(([^)]+)\)/g; + content = content.replace(markdownRegex, (match, alt, path) => { + // 检查这个路径是否匹配我们的 canvas 文件 + for (const testPath of possiblePaths) { + if (path === testPath || path === testPath.replace(/^\//, '')) { + const relativePath = this.settings.assetsPath.replace('docs/', ''); + console.log(`Found matching canvas link: ${path} -> `); + return ``; + } + } + return match; + }); + + // 替换 wikilink 格式: ![[canvas]] -> + const wikilinkRegex = /!\[\[([^\]]+)\]\]/g; + content = content.replace(wikilinkRegex, (match, link) => { + // 移除可能的别名字段 + const cleanLink = link.split('|')[0].trim(); + + for (const testPath of possiblePaths) { + if (cleanLink === testPath || cleanLink === testPath.replace(/^\//, '')) { + const relativePath = this.settings.assetsPath.replace('docs/', ''); + console.log(`Found matching canvas wikilink: ${cleanLink} -> `); + return ``; + } + } + return match; + }); + + return content; + } +} + +// 设置面板 +class VitePressExporterSettingTab extends PluginSettingTab { + plugin: VitePressExporterPlugin; + + constructor(app: App, plugin: VitePressExporterPlugin) { + super(app, plugin); + this.plugin = plugin; + } + + display(): void { + const { containerEl } = this; + + containerEl.empty(); + + containerEl.createEl('h2', { text: 'VitePress Exporter Settings' }); + + new Setting(containerEl) + .setName('Docs path') + .setDesc('Path to the docs directory (relative to vault root)') + .addText(text => text + .setPlaceholder('docs') + .setValue(this.plugin.settings.docsPath) + .onChange(async (value) => { + this.plugin.settings.docsPath = value; + await this.plugin.saveSettings(); + })); + + new Setting(containerEl) + .setName('Assets path') + .setDesc('Path to the assets directory (relative to vault root)') + .addText(text => text + .setPlaceholder('docs/assets') + .setValue(this.plugin.settings.assetsPath) + .onChange(async (value) => { + this.plugin.settings.assetsPath = value; + await this.plugin.saveSettings(); + })); + } +} diff --git a/main.ts.backup b/main.ts.backup new file mode 100644 index 0000000..b40f6d1 --- /dev/null +++ b/main.ts.backup @@ -0,0 +1,1145 @@ +import { App, Plugin, PluginSettingTab, Setting, TFile, Notice } from 'obsidian'; + +interface VitePressExporterSettings { + docsPath: string; + assetsPath: string; +} + +const DEFAULT_SETTINGS: VitePressExporterSettings = { + docsPath: 'docs', + assetsPath: 'docs/assets' +} + +export default class VitePressExporterPlugin extends Plugin { + settings: VitePressExporterSettings; + + async onload() { + await this.loadSettings(); + + // 添加导出命令 + this.addCommand({ + id: 'export-to-vitepress', + name: 'Export current note to VitePress', + callback: () => { + this.exportCurrentNote(); + } + }); + + // 添加功能区按钮 + this.addRibbonIcon('upload', 'Export to VitePress', () => { + this.exportCurrentNote(); + }); + + // 添加设置面板 + this.addSettingTab(new VitePressExporterSettingTab(this.app, this)); + + console.log('VitePress Exporter plugin loaded'); + } + + onunload() { + console.log('VitePress Exporter plugin unloaded'); + } + + async loadSettings() { + this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + } + + async saveSettings() { + await this.saveData(this.settings); + } + + // 导出当前笔记 + async exportCurrentNote() { + const activeFile = this.app.workspace.getActiveFile(); + + if (!activeFile) { + new Notice('No active file found'); + return; + } + + if (activeFile.extension !== 'md') { + new Notice('Current file is not a markdown file'); + return; + } + + new Notice(`Exporting ${activeFile.name} to VitePress...`); + + try { + await this.exportNote(activeFile); + new Notice(`Successfully exported ${activeFile.name} to VitePress`); + } catch (error) { + console.error('Export failed:', error); + new Notice(`Export failed: ${error.message}`); + } + } + + // 导出单个笔记 + async exportNote(file: TFile) { + const { vault } = this.app; + + // 使用 binary 模式读取文件以保留原始格式(包括行尾空格) + const contentBuffer = await vault.readBinary(file); + const content = new TextDecoder().decode(contentBuffer); + + // 1. 扫描并复制所有资源文件(传入文件对象用于路径解析) + const updatedContent = await this.processAssets(content, file); + + // 2. 处理 canvas 引用(暂时保留,后续实现) + // const finalContent = await this.processCanvases(updatedContent); + + // 3. 写入到 docs 目录(使用 binary 模式保留原始格式) + const docsPath = `${this.settings.docsPath}/${file.name}`; + const updatedBuffer = new TextEncoder().encode(updatedContent); + await vault.adapter.writeBinary(docsPath, updatedBuffer); + + console.log(`Exported ${file.name} to ${docsPath}`); + } + + // 处理资源文件 + async processAssets(content: string, sourceFile: TFile): Promise { + const { vault, metadataCache } = this.app; + + console.log('Processing assets for file:', sourceFile.path); + + // 使用 Obsidian API 获取文件的所有嵌入和链接 + const cache = metadataCache.getCache(sourceFile.path); + + console.log('Cache:', cache); + console.log('Embeds:', cache?.embeds); + console.log('Links:', cache?.links); + + if (!cache) { + console.log('No cache found for file'); + return content; + } + + const assetsToCopy = new Set(); + const canvasFiles = new Set(); + + // 收集嵌入文件(图片等) + if (cache.embeds) { + for (const embed of cache.embeds) { + console.log('Processing embed:', embed); + const resolvedLink = metadataCache.getFirstLinkpathDest(embed.link, sourceFile.path); + console.log('Resolved link for embed:', resolvedLink?.path); + if (resolvedLink) { + // 检查是否是 canvas 文件 + if (resolvedLink.extension === 'canvas') { + canvasFiles.add(resolvedLink.path); + } else { + assetsToCopy.add(resolvedLink.path); + } + } + } + } + + // 收集普通链接(可选,如果也想复制链接的文件) + if (cache.links) { + for (const link of cache.links) { + const resolvedLink = metadataCache.getFirstLinkpathDest(link.link, sourceFile.path); + // 只复制本地文件链接,不包括其他 md 文件 + if (resolvedLink && resolvedLink.extension !== 'md') { + assetsToCopy.add(resolvedLink.path); + } + } + } + + console.log('Assets to copy:', Array.from(assetsToCopy)); + console.log('Canvas files to render:', Array.from(canvasFiles)); + + // 处理 Canvas 文件:渲染为图片 + for (const canvasPath of canvasFiles) { + try { + const canvasFile = vault.getAbstractFileByPath(canvasPath); + if (canvasFile instanceof TFile) { + const renderedImage = await this.renderCanvasToImage(canvasFile); + if (renderedImage) { + const imageFileName = canvasFile.name.replace('.canvas', '.png'); + // 图片保存到 docs/assets/ + const imagePath = `${this.settings.assetsPath}/${imageFileName}`; + + // 确保目标目录存在 + await vault.adapter.mkdir(this.settings.assetsPath); + + // 写入渲染的图片 + await vault.adapter.writeBinary(imagePath, renderedImage); + + // 更新内容中的 canvas 引用,使用相对路径 assets/xxx.png + content = this.updateCanvasLinksInContent(content, canvasFile, canvasPath, imageFileName); + + console.log(`Successfully rendered canvas: ${canvasPath} -> ${imagePath}`); + } + } + } catch (error) { + console.error(`Failed to render canvas ${canvasPath}:`, error); + } + } + + // 复制资源文件到 docs/assets + for (const assetPath of assetsToCopy) { + try { + const sourceFile = vault.getAbstractFileByPath(assetPath); + console.log('Source file for asset:', sourceFile); + + if (sourceFile instanceof TFile) { + // 使用 binary 读取模式来保留文件原始内容 + const assetContent = await vault.readBinary(sourceFile); + const fileName = sourceFile.name; + const destPath = `${this.settings.assetsPath}/${fileName}`; + + console.log('Copying asset:', assetPath, '->', destPath); + + // 确保目标目录存在 + await vault.adapter.mkdir(this.settings.assetsPath); + + // 写入资源文件(使用 binary 模式) + await vault.adapter.writeBinary(destPath, assetContent); + + // 更新内容中的资源路径(使用更智能的替换) + content = this.updateLinksInContent(content, sourceFile, assetPath, fileName); + + console.log(`Successfully copied asset: ${assetPath} -> ${destPath}`); + } + } catch (error) { + console.error(`Failed to copy asset ${assetPath}:`, error); + } + } + + return content; + } + + // 获取原始链接文本 + getOriginalLink(content: string, targetPath: string, sourcePath: string): string | null { + const { metadataCache } = this.app; + + // 尝试多种可能的链接格式 + const possibleFormats = [ + // Wikilink 格式 + new RegExp(`!\\[\\[${this.escapeRegExp(targetPath)}(\\|[^\\]]*)?\\]\\]`, 'g'), + new RegExp(`\\[\\[${this.escapeRegExp(targetPath)}(\\|[^\\]]*)?\\]\\]`, 'g'), + // Markdown 格式 + new RegExp(`!\\[.*?\\]\\(${this.escapeRegExp(targetPath)}\\)`, 'g'), + new RegExp(`\\[.*?\\]\\(${this.escapeRegExp(targetPath)}\\)`, 'g'), + // 相对路径格式 + new RegExp(`!\\[\\[${this.escapeRegExp(this.getRelativePath(targetPath, sourcePath))}(\\|[^\\]]*)?\\]\\]`, 'g'), + ]; + + for (const regex of possibleFormats) { + const match = content.match(regex); + if (match) { + return match[0]; + } + } + + return null; + } + + // 更新内容中的链接 + updateLinksInContent(content: string, sourceFile: TFile, assetPath: string, newFileName: string): string { + // 获取源文件的目录路径 + const sourceDir = sourceFile.path.substring(0, sourceFile.path.lastIndexOf('/')); + if (!sourceDir) return content; + + // 尝试多种可能的路径格式 + const possiblePaths = [ + // 完整路径 + assetPath, + // 相对于源文件的路径 + assetPath.substring(sourceDir.length + 1), + // URL 编码版本 + encodeURI(assetPath), + encodeURI(assetPath.substring(sourceDir.length + 1)), + // 文件名 + sourceFile.name, + encodeURI(sourceFile.name) + ]; + + console.log('Trying to replace links for paths:', possiblePaths); + + // 替换 markdown 格式: ![](path) -> ![](assets/newfile.png) + const markdownRegex = /!\[([^\]]*)\]\(([^)]+)\)/g; + content = content.replace(markdownRegex, (match, alt, path) => { + // 检查这个路径是否匹配我们的目标文件 + for (const testPath of possiblePaths) { + if (path === testPath || path === testPath.replace(/^\//, '')) { + console.log(`Found matching link: ${path} -> ${this.settings.assetsPath}/${newFileName}`); + return `![](${this.settings.assetsPath}/${newFileName})`; + } + } + return match; + }); + + // 替换 wikilink 格式: ![[path]] -> ![[assets/newfile.png]] + const wikilinkRegex = /!\[\[([^\]]+)\]\]/g; + content = content.replace(wikilinkRegex, (match, link) => { + // 移除可能的别名字段 + const cleanLink = link.split('|')[0].trim(); + + for (const testPath of possiblePaths) { + if (cleanLink === testPath || cleanLink === testPath.replace(/^\//, '')) { + console.log(`Found matching wikilink: ${cleanLink} -> ${this.settings.assetsPath}/${newFileName}`); + return `![[${this.settings.assetsPath}/${newFileName}]]`; + } + } + return match; + }); + + return content; + } + + // 辅助函数:转义正则表达式特殊字符 + escapeRegExp(string: string): string { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + + // 辅助函数:获取相对路径 + getRelativePath(targetPath: string, sourcePath: string): string { + // 简化的相对路径计算 + const targetParts = targetPath.split('/'); + const sourceParts = sourcePath.split('/'); + + // 移除文件名 + sourceParts.pop(); + + let commonIndex = 0; + while (commonIndex < Math.min(targetParts.length - 1, sourceParts.length) && + targetParts[commonIndex] === sourceParts[commonIndex]) { + commonIndex++; + } + + const relativeParts = []; + for (let i = commonIndex; i < sourceParts.length; i++) { + relativeParts.push('..'); + } + + return [...relativeParts, ...targetParts.slice(commonIndex)].join('/'); + } + + // 渲染 Canvas 为图片(使用 Obsidian 原生渲染) + async renderCanvasToImage(canvasFile: TFile): Promise { + try { + console.log('🎯 Attempting to render canvas using Obsidian native rendering:', canvasFile.path); + + // 使用 Workspace API 打开 Canvas 并捕获原生渲染 + const nativeImage = await this.tryNativeCanvasCapture(canvasFile); + if (nativeImage) { + console.log('✅ Successfully captured native Obsidian canvas rendering'); + return nativeImage; + } + + console.log('⚠️ Native capture failed, using placeholder'); + // 降级方案:生成占位图 + return this.generatePlaceholderImage(canvasFile); + + } catch (error) { + console.error('❌ Error rendering canvas:', error); + return this.generatePlaceholderImage(canvasFile); + } + } + + + // 隐藏 Canvas UI 元素(用于导出时) + hideCanvasUIElements(): HTMLStyleElement { + const styleElement = document.createElement('style'); + styleElement.id = 'canvas-export-hide-ui'; + styleElement.textContent = ` + /* 隐藏 Canvas 控制按钮 */ + .canvas-control-menu, + .canvas-card-menu, + .canvas-node-menu-button, + .canvas-node:hover .canvas-node-menu-button, + .canvas-controls, + .canvas-help-button { + display: none !important; + } + + /* 移除选中状态的高亮 */ + .canvas-node.is-selected, + .canvas-node.is-focused, + .canvas-edge.is-selected { + box-shadow: none !important; + outline: none !important; + } + + /* 隐藏工具提示和弹出菜单 */ + .tooltip, + .popover, + .modal { + display: none !important; + } + + /* 隐藏滚动条但保留滚动功能 */ + .canvas-view-content::-webkit-scrollbar { + display: none !important; + } + + /* 确保内容不被裁切 */ + .canvas-view-content { + overflow: visible !important; + } + + /* Privacy Mode: 防止卡片内容因缩放被隐藏 */ + .canvas-node-content-hidden { + display: block !important; + opacity: 1 !important; + } + + /* 确保所有卡片内容始终可见 */ + .canvas-node-content { + display: block !important; + opacity: 1 !important; + } + + /* 防止卡片被折叠 */ + .canvas-node .canvas-node-content { + display: block !important; + } + `; + document.head.appendChild(styleElement); + console.log('✅ Canvas UI elements hidden for export (privacy mode enabled)'); + return styleElement; + } + + // 计算实际的 Canvas 内容尺寸和偏移 + getCanvasContentSize(canvasDom: Element): { width: number; height: number; offsetX: number; offsetY: number } { + const nodes = canvasDom.querySelectorAll('.canvas-node'); + console.log(`📐 Found ${nodes.length} canvas nodes`); + + if (nodes.length === 0) { + // 降级方案:使用容器尺寸 + return { + width: (canvasDom as any).offsetWidth || 800, + height: (canvasDom as any).offsetHeight || 600, + offsetX: 0, + offsetY: 0 + }; + } + + // 计算所有节点的边界框 + let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; + + nodes.forEach(node => { + const rect = node.getBoundingClientRect(); + const canvasRect = canvasDom.getBoundingClientRect(); + + // 计算相对于 Canvas 的位置 + const relativeX = rect.left - canvasRect.left; + const relativeY = rect.top - canvasRect.top; + + minX = Math.min(minX, relativeX); + minY = Math.min(minY, relativeY); + maxX = Math.max(maxX, relativeX + rect.width); + maxY = Math.max(maxY, relativeY + rect.height); + }); + + // 添加 padding + const padding = 50; + const offsetX = Math.max(0, minX - padding); + const offsetY = Math.max(0, minY - padding); + const contentWidth = maxX - minX + padding * 2; + const contentHeight = maxY - minY + padding * 2; + + console.log(`📐 Canvas: ${contentWidth}x${contentHeight}, offset: (${offsetX}, ${offsetY})`); + + return { width: contentWidth, height: contentHeight, offsetX, offsetY }; + } + + + // 通过滚动拼接捕获完整 Canvas + async captureCanvasByScrolling( + canvasDom: Element, + contentSize: { width: number; height: number; offsetX: number; offsetY: number } + ): Promise { + try { + // 检查 canvasDom 本身是否就是 wrapper,或者 wrapper 是其子元素 + let canvasWrapper: HTMLElement | null = null; + if ((canvasDom as HTMLElement).classList.contains('canvas-wrapper')) { + console.log('📦 canvasDom itself is the wrapper'); + canvasWrapper = canvasDom as HTMLElement; + } else { + canvasWrapper = canvasDom.querySelector('.canvas-wrapper') as HTMLElement; + if (!canvasWrapper) { + console.log('❌ No canvas wrapper found'); + return null; + } + } + + // 使用 canvasWrapper 获取视口尺寸 + const viewportWidth = canvasWrapper.offsetWidth; + const viewportHeight = canvasWrapper.offsetHeight; + const totalWidth = contentSize.width; + const totalHeight = contentSize.height; + + console.log(`📐 Viewport: ${viewportWidth}x${viewportHeight}, Total: ${totalWidth}x${totalHeight}`); + + // 如果内容小于视口,直接捕获 + if (totalWidth <= viewportWidth && totalHeight <= viewportHeight) { + console.log('📸 Content fits in viewport, single capture'); + return null; // 让降级处理 + } + + // 计算需要分块的数量 + const cols = Math.ceil(totalWidth / viewportWidth); + const rows = Math.ceil(totalHeight / viewportHeight); + console.log(`🧩 Will capture ${cols}x${rows} = ${cols * rows} tiles`); + console.log(`📍 Content offset: (${contentSize.offsetX}, ${contentSize.offsetY})`); + + // 保存原始滚动位置 + const originalScrollLeft = canvasWrapper.scrollLeft; + const originalScrollTop = canvasWrapper.scrollTop; + + // 创建最终拼接的 Canvas + const finalCanvas = document.createElement('canvas'); + finalCanvas.width = totalWidth; + finalCanvas.height = totalHeight; + const ctx = finalCanvas.getContext('2d'); + if (!ctx) { + console.log('❌ Failed to get canvas context'); + return null; + } + + // 填充白色背景 + ctx.fillStyle = '#ffffff'; + ctx.fillRect(0, 0, totalWidth, totalHeight); + + // @ts-ignore + const domToImage = require('dom-to-image-more'); + + // 分块捕获并拼接 + for (let row = 0; row < rows; row++) { + for (let col = 0; col < cols; col++) { + const x = col * viewportWidth; + const y = row * viewportHeight; + + // 滚动到对应位置 (确保从内容起始位置开始) + const targetScrollLeft = Math.max(0, contentSize.offsetX + x); + const targetScrollTop = Math.max(0, contentSize.offsetY + y); + canvasWrapper.scrollLeft = targetScrollLeft; + canvasWrapper.scrollTop = targetScrollTop; + console.log(`🔄 Scrolled to (${targetScrollLeft}, ${targetScrollTop})`); + + // 等待渲染 + await new Promise(resolve => setTimeout(resolve, 150)); + + // 捕获当前视口 + const tileDataUrl = await domToImage.toPng(canvasDom, { + backgroundColor: '#ffffff', + quality: 1, + width: viewportWidth, + height: viewportHeight + }); + + // 加载图片并绘制到最终 Canvas + const img = await this.loadImage(tileDataUrl); + if (img) { + const drawWidth = Math.min(viewportWidth, totalWidth - x); + const drawHeight = Math.min(viewportHeight, totalHeight - y); + ctx.drawImage(img, 0, 0, drawWidth, drawHeight, x, y, drawWidth, drawHeight); + console.log(`✅ Tile [${row},${col}] at (${x},${y}) size ${drawWidth}x${drawHeight}`); + } + } + } + + // 恢复滚动位置 + canvasWrapper.scrollLeft = originalScrollLeft; + canvasWrapper.scrollTop = originalScrollTop; + + // 转换为 Uint8Array + const finalDataUrl = finalCanvas.toDataURL('image/png'); + const base64Data = finalDataUrl.split(',')[1]; + const binaryString = atob(base64Data); + const bytes = new Uint8Array(binaryString.length); + + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + + console.log('✅ Stitched canvas complete'); + return bytes; + + } catch (error) { + console.error('❌ Scroll and stitch failed:', error); + return null; + } + } + + // 加载图片 + async loadImage(dataUrl: string): Promise { + return new Promise((resolve) => { + const img = new Image(); + img.onload = () => resolve(img); + img.onerror = () => resolve(null); + img.src = dataUrl; + }); + } + + // 将 DataURL 转换为 Uint8Array + dataUrlToUint8Array(dataUrl: string): Uint8Array { + const base64Data = dataUrl.split(',')[1]; + const binaryString = atob(base64Data); + const bytes = new Uint8Array(binaryString.length); + + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + + return bytes; + } + + // 尝试捕获 Obsidian 原生 Canvas 渲染 + async tryNativeCanvasCapture(canvasFile: TFile): Promise { + let uiStyleElement: HTMLStyleElement | null = null; + let tempLeaf: any = null; + + try { + console.log('🔍 Step 1: Creating independent hidden window for rendering...'); + + // 创建一个新的分割窗口用于渲染(不影响用户当前视图) + // @ts-ignore - 使用 Obsidian 的 splitActiveLeaf API + tempLeaf = this.app.workspace.splitActiveLeaf('vertical'); + if (!tempLeaf) { + console.log('⚠️ Could not create split leaf, using active leaf'); + tempLeaf = this.app.workspace.activeLeaf; + } + + console.log('🔍 Step 2: Opening canvas file in independent window...'); + await tempLeaf.openFile(canvasFile); + + console.log('⏳ Step 3: Waiting for canvas render...'); + await this.waitForCanvasRender(); + + console.log('🔍 Step 4: Finding canvas DOM...'); + const canvasDom = this.findCanvasDomElement(); + if (!canvasDom) { + console.log('❌ Could not find canvas DOM element'); + return null; + } + + console.log('✅ Found canvas DOM:', canvasDom.className, 'Size:', (canvasDom as any).offsetWidth, 'x', (canvasDom as any).offsetHeight); + + console.log('🎨 Step 4.5: Hiding Canvas UI elements...'); + uiStyleElement = this.hideCanvasUIElements(); + + console.log('📐 Step 4.6: Calculating canvas content size...'); + const contentSize = this.getCanvasContentSize(canvasDom); + + console.log('📸 Step 5: Determining capture strategy...'); + + // 获取视口尺寸 + const viewportWidth = (canvasDom as any).offsetWidth || 800; + const viewportHeight = (canvasDom as any).offsetHeight || 600; + + console.log(` Viewport: ${viewportWidth}x${viewportHeight}, Content: ${contentSize.width}x${contentSize.height}`); + console.log(` Offset: (${contentSize.offsetX}, ${contentSize.offsetY})`); + + let imageData: Uint8Array | null = null; + + // 判断是否需要滚动拼接 + if (contentSize.width > viewportWidth || contentSize.height > viewportHeight) { + // 大画布:使用滚动拼接方法 + console.log('🧩 Using scroll-and-stitch for large canvas...'); + imageData = await this.captureCanvasByScrolling(canvasDom, contentSize); + } else { + // 小画布:使用单次捕获,但需要调整 offset + console.log('📸 Using single capture for small canvas...'); + + // 滚动到正确位置以确保内容在视野中 + // 获取 canvasWrapper(处理 canvasDom 本身就是 wrapper 的情况) + let canvasWrapper: HTMLElement | null = null; + if ((canvasDom as HTMLElement).classList.contains('canvas-wrapper')) { + canvasWrapper = canvasDom as HTMLElement; + } else { + canvasWrapper = canvasDom.querySelector('.canvas-wrapper') as HTMLElement; + } + if (canvasWrapper) { + const originalScrollLeft = canvasWrapper.scrollLeft; + const originalScrollTop = canvasWrapper.scrollTop; + + // 滚动到内容起始位置 + canvasWrapper.scrollLeft = contentSize.offsetX; + canvasWrapper.scrollTop = contentSize.offsetY; + + // 等待滚动完成 + await new Promise(resolve => setTimeout(resolve, 200)); + + // @ts-ignore + const domToImage = require('dom-to-image-more'); + + const dataUrl = await domToImage.toPng(canvasDom, { + backgroundColor: '#ffffff', + quality: 1, + width: contentSize.width, + height: contentSize.height + }); + + imageData = this.dataUrlToUint8Array(dataUrl); + + // 恢复滚动位置 + canvasWrapper.scrollLeft = originalScrollLeft; + canvasWrapper.scrollTop = originalScrollTop; + } else { + // 降级方案:直接捕获整个 DOM + // @ts-ignore + const domToImage = require('dom-to-image-more'); + + const dataUrl = await domToImage.toPng(canvasDom, { + backgroundColor: '#ffffff', + quality: 1, + width: contentSize.width, + height: contentSize.height + }); + + imageData = this.dataUrlToUint8Array(dataUrl); + } + } + + if (imageData) { + console.log('✅ Successfully captured canvas! Size:', imageData.length, 'bytes'); + return imageData; + } + + console.log('❌ Capture failed, returning null'); + return null; + + } catch (error) { + console.error('❌ Native canvas capture failed:', error); + return null; + } finally { + if (uiStyleElement && uiStyleElement.parentNode) { + uiStyleElement.parentNode.removeChild(uiStyleElement); + console.log('🧹 Cleaned up UI hiding styles'); + } + + // 关闭临时窗口 + if (tempLeaf && tempLeaf !== this.app.workspace.activeLeaf) { + try { + // @ts-ignore + tempLeaf.detach(); + console.log('🧹 Closed temporary render window'); + } catch (e) { + console.log('⚠️ Could not close temporary leaf:', e); + } + } + } + } + + + // 等待 Canvas 渲染完成 + async waitForCanvasRender(): Promise { + return new Promise(resolve => { + const maxWait = 8000; // 最多等待 8 秒 + const startTime = Date.now(); + + const checkCanvas = () => { + const elapsed = Date.now() - startTime; + + if (elapsed > maxWait) { + console.log('⏰ Canvas render timeout after', maxWait, 'ms'); + resolve(); + return; + } + + // 尝试多种可能的选择器 + const selectors = [ + '.canvas-view-content', + '.canvas-wrapper', + '.canvas-container', + '[data-type="canvas"]', + '.workspace-leaf-content .canvas-view' + ]; + + for (const selector of selectors) { + const canvas = document.querySelector(selector); + if (canvas && canvas.childElementCount > 0) { + console.log(`✅ Canvas rendered using selector: ${selector} (${elapsed}ms)`); + // 额外等待确保渲染完全完成 + setTimeout(resolve, 500); + return; + } + } + + // 继续等待 + setTimeout(checkCanvas, 100); + }; + + console.log('⏳ Starting to wait for canvas render...'); + checkCanvas(); + }); + } + + // 查找 Canvas DOM 元素 + findCanvasDomElement(): Element | null { + console.log('🔍 Searching for canvas DOM elements...'); + + // 尝试多种可能的选择器 + const selectors = [ + '.canvas-view-content', + '.canvas-wrapper', + '.canvas-container', + '[data-type="canvas"]', + '.workspace-leaf-content .canvas-view', + '.canvas-view' + ]; + + for (const selector of selectors) { + const element = document.querySelector(selector); + if (element) { + console.log('✅ Found canvas element with selector: "' + selector + '"'); + console.log(' Element:', element.tagName, element.className); + // @ts-ignore - HTMLElement 类型扩展 + console.log(' Size:', element.offsetWidth, 'x', element.offsetHeight); + console.log(' Children:', element.children.length); + return element; + } + } + + console.log('❌ No canvas element found'); + return null; + } + + // 从 Canvas JSON 渲染图片 + async renderCanvasFromJSON(canvasFile: TFile): Promise { + try { + console.log('📖 Reading canvas JSON...'); + const { vault } = this.app; + + // 读取 Canvas JSON + const content = await vault.read(canvasFile); + const canvasData = JSON.parse(content); + + console.log('📊 Canvas data:', canvasData); + + // 解析节点和边 + const nodes = canvasData.nodes || []; + const edges = canvasData.edges || []; + + console.log(`📦 Found ${nodes.length} nodes and ${edges.length} edges`); + + if (nodes.length === 0) { + console.log('⚠️ No nodes found in canvas'); + return null; + } + + // 计算画布边界 + let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; + + for (const node of nodes) { + const x = node.x || 0; + const y = node.y || 0; + const width = node.width || 200; + const height = node.height || 100; + + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x + width); + maxY = Math.max(maxY, y + height); + } + + // 添加 padding + const padding = 50; + minX -= padding; + minY -= padding; + maxX += padding; + maxY += padding; + + const canvasWidth = maxX - minX; + const canvasHeight = maxY - minY; + + console.log(`📐 Canvas size: ${canvasWidth} x ${canvasHeight}`); + + // 创建 Canvas + const canvas = document.createElement('canvas'); + canvas.width = canvasWidth; + canvas.height = canvasHeight; + const ctx = canvas.getContext('2d'); + + if (!ctx) { + console.log('❌ Failed to get canvas context'); + return null; + } + + // 填充背景 + ctx.fillStyle = '#ffffff'; + ctx.fillRect(0, 0, canvasWidth, canvasHeight); + + // 绘制边(连接线) + console.log('🔗 Drawing edges...'); + ctx.strokeStyle = '#999999'; + ctx.lineWidth = 2; + + for (const edge of edges) { + const fromNode = nodes.find((n: any) => n.id === edge.fromNode || n.id === edge.from); + const toNode = nodes.find((n: any) => n.id === edge.toNode || n.id === edge.to); + + if (fromNode && toNode) { + const fromX = fromNode.x + (fromNode.width || 200) / 2 - minX; + const fromY = fromNode.y + (fromNode.height || 100) / 2 - minY; + const toX = toNode.x + (toNode.width || 200) / 2 - minX; + const toY = toNode.y + (toNode.height || 100) / 2 - minY; + + ctx.beginPath(); + ctx.moveTo(fromX, fromY); + ctx.lineTo(toX, toY); + ctx.stroke(); + } + } + + // 绘制节点 + console.log('🎨 Drawing nodes...'); + for (const node of nodes) { + await this.drawCanvasNode(ctx, node, minX, minY); + } + + console.log('💾 Converting to Uint8Array...'); + + // 转换为 Uint8Array + const dataUrl = canvas.toDataURL('image/png'); + const base64Data = dataUrl.split(',')[1]; + const binaryString = atob(base64Data); + const bytes = new Uint8Array(binaryString.length); + + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + + return bytes; + + } catch (error) { + console.error('❌ Error rendering canvas from JSON:', error); + return null; + } + } + + // 绘制单个 Canvas 节点 + async drawCanvasNode(ctx: CanvasRenderingContext2D, node: any, offsetX: number, offsetY: number): Promise { + const x = (node.x || 0) - offsetX; + const y = (node.y || 0) - offsetY; + const width = node.width || 200; + const height = node.height || 100; + + console.log(` Drawing node "${node.id}" at (${x}, ${y})`); + + // 设置背景颜色 + let bgColor = '#f0f0f0'; + if (node.color) { + const colorMap: Record = { + '1': '#ff6b6b', + '2': '#4ecdc4', + '3': '#45b7d1', + '4': '#96ceb4', + '5': '#ffeaa7', + '6': '#dfe6e9' + }; + bgColor = colorMap[node.color] || node.color; + } + + // 绘制节点背景 + ctx.fillStyle = bgColor; + ctx.fillRect(x, y, width, height); + + // 绘制边框 + ctx.strokeStyle = '#cccccc'; + ctx.lineWidth = 2; + ctx.strokeRect(x, y, width, height); + + // 绘制文本内容 + if (node.type === 'text' && node.text) { + ctx.fillStyle = '#333333'; + ctx.font = '14px sans-serif'; + ctx.textAlign = 'left'; + ctx.textBaseline = 'top'; + + // 简单的文本换行处理 + const padding = 10; + const maxWidth = width - padding * 2; + const lineHeight = 20; + + this.wrapText(ctx, node.text, x + padding, y + padding, maxWidth, lineHeight); + } else if (node.type === 'file' && node.file) { + ctx.fillStyle = '#333333'; + ctx.font = 'bold 14px sans-serif'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + + // 显示文件名 + const fileName = node.file.split('/').pop(); + ctx.fillText(fileName || node.file, x + width / 2, y + height / 2); + } else if (node.label) { + ctx.fillStyle = '#333333'; + ctx.font = 'bold 16px sans-serif'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText(node.label, x + width / 2, y + height / 2); + } + } + + // 文本换行辅助函数 + wrapText(ctx: CanvasRenderingContext2D, text: string, x: number, y: number, maxWidth: number, lineHeight: number): void { + const words = text.split(' '); + let line = ''; + let currentY = y; + + for (let i = 0; i < words.length; i++) { + const testLine = line + words[i] + ' '; + const metrics = ctx.measureText(testLine); + const testWidth = metrics.width; + + if (testWidth > maxWidth && i > 0) { + ctx.fillText(line, x, currentY); + line = words[i] + ' '; + currentY += lineHeight; + } else { + line = testLine; + } + } + + ctx.fillText(line, x, currentY); + } + + // 生成占位图 + generatePlaceholderImage(canvasFile: TFile): Uint8Array | null { + try { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + + if (!ctx) return null; + + // 设置占位图尺寸 + canvas.width = 800; + canvas.height = 600; + + // 绘制背景 + ctx.fillStyle = '#f0f0f0'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + // 绘制边框 + ctx.strokeStyle = '#ccc'; + ctx.lineWidth = 2; + ctx.strokeRect(10, 10, canvas.width - 20, canvas.height - 20); + + // 绘制文字 + ctx.fillStyle = '#666'; + ctx.font = '24px Arial'; + ctx.textAlign = 'center'; + ctx.fillText('Canvas 占位图', canvas.width / 2, canvas.height / 2 - 20); + + ctx.font = '16px Arial'; + ctx.fillText(canvasFile.name, canvas.width / 2, canvas.height / 2 + 20); + ctx.font = '14px Arial'; + ctx.fillText('(需要手动导出或等待原生渲染支持)', canvas.width / 2, canvas.height / 2 + 50); + + // 转换为 Uint8Array + const dataUrl = canvas.toDataURL('image/png'); + const base64Data = dataUrl.split(',')[1]; + const binaryString = atob(base64Data); + const bytes = new Uint8Array(binaryString.length); + + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + + return bytes; + + } catch (error) { + console.error('Error generating placeholder image:', error); + return null; + } + } + + // 更新内容中的 Canvas 链接 + updateCanvasLinksInContent(content: string, canvasFile: TFile, canvasPath: string, imageFileName: string): string { + // 获取源文件的目录路径 + const sourceDir = canvasFile.path.substring(0, canvasFile.path.lastIndexOf('/')); + if (!sourceDir) return content; + + // 尝试多种可能的路径格式 + const possiblePaths = [ + // 完整路径 + canvasPath, + // 相对于源文件的路径 + canvasPath.substring(sourceDir.length + 1), + // URL 编码版本 + encodeURI(canvasPath), + encodeURI(canvasPath.substring(sourceDir.length + 1)), + // 文件名(包括和不包括 .canvas 扩展名) + canvasFile.name, + canvasFile.name.replace('.canvas', ''), + encodeURI(canvasFile.name), + encodeURI(canvasFile.name.replace('.canvas', '')) + ]; + + console.log('Trying to replace canvas links for paths:', possiblePaths); + + // 替换 markdown 格式: !(canvas) -> + const markdownRegex = /!\[([^\]]*)\]\(([^)]+)\)/g; + content = content.replace(markdownRegex, (match, alt, path) => { + // 检查这个路径是否匹配我们的 canvas 文件 + for (const testPath of possiblePaths) { + if (path === testPath || path === testPath.replace(/^\//, '')) { + const relativePath = this.settings.assetsPath.replace('docs/', ''); + console.log(`Found matching canvas link: ${path} -> `); + return ``; + } + } + return match; + }); + + // 替换 wikilink 格式: ![[canvas]] -> + const wikilinkRegex = /!\[\[([^\]]+)\]\]/g; + content = content.replace(wikilinkRegex, (match, link) => { + // 移除可能的别名字段 + const cleanLink = link.split('|')[0].trim(); + + for (const testPath of possiblePaths) { + if (cleanLink === testPath || cleanLink === testPath.replace(/^\//, '')) { + const relativePath = this.settings.assetsPath.replace('docs/', ''); + console.log(`Found matching canvas wikilink: ${cleanLink} -> `); + return ``; + } + } + return match; + }); + + return content; + } +} + +// 设置面板 +class VitePressExporterSettingTab extends PluginSettingTab { + plugin: VitePressExporterPlugin; + + constructor(app: App, plugin: VitePressExporterPlugin) { + super(app, plugin); + this.plugin = plugin; + } + + display(): void { + const { containerEl } = this; + + containerEl.empty(); + + containerEl.createEl('h2', { text: 'VitePress Exporter Settings' }); + + new Setting(containerEl) + .setName('Docs path') + .setDesc('Path to the docs directory (relative to vault root)') + .addText(text => text + .setPlaceholder('docs') + .setValue(this.plugin.settings.docsPath) + .onChange(async (value) => { + this.plugin.settings.docsPath = value; + await this.plugin.saveSettings(); + })); + + new Setting(containerEl) + .setName('Assets path') + .setDesc('Path to the assets directory (relative to vault root)') + .addText(text => text + .setPlaceholder('docs/assets') + .setValue(this.plugin.settings.assetsPath) + .onChange(async (value) => { + this.plugin.settings.assetsPath = value; + await this.plugin.saveSettings(); + })); + } +} diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..57db413 --- /dev/null +++ b/manifest.json @@ -0,0 +1,10 @@ +{ + "id": "vitepress-exporter", + "name": "VitePress Exporter", + "version": "0.1.0", + "minAppVersion": "0.15.0", + "description": "Export Obsidian notes to VitePress with asset management", + "author": "Your Name", + "authorUrl": "https://github.com/yourusername", + "isDesktopOnly": false +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..319339c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2466 @@ +{ + "name": "vitepress-exporter", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vitepress-exporter", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "html2canvas": "^1.4.1" + }, + "devDependencies": { + "@types/node": "^16.11.6", + "@typescript-eslint/eslint-plugin": "5.29.0", + "@typescript-eslint/parser": "5.29.0", + "builtin-modules": "3.3.0", + "dom-to-image-more": "^3.7.2", + "esbuild": "0.17.3", + "obsidian": "latest", + "tslib": "2.4.0", + "typescript": "4.7.4" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "peer": true, + "dependencies": { + "@codemirror/state": "^6.5.0", + "crelt": "^1.0.6", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.3.tgz", + "integrity": "sha512-1Mlz934GvbgdDmt26rTLmf03cAgLg5HyOgJN+ZGCeP3Q9ynYTNMn2/LQxIl7Uy+o4K6Rfi2OuLsr12JQQR8gNg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.3.tgz", + "integrity": "sha512-XvJsYo3dO3Pi4kpalkyMvfQsjxPWHYjoX4MDiB/FUM4YMfWcXa5l4VCwFWVYI1+92yxqjuqrhNg0CZg3gSouyQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.3.tgz", + "integrity": "sha512-nuV2CmLS07Gqh5/GrZLuqkU9Bm6H6vcCspM+zjp9TdQlxJtIe+qqEXQChmfc7nWdyr/yz3h45Utk1tUn8Cz5+A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.3.tgz", + "integrity": "sha512-01Hxaaat6m0Xp9AXGM8mjFtqqwDjzlMP0eQq9zll9U85ttVALGCGDuEvra5Feu/NbP5AEP1MaopPwzsTcUq1cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.3.tgz", + "integrity": "sha512-Eo2gq0Q/er2muf8Z83X21UFoB7EU6/m3GNKvrhACJkjVThd0uA+8RfKpfNhuMCl1bKRfBzKOk6xaYKQZ4lZqvA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.3.tgz", + "integrity": "sha512-CN62ESxaquP61n1ZjQP/jZte8CE09M6kNn3baos2SeUfdVBkWN5n6vGp2iKyb/bm/x4JQzEvJgRHLGd5F5b81w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.3.tgz", + "integrity": "sha512-feq+K8TxIznZE+zhdVurF3WNJ/Sa35dQNYbaqM/wsCbWdzXr5lyq+AaTUSER2cUR+SXPnd/EY75EPRjf4s1SLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.3.tgz", + "integrity": "sha512-CLP3EgyNuPcg2cshbwkqYy5bbAgK+VhyfMU7oIYyn+x4Y67xb5C5ylxsNUjRmr8BX+MW3YhVNm6Lq6FKtRTWHQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.3.tgz", + "integrity": "sha512-JHeZXD4auLYBnrKn6JYJ0o5nWJI9PhChA/Nt0G4MvLaMrvXuWnY93R3a7PiXeJQphpL1nYsaMcoV2QtuvRnF/g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.3.tgz", + "integrity": "sha512-FyXlD2ZjZqTFh0sOQxFDiWG1uQUEOLbEh9gKN/7pFxck5Vw0qjWSDqbn6C10GAa1rXJpwsntHcmLqydY9ST9ZA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.3.tgz", + "integrity": "sha512-OrDGMvDBI2g7s04J8dh8/I7eSO+/E7nMDT2Z5IruBfUO/RiigF1OF6xoH33Dn4W/OwAWSUf1s2nXamb28ZklTA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.3.tgz", + "integrity": "sha512-DcnUpXnVCJvmv0TzuLwKBC2nsQHle8EIiAJiJ+PipEVC16wHXaPEKP0EqN8WnBe0TPvMITOUlP2aiL5YMld+CQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.3.tgz", + "integrity": "sha512-BDYf/l1WVhWE+FHAW3FzZPtVlk9QsrwsxGzABmN4g8bTjmhazsId3h127pliDRRu5674k1Y2RWejbpN46N9ZhQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.3.tgz", + "integrity": "sha512-WViAxWYMRIi+prTJTyV1wnqd2mS2cPqJlN85oscVhXdb/ZTFJdrpaqm/uDsZPGKHtbg5TuRX/ymKdOSk41YZow==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.3.tgz", + "integrity": "sha512-Iw8lkNHUC4oGP1O/KhumcVy77u2s6+KUjieUqzEU3XuWJqZ+AY7uVMrrCbAiwWTkpQHkr00BuXH5RpC6Sb/7Ug==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.3.tgz", + "integrity": "sha512-0AGkWQMzeoeAtXQRNB3s4J1/T2XbigM2/Mn2yU1tQSmQRmHIZdkGbVq2A3aDdNslPyhb9/lH0S5GMTZ4xsjBqg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.3.tgz", + "integrity": "sha512-4+rR/WHOxIVh53UIQIICryjdoKdHsFZFD4zLSonJ9RRw7bhKzVyXbnRPsWSfwybYqw9sB7ots/SYyufL1mBpEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.3.tgz", + "integrity": "sha512-cVpWnkx9IYg99EjGxa5Gc0XmqumtAwK3aoz7O4Dii2vko+qXbkHoujWA68cqXjhh6TsLaQelfDO4MVnyr+ODeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.3.tgz", + "integrity": "sha512-RxmhKLbTCDAY2xOfrww6ieIZkZF+KBqG7S2Ako2SljKXRFi+0863PspK74QQ7JpmWwncChY25JTJSbVBYGQk2Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.3.tgz", + "integrity": "sha512-0r36VeEJ4efwmofxVJRXDjVRP2jTmv877zc+i+Pc7MNsIr38NfsjkQj23AfF7l0WbB+RQ7VUb+LDiqC/KY/M/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.3.tgz", + "integrity": "sha512-wgO6rc7uGStH22nur4aLFcq7Wh86bE9cOFmfTr/yxN3BXvDEdCSXyKkO+U5JIt53eTOgC47v9k/C1bITWL/Teg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.3.tgz", + "integrity": "sha512-FdVl64OIuiKjgXBjwZaJLKp0eaEckifbhn10dXWhysMJkWblg3OEEGKSIyhiD5RSgAya8WzP3DNkngtIg3Nt7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "Apache-2.0", + "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, + "license": "Apache-2.0", + "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, + "license": "BSD-3-Clause", + "peer": true + }, + "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, + "license": "MIT", + "peer": true + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "16.18.126", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.126.tgz", + "integrity": "sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.29.0.tgz", + "integrity": "sha512-kgTsISt9pM53yRFQmLZ4npj99yGl3x3Pl7z4eA66OuTzAGC4bQB5H5fuLwPnqTKU3yyrrg4MIhjF17UYnL4c0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "5.29.0", + "@typescript-eslint/type-utils": "5.29.0", + "@typescript-eslint/utils": "5.29.0", + "debug": "^4.3.4", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.2.0", + "regexpp": "^3.2.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.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.29.0.tgz", + "integrity": "sha512-ruKWTv+x0OOxbzIw9nW5oWlUopvP/IQDjB5ZqmTglLIoDTctLlAJpAQFpNPJP/ZI7hTT9sARBosEfaKbcFuECw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "5.29.0", + "@typescript-eslint/types": "5.29.0", + "@typescript-eslint/typescript-estree": "5.29.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.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.29.0.tgz", + "integrity": "sha512-etbXUT0FygFi2ihcxDZjz21LtC+Eps9V2xVx09zFoN44RRHPrkMflidGMI+2dUs821zR1tDS6Oc9IXxIjOUZwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.29.0", + "@typescript-eslint/visitor-keys": "5.29.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.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.29.0.tgz", + "integrity": "sha512-JK6bAaaiJozbox3K220VRfCzLa9n0ib/J+FHIwnaV3Enw/TO267qe0pM1b1QrrEuy6xun374XEAsRlA86JJnyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "5.29.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.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.29.0.tgz", + "integrity": "sha512-X99VbqvAXOMdVyfFmksMy3u8p8yoRGITgU1joBJPzeYa0rhdf5ok9S56/itRoUSh99fiDoMtarSIJXo7H/SnOg==", + "dev": true, + "license": "MIT", + "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.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.29.0.tgz", + "integrity": "sha512-mQvSUJ/JjGBdvo+1LwC+GY2XmSYjK1nAaVw2emp/E61wEVYEyibRHCqm1I1vEKbXCpUKuW4G7u9ZCaZhJbLoNQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "5.29.0", + "@typescript-eslint/visitor-keys": "5.29.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.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.29.0.tgz", + "integrity": "sha512-3Eos6uP1nyLOBayc/VUdKZikV90HahXE5Dx9L5YlSd/7ylQPXhLk1BYb29SDgnBnTp+jmSZUU0QxUiyHgW4p7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.29.0", + "@typescript-eslint/types": "5.29.0", + "@typescript-eslint/typescript-estree": "5.29.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "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.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.29.0.tgz", + "integrity": "sha512-Hpb/mCWsjILvikMQoZIE3voc9wtQcS0A9FUw3h8bhr9UxBdtI/tw1ZDZUOXHXLOVMedKCH5NxyzATwnU78bWCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.29.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, + "license": "ISC", + "peer": true + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "peer": 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, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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, + "license": "Python-2.0", + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "peer": true + }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6.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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "peer": 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/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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "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, + "license": "MIT", + "peer": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "license": "MIT", + "dependencies": { + "utrie": "^1.0.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "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, + "license": "MIT", + "peer": true + }, + "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, + "license": "MIT", + "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, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-to-image-more": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/dom-to-image-more/-/dom-to-image-more-3.7.2.tgz", + "integrity": "sha512-uQf+pHv6eQhgfI8t2bFuinV0KsPyT8TZgCLwcSU8uBVgN9v6leb0mMpvp6HQAlAcplP3NCcGjxbdqef6pTzvmw==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.3.tgz", + "integrity": "sha512-9n3AsBRe6sIyOc6kmoXg2ypCLgf3eZSraWFRpnkto+svt8cZNuKTkb1bhQcitBcvIqjNiK7K0J3KPmwGSfkA8g==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.3", + "@esbuild/android-arm64": "0.17.3", + "@esbuild/android-x64": "0.17.3", + "@esbuild/darwin-arm64": "0.17.3", + "@esbuild/darwin-x64": "0.17.3", + "@esbuild/freebsd-arm64": "0.17.3", + "@esbuild/freebsd-x64": "0.17.3", + "@esbuild/linux-arm": "0.17.3", + "@esbuild/linux-arm64": "0.17.3", + "@esbuild/linux-ia32": "0.17.3", + "@esbuild/linux-loong64": "0.17.3", + "@esbuild/linux-mips64el": "0.17.3", + "@esbuild/linux-ppc64": "0.17.3", + "@esbuild/linux-riscv64": "0.17.3", + "@esbuild/linux-s390x": "0.17.3", + "@esbuild/linux-x64": "0.17.3", + "@esbuild/netbsd-x64": "0.17.3", + "@esbuild/openbsd-x64": "0.17.3", + "@esbuild/sunos-x64": "0.17.3", + "@esbuild/win32-arm64": "0.17.3", + "@esbuild/win32-ia32": "0.17.3", + "@esbuild/win32-x64": "0.17.3" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "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, + "license": "Apache-2.0", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "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/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, + "license": "BSD-3-Clause", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": ">=0.10.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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "ISC", + "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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "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, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "ISC", + "peer": true + }, + "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, + "license": "ISC", + "peer": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "ISC", + "peer": 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, + "license": "ISC", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT", + "peer": true + }, + "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, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "license": "MIT", + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.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, + "license": "MIT", + "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, + "license": "MIT", + "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/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "peer": 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, + "license": "ISC", + "peer": 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, + "license": "ISC", + "peer": 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, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC", + "peer": 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, + "license": "MIT", + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "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, + "license": "MIT", + "peer": true + }, + "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, + "license": "MIT", + "peer": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "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, + "license": "MIT", + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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, + "license": "MIT", + "peer": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.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, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT" + }, + "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, + "license": "MIT", + "peer": true + }, + "node_modules/obsidian": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.12.3.tgz", + "integrity": "sha512-HxWqe763dOqzXjnNiHmAJTRERN8KILBSqxDSEqbeSr7W8R8Jxezzbca+nz1LiiqXnMpM8lV2jzAezw3CZ4xNUw==", + "dev": true, + "license": "MIT", + "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, + "license": "ISC", + "peer": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "peer": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "peer": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "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, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "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" + } + ], + "license": "MIT" + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "ISC", + "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" + } + ], + "license": "MIT", + "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, + "license": "ISC", + "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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "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, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "license": "MIT", + "dependencies": { + "utrie": "^1.0.2" + } + }, + "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, + "license": "MIT", + "peer": 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, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true, + "license": "0BSD" + }, + "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, + "license": "MIT", + "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, + "license": "0BSD" + }, + "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, + "license": "MIT", + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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, + "license": "(MIT OR CC0-1.0)", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.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, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "license": "MIT", + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, + "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, + "license": "MIT", + "peer": true + }, + "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, + "license": "ISC", + "peer": 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, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "ISC", + "peer": true + }, + "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, + "license": "MIT", + "peer": 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..193b1d6 --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "vitepress-exporter", + "version": "0.1.0", + "description": "Export Obsidian notes to VitePress", + "main": "main.js", + "scripts": { + "dev": "node esbuild.config.mjs", + "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production", + "version": "node version-bump.mjs && git add manifest.json versions.json" + }, + "keywords": [ + "obsidian", + "vitepress", + "export" + ], + "author": "Your Name", + "license": "MIT", + "devDependencies": { + "@types/node": "^16.11.6", + "@typescript-eslint/eslint-plugin": "5.29.0", + "@typescript-eslint/parser": "5.29.0", + "builtin-modules": "3.3.0", + "dom-to-image-more": "^3.7.2", + "esbuild": "0.17.3", + "obsidian": "latest", + "tslib": "2.4.0", + "typescript": "4.7.4" + }, + "dependencies": { + "dom-to-image-more": "^3.7.2" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..9e80298 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1443 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@types/node': + specifier: ^16.11.6 + version: 16.18.126 + '@typescript-eslint/eslint-plugin': + specifier: 5.29.0 + version: 5.29.0(@typescript-eslint/parser@5.29.0(eslint@8.57.1)(typescript@4.7.4))(eslint@8.57.1)(typescript@4.7.4) + '@typescript-eslint/parser': + specifier: 5.29.0 + version: 5.29.0(eslint@8.57.1)(typescript@4.7.4) + builtin-modules: + specifier: 3.3.0 + version: 3.3.0 + dom-to-image-more: + specifier: ^3.7.2 + version: 3.7.2 + esbuild: + specifier: 0.17.3 + version: 0.17.3 + obsidian: + specifier: latest + version: 1.12.3(@codemirror/state@6.5.0)(@codemirror/view@6.38.6) + tslib: + specifier: 2.4.0 + version: 2.4.0 + typescript: + specifier: 4.7.4 + version: 4.7.4 + +packages: + + '@codemirror/state@6.5.0': + resolution: {integrity: sha512-MwBHVK60IiIHDcoMet78lxt6iw5gJOGSbNbOIVBHWVXIH4/Nq1+GQgLLGgI1KlnN86WDXsPudVaqYHKBIx7Eyw==} + + '@codemirror/view@6.38.6': + resolution: {integrity: sha512-qiS0z1bKs5WOvHIAC0Cybmv4AJSkAXgX5aD6Mqd2epSLlVJsQl8NG23jCVouIgkh4All/mrbdsf2UOLFnJw0tw==} + + '@esbuild/android-arm64@0.17.3': + resolution: {integrity: sha512-XvJsYo3dO3Pi4kpalkyMvfQsjxPWHYjoX4MDiB/FUM4YMfWcXa5l4VCwFWVYI1+92yxqjuqrhNg0CZg3gSouyQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.17.3': + resolution: {integrity: sha512-1Mlz934GvbgdDmt26rTLmf03cAgLg5HyOgJN+ZGCeP3Q9ynYTNMn2/LQxIl7Uy+o4K6Rfi2OuLsr12JQQR8gNg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.17.3': + resolution: {integrity: sha512-nuV2CmLS07Gqh5/GrZLuqkU9Bm6H6vcCspM+zjp9TdQlxJtIe+qqEXQChmfc7nWdyr/yz3h45Utk1tUn8Cz5+A==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.17.3': + resolution: {integrity: sha512-01Hxaaat6m0Xp9AXGM8mjFtqqwDjzlMP0eQq9zll9U85ttVALGCGDuEvra5Feu/NbP5AEP1MaopPwzsTcUq1cw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.17.3': + resolution: {integrity: sha512-Eo2gq0Q/er2muf8Z83X21UFoB7EU6/m3GNKvrhACJkjVThd0uA+8RfKpfNhuMCl1bKRfBzKOk6xaYKQZ4lZqvA==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.17.3': + resolution: {integrity: sha512-CN62ESxaquP61n1ZjQP/jZte8CE09M6kNn3baos2SeUfdVBkWN5n6vGp2iKyb/bm/x4JQzEvJgRHLGd5F5b81w==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.17.3': + resolution: {integrity: sha512-feq+K8TxIznZE+zhdVurF3WNJ/Sa35dQNYbaqM/wsCbWdzXr5lyq+AaTUSER2cUR+SXPnd/EY75EPRjf4s1SLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.17.3': + resolution: {integrity: sha512-JHeZXD4auLYBnrKn6JYJ0o5nWJI9PhChA/Nt0G4MvLaMrvXuWnY93R3a7PiXeJQphpL1nYsaMcoV2QtuvRnF/g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.17.3': + resolution: {integrity: sha512-CLP3EgyNuPcg2cshbwkqYy5bbAgK+VhyfMU7oIYyn+x4Y67xb5C5ylxsNUjRmr8BX+MW3YhVNm6Lq6FKtRTWHQ==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.17.3': + resolution: {integrity: sha512-FyXlD2ZjZqTFh0sOQxFDiWG1uQUEOLbEh9gKN/7pFxck5Vw0qjWSDqbn6C10GAa1rXJpwsntHcmLqydY9ST9ZA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.17.3': + resolution: {integrity: sha512-OrDGMvDBI2g7s04J8dh8/I7eSO+/E7nMDT2Z5IruBfUO/RiigF1OF6xoH33Dn4W/OwAWSUf1s2nXamb28ZklTA==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.17.3': + resolution: {integrity: sha512-DcnUpXnVCJvmv0TzuLwKBC2nsQHle8EIiAJiJ+PipEVC16wHXaPEKP0EqN8WnBe0TPvMITOUlP2aiL5YMld+CQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.17.3': + resolution: {integrity: sha512-BDYf/l1WVhWE+FHAW3FzZPtVlk9QsrwsxGzABmN4g8bTjmhazsId3h127pliDRRu5674k1Y2RWejbpN46N9ZhQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.17.3': + resolution: {integrity: sha512-WViAxWYMRIi+prTJTyV1wnqd2mS2cPqJlN85oscVhXdb/ZTFJdrpaqm/uDsZPGKHtbg5TuRX/ymKdOSk41YZow==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.17.3': + resolution: {integrity: sha512-Iw8lkNHUC4oGP1O/KhumcVy77u2s6+KUjieUqzEU3XuWJqZ+AY7uVMrrCbAiwWTkpQHkr00BuXH5RpC6Sb/7Ug==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.17.3': + resolution: {integrity: sha512-0AGkWQMzeoeAtXQRNB3s4J1/T2XbigM2/Mn2yU1tQSmQRmHIZdkGbVq2A3aDdNslPyhb9/lH0S5GMTZ4xsjBqg==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.17.3': + resolution: {integrity: sha512-4+rR/WHOxIVh53UIQIICryjdoKdHsFZFD4zLSonJ9RRw7bhKzVyXbnRPsWSfwybYqw9sB7ots/SYyufL1mBpEg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.17.3': + resolution: {integrity: sha512-cVpWnkx9IYg99EjGxa5Gc0XmqumtAwK3aoz7O4Dii2vko+qXbkHoujWA68cqXjhh6TsLaQelfDO4MVnyr+ODeA==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.17.3': + resolution: {integrity: sha512-RxmhKLbTCDAY2xOfrww6ieIZkZF+KBqG7S2Ako2SljKXRFi+0863PspK74QQ7JpmWwncChY25JTJSbVBYGQk2Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.17.3': + resolution: {integrity: sha512-0r36VeEJ4efwmofxVJRXDjVRP2jTmv877zc+i+Pc7MNsIr38NfsjkQj23AfF7l0WbB+RQ7VUb+LDiqC/KY/M/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.17.3': + resolution: {integrity: sha512-wgO6rc7uGStH22nur4aLFcq7Wh86bE9cOFmfTr/yxN3BXvDEdCSXyKkO+U5JIt53eTOgC47v9k/C1bITWL/Teg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.17.3': + resolution: {integrity: sha512-FdVl64OIuiKjgXBjwZaJLKp0eaEckifbhn10dXWhysMJkWblg3OEEGKSIyhiD5RSgAya8WzP3DNkngtIg3Nt7g==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@humanwhocodes/config-array@0.13.0': + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + + '@marijn/find-cluster-break@1.0.2': + resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@types/codemirror@5.60.8': + resolution: {integrity: sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/node@16.18.126': + resolution: {integrity: sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==} + + '@types/tern@0.23.9': + resolution: {integrity: sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==} + + '@typescript-eslint/eslint-plugin@5.29.0': + resolution: {integrity: sha512-kgTsISt9pM53yRFQmLZ4npj99yGl3x3Pl7z4eA66OuTzAGC4bQB5H5fuLwPnqTKU3yyrrg4MIhjF17UYnL4c0w==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@5.29.0': + resolution: {integrity: sha512-ruKWTv+x0OOxbzIw9nW5oWlUopvP/IQDjB5ZqmTglLIoDTctLlAJpAQFpNPJP/ZI7hTT9sARBosEfaKbcFuECw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/scope-manager@5.29.0': + resolution: {integrity: sha512-etbXUT0FygFi2ihcxDZjz21LtC+Eps9V2xVx09zFoN44RRHPrkMflidGMI+2dUs821zR1tDS6Oc9IXxIjOUZwA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@typescript-eslint/type-utils@5.29.0': + resolution: {integrity: sha512-JK6bAaaiJozbox3K220VRfCzLa9n0ib/J+FHIwnaV3Enw/TO267qe0pM1b1QrrEuy6xun374XEAsRlA86JJnyg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/types@5.29.0': + resolution: {integrity: sha512-X99VbqvAXOMdVyfFmksMy3u8p8yoRGITgU1joBJPzeYa0rhdf5ok9S56/itRoUSh99fiDoMtarSIJXo7H/SnOg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@typescript-eslint/typescript-estree@5.29.0': + resolution: {integrity: sha512-mQvSUJ/JjGBdvo+1LwC+GY2XmSYjK1nAaVw2emp/E61wEVYEyibRHCqm1I1vEKbXCpUKuW4G7u9ZCaZhJbLoNQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/utils@5.29.0': + resolution: {integrity: sha512-3Eos6uP1nyLOBayc/VUdKZikV90HahXE5Dx9L5YlSd/7ylQPXhLk1BYb29SDgnBnTp+jmSZUU0QxUiyHgW4p7A==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + + '@typescript-eslint/visitor-keys@5.29.0': + resolution: {integrity: sha512-Hpb/mCWsjILvikMQoZIE3voc9wtQcS0A9FUw3h8bhr9UxBdtI/tw1ZDZUOXHXLOVMedKCH5NxyzATwnU78bWCQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@1.1.14: + resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + builtin-modules@3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + dom-to-image-more@3.7.2: + resolution: {integrity: sha512-uQf+pHv6eQhgfI8t2bFuinV0KsPyT8TZgCLwcSU8uBVgN9v6leb0mMpvp6HQAlAcplP3NCcGjxbdqef6pTzvmw==} + + esbuild@0.17.3: + resolution: {integrity: sha512-9n3AsBRe6sIyOc6kmoXg2ypCLgf3eZSraWFRpnkto+svt8cZNuKTkb1bhQcitBcvIqjNiK7K0J3KPmwGSfkA8g==} + engines: {node: '>=12'} + hasBin: true + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-utils@3.0.0: + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + + eslint-visitor-keys@2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + functional-red-black-tree@1.0.1: + resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@7.2.3: + resolution: {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 + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {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. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + moment@2.29.4: + resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + obsidian@1.12.3: + resolution: {integrity: sha512-HxWqe763dOqzXjnNiHmAJTRERN8KILBSqxDSEqbeSr7W8R8Jxezzbca+nz1LiiqXnMpM8lV2jzAezw3CZ4xNUw==} + peerDependencies: + '@codemirror/state': 6.5.0 + '@codemirror/view': 6.38.6 + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + regexpp@3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + style-mod@4.1.3: + resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tslib@2.4.0: + resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} + + tsutils@3.21.0: + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + 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' + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + typescript@4.7.4: + resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==} + engines: {node: '>=4.2.0'} + hasBin: true + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@codemirror/state@6.5.0': + dependencies: + '@marijn/find-cluster-break': 1.0.2 + + '@codemirror/view@6.38.6': + dependencies: + '@codemirror/state': 6.5.0 + crelt: 1.0.6 + style-mod: 4.1.3 + w3c-keyname: 2.2.8 + + '@esbuild/android-arm64@0.17.3': + optional: true + + '@esbuild/android-arm@0.17.3': + optional: true + + '@esbuild/android-x64@0.17.3': + optional: true + + '@esbuild/darwin-arm64@0.17.3': + optional: true + + '@esbuild/darwin-x64@0.17.3': + optional: true + + '@esbuild/freebsd-arm64@0.17.3': + optional: true + + '@esbuild/freebsd-x64@0.17.3': + optional: true + + '@esbuild/linux-arm64@0.17.3': + optional: true + + '@esbuild/linux-arm@0.17.3': + optional: true + + '@esbuild/linux-ia32@0.17.3': + optional: true + + '@esbuild/linux-loong64@0.17.3': + optional: true + + '@esbuild/linux-mips64el@0.17.3': + optional: true + + '@esbuild/linux-ppc64@0.17.3': + optional: true + + '@esbuild/linux-riscv64@0.17.3': + optional: true + + '@esbuild/linux-s390x@0.17.3': + optional: true + + '@esbuild/linux-x64@0.17.3': + optional: true + + '@esbuild/netbsd-x64@0.17.3': + optional: true + + '@esbuild/openbsd-x64@0.17.3': + optional: true + + '@esbuild/sunos-x64@0.17.3': + optional: true + + '@esbuild/win32-arm64@0.17.3': + optional: true + + '@esbuild/win32-ia32@0.17.3': + optional: true + + '@esbuild/win32-x64@0.17.3': + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)': + dependencies: + eslint: 8.57.1 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/eslintrc@2.1.4': + dependencies: + ajv: 6.14.0 + debug: 4.4.3 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@8.57.1': {} + + '@humanwhocodes/config-array@0.13.0': + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/object-schema@2.0.3': {} + + '@marijn/find-cluster-break@1.0.2': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@types/codemirror@5.60.8': + dependencies: + '@types/tern': 0.23.9 + + '@types/estree@1.0.8': {} + + '@types/json-schema@7.0.15': {} + + '@types/node@16.18.126': {} + + '@types/tern@0.23.9': + dependencies: + '@types/estree': 1.0.8 + + '@typescript-eslint/eslint-plugin@5.29.0(@typescript-eslint/parser@5.29.0(eslint@8.57.1)(typescript@4.7.4))(eslint@8.57.1)(typescript@4.7.4)': + dependencies: + '@typescript-eslint/parser': 5.29.0(eslint@8.57.1)(typescript@4.7.4) + '@typescript-eslint/scope-manager': 5.29.0 + '@typescript-eslint/type-utils': 5.29.0(eslint@8.57.1)(typescript@4.7.4) + '@typescript-eslint/utils': 5.29.0(eslint@8.57.1)(typescript@4.7.4) + debug: 4.4.3 + eslint: 8.57.1 + functional-red-black-tree: 1.0.1 + ignore: 5.3.2 + regexpp: 3.2.0 + semver: 7.7.4 + tsutils: 3.21.0(typescript@4.7.4) + optionalDependencies: + typescript: 4.7.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@5.29.0(eslint@8.57.1)(typescript@4.7.4)': + dependencies: + '@typescript-eslint/scope-manager': 5.29.0 + '@typescript-eslint/types': 5.29.0 + '@typescript-eslint/typescript-estree': 5.29.0(typescript@4.7.4) + debug: 4.4.3 + eslint: 8.57.1 + optionalDependencies: + typescript: 4.7.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@5.29.0': + dependencies: + '@typescript-eslint/types': 5.29.0 + '@typescript-eslint/visitor-keys': 5.29.0 + + '@typescript-eslint/type-utils@5.29.0(eslint@8.57.1)(typescript@4.7.4)': + dependencies: + '@typescript-eslint/utils': 5.29.0(eslint@8.57.1)(typescript@4.7.4) + debug: 4.4.3 + eslint: 8.57.1 + tsutils: 3.21.0(typescript@4.7.4) + optionalDependencies: + typescript: 4.7.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@5.29.0': {} + + '@typescript-eslint/typescript-estree@5.29.0(typescript@4.7.4)': + dependencies: + '@typescript-eslint/types': 5.29.0 + '@typescript-eslint/visitor-keys': 5.29.0 + debug: 4.4.3 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.7.4 + tsutils: 3.21.0(typescript@4.7.4) + optionalDependencies: + typescript: 4.7.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@5.29.0(eslint@8.57.1)(typescript@4.7.4)': + dependencies: + '@types/json-schema': 7.0.15 + '@typescript-eslint/scope-manager': 5.29.0 + '@typescript-eslint/types': 5.29.0 + '@typescript-eslint/typescript-estree': 5.29.0(typescript@4.7.4) + eslint: 8.57.1 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0(eslint@8.57.1) + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/visitor-keys@5.29.0': + dependencies: + '@typescript-eslint/types': 5.29.0 + eslint-visitor-keys: 3.4.3 + + '@ungap/structured-clone@1.3.0': {} + + acorn-jsx@5.3.2(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + + acorn@8.16.0: {} + + ajv@6.14.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + array-union@2.1.0: {} + + balanced-match@1.0.2: {} + + brace-expansion@1.1.14: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + builtin-modules@3.3.0: {} + + callsites@3.1.0: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + crelt@1.0.6: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + dom-to-image-more@3.7.2: {} + + esbuild@0.17.3: + optionalDependencies: + '@esbuild/android-arm': 0.17.3 + '@esbuild/android-arm64': 0.17.3 + '@esbuild/android-x64': 0.17.3 + '@esbuild/darwin-arm64': 0.17.3 + '@esbuild/darwin-x64': 0.17.3 + '@esbuild/freebsd-arm64': 0.17.3 + '@esbuild/freebsd-x64': 0.17.3 + '@esbuild/linux-arm': 0.17.3 + '@esbuild/linux-arm64': 0.17.3 + '@esbuild/linux-ia32': 0.17.3 + '@esbuild/linux-loong64': 0.17.3 + '@esbuild/linux-mips64el': 0.17.3 + '@esbuild/linux-ppc64': 0.17.3 + '@esbuild/linux-riscv64': 0.17.3 + '@esbuild/linux-s390x': 0.17.3 + '@esbuild/linux-x64': 0.17.3 + '@esbuild/netbsd-x64': 0.17.3 + '@esbuild/openbsd-x64': 0.17.3 + '@esbuild/sunos-x64': 0.17.3 + '@esbuild/win32-arm64': 0.17.3 + '@esbuild/win32-ia32': 0.17.3 + '@esbuild/win32-x64': 0.17.3 + + escape-string-regexp@4.0.0: {} + + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-utils@3.0.0(eslint@8.57.1): + dependencies: + eslint: 8.57.1 + eslint-visitor-keys: 2.1.0 + + eslint-visitor-keys@2.1.0: {} + + eslint-visitor-keys@3.4.3: {} + + eslint@8.57.1: + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) + '@eslint-community/regexpp': 4.12.2 + '@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.3.0 + ajv: 6.14.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + 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.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.1 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + espree@9.6.1: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 3.4.3 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@4.3.0: {} + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + file-entry-cache@6.0.1: + dependencies: + flat-cache: 3.2.0 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@3.2.0: + dependencies: + flatted: 3.4.2 + keyv: 4.5.4 + rimraf: 3.0.2 + + flatted@3.4.2: {} + + fs.realpath@1.0.0: {} + + functional-red-black-tree@1.0.1: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.5 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + graphemer@1.4.0: {} + + has-flag@4.0.0: {} + + ignore@5.3.2: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-path-inside@3.0.3: {} + + isexe@2.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.14 + + moment@2.29.4: {} + + ms@2.1.3: {} + + natural-compare@1.4.0: {} + + obsidian@1.12.3(@codemirror/state@6.5.0)(@codemirror/view@6.38.6): + dependencies: + '@codemirror/state': 6.5.0 + '@codemirror/view': 6.38.6 + '@types/codemirror': 5.60.8 + moment: 2.29.4 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-type@4.0.0: {} + + picomatch@2.3.2: {} + + prelude-ls@1.2.1: {} + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + regexpp@3.2.0: {} + + resolve-from@4.0.0: {} + + reusify@1.1.0: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + semver@7.7.4: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + slash@3.0.0: {} + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-json-comments@3.1.1: {} + + style-mod@4.1.3: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + text-table@0.2.0: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tslib@1.14.1: {} + + tslib@2.4.0: {} + + tsutils@3.21.0(typescript@4.7.4): + dependencies: + tslib: 1.14.1 + typescript: 4.7.4 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@0.20.2: {} + + typescript@4.7.4: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + w3c-keyname@2.2.8: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrappy@1.0.2: {} + + yocto-queue@0.1.0: {} diff --git a/puppeteer_version.txt b/puppeteer_version.txt new file mode 100644 index 0000000..32fee9c --- /dev/null +++ b/puppeteer_version.txt @@ -0,0 +1,92 @@ + // 尝试使用 Puppeteer 截图 Canvas(保留完整样式) + async tryNativeCanvasCapture(canvasFile: TFile): Promise { + let newWindowLeaf: any = null; + + try { + console.log('🔍 Step 1: Opening canvas in new window...'); + + // 创建新窗口 + newWindowLeaf = this.app.workspace.getLeaf('window'); + if (!newWindowLeaf) { + console.log('❌ Failed to create new window'); + return null; + } + + console.log('✅ New window created, opening canvas file...'); + await newWindowLeaf.openFile(canvasFile); + + console.log('⏳ Step 2: Waiting for canvas render...'); + // 等待 Canvas 渲染 + await new Promise(resolve => setTimeout(resolve, 3000)); + + console.log('📸 Step 3: Capturing with Puppeteer...'); + // @ts-ignore + const puppeteer = require('puppeteer'); + + // 启动 Puppeteer + const browser = await puppeteer.launch({ + headless: true, + args: ['--no-sandbox', '--disable-setuid-sandbox'] + }); + + try { + const page = await browser.newPage(); + + // 获取新窗口的 HTML 内容 + const container = newWindowLeaf.containerEl; + const canvasWrapper = container.querySelector('.canvas-wrapper'); + + if (!canvasWrapper) { + console.log('❌ Could not find canvas wrapper'); + return null; + } + + // 获取完整的 HTML,包括所有样式 + const htmlContent = canvasWrapper.outerHTML; + + // 设置 HTML 内容 + await page.setContent(htmlContent, { + waitUntil: 'networkidle0', + timeout: 10000 + }); + + // 计算内容尺寸 + const contentSize = this.getCanvasContentSize(canvasWrapper); + const viewportWidth = Math.ceil(contentSize.width); + const viewportHeight = Math.ceil(contentSize.height); + + console.log(`📸 Screenshot size: ${viewportWidth}x${viewportHeight}`); + + // 截图 + const screenshot = await page.screenshot({ + type: 'png', + clip: { + x: contentSize.offsetX, + y: contentSize.offsetY, + width: contentSize.width, + height: contentSize.height + } + }); + + console.log('✅ Capture successful!'); + return new Uint8Array(screenshot); + + } finally { + await browser.close(); + } + + } catch (error) { + console.error('❌ Puppeteer capture failed:', error); + return null; + } finally { + // 关闭新窗口 + if (newWindowLeaf) { + try { + newWindowLeaf.detach(); + console.log('🧹 Closed new window'); + } catch (e) { + console.log('⚠️ Could not close new window:', e); + } + } + } + } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..0ee61f0 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "inlineSourceMap": true, + "inlineSources": true, + "module": "ESNext", + "target": "ES6", + "allowJs": true, + "noImplicitAny": true, + "moduleResolution": "node", + "importHelpers": true, + "isolatedModules": true, + "strictNullChecks": true, + "lib": [ + "DOM", + "ES5", + "ES6", + "ES7" + ] + }, + "include": [ + "**/*.ts" + ], + "exclude": [ + "node_modules", + "docs", + "**/*.vue" + ] +}