diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..84b8a66 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +# top-most EditorConfig file +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = tab +indent_size = 4 +tab_width = 4 diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..e019f3c --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +node_modules/ + +main.js diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..0807290 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,23 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "env": { "node": true }, + "plugins": [ + "@typescript-eslint" + ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + "parserOptions": { + "sourceType": "module" + }, + "rules": { + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }], + "@typescript-eslint/ban-ts-comment": "off", + "no-prototype-builtins": "off", + "@typescript-eslint/no-empty-function": "off" + } + } \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..8065860 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,35 @@ +name: Release Obsidian plugin + +on: + push: + tags: + - "*" + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v3 + + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: "18.x" + + - name: Build plugin + run: | + npm install + npm run build + + - name: Create release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + tag="${GITHUB_REF#refs/tags/}" + + gh release create "$tag" \ + --title="$tag" \ + --draft \ + main.js manifest.json styles.css \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..b973752 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +tag-version-prefix="" \ No newline at end of file diff --git a/README.md b/README.md index cd3b3a0..987c413 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ ## OpenWords - 简介 - - **OpenWords** 是一个用于背单词和单词管理的 [Obsidian](https://obsidian.md/) 简单插件, 使用 SuperMemo 2 间隔重复算法以及 OpenText 单词库. 依赖的第三方包主要是用于重复计算的 [supermemo](https://www.npmjs.com/package/supermemo) 和用于词形还原的 [wink-pos-tagger](https://www.npmjs.com/package/wink-pos-tagger) - - ![p7](README/p7.png) + - **OpenWords** 是一个用于背单词和单词管理的 [Obsidian](https://obsidian.md/) 简单插件, 插件入口是左侧工具栏的一个按钮加上两个命令. 使用 SuperMemo 2 间隔重复算法以及 OpenText 单词库. 依赖的第三方包主要是用于重复计算的 [supermemo](https://www.npmjs.com/package/supermemo) 和用于词形还原的 [wink-pos-tagger](https://www.npmjs.com/package/wink-pos-tagger). 本插件完全依赖单词文件及其属性, 没有表格, Json 等外部存储, 启动时会读取所有单词缓存属性, 并在更改时写入相应的单词文件, 没有设计过多的搜索功能, 可以使用内置的属性搜索单词 + - ![p7](p7.png) - 单词 - - **单词库**以 [OpenText](opentext.net.cn) 为参考, 是 Obsidian 仓库中的一个文件夹, 其中按首字母分类储存所有单词文件, 单词即为文件名, 元数据使用文件 YAML 属性, 其中复选框和标签用于确定插件运行的作用域, 数字和日期是 SM 2 的计算参数. 本插件完全依赖单词文件及其属性, 没有表格, Json 等外部存储, 启动时会读取所有单词缓存属性, 并在更改时写入相应的单词文件 + - **单词库**以 [OpenText](opentext.net.cn) 为参考, 是 Obsidian 仓库中的一个文件夹, 其中按首字母分类储存所有单词文件, 单词即为文件名, 元数据使用文件 YAML 属性, 其中复选框和标签用于确定插件运行的作用域, 数字和日期是 SM 2 的计算参数 - 复选框: `掌握` , 确定插件作用域, 单词被掌握意味着不会被插件处理 - 标签: `级别/小学`, `级别/中考`, `级别/高考四级`, `级别/考研`, `级别/六级`, `级别/雅思`, `级别/托福`, `级别/GRE`, 确定插件作用域, 标签意味着当前主要精力范围, 设置中没有勾选意味着不会被插件处理 - 数字: `重复次数`, 连续正确回答的次数, 初始值为 0 @@ -26,8 +26,11 @@ - 背单词 - 新词指重复次数为 0 的单词, 它可能是从未被学习过的, 也可能是前面学后面忘了的. 新词调度中 70% 纯随机, 30% 从易记因子和重复次数最低的 20% 中随机; 旧词指重复次数大于 0 的单词, 它是之前回答正确的. 旧词调度从已过期的单词中 70% 纯随机, 30% 从易记因子和重复次数最低的 20% 中随机. 应该尽可能的提高每个单词的重复次数和易记因子 - ![p4](README/p4.gif) + - 默写单词 + - 从作用域中随机抽取单词进行拼写, 目前只是一个练习功能, 不会改变更改单词的属性, 按下 `Tab` 键显示答案 + - ![](README/p8.gif) - 添加双链 - - 为当前活动页面笔记中的单词添加双链, 单词范围是作用域中易记因子小于等于 2.5 的, 所以默认属性都是添加的. 准确率在 90 % + - 为当前活动页面笔记中的单词添加双链, 单词范围是作用域中易记因子小于等于 2.5 的, 所以默认属性都是添加的. 准确率在 90 %. 需要文章尽可能规范, 减少不必要的标点符号. 目前只能通过 `ctrl z` 回撤 - ![p5](README/p5.gif) - 重置单词属性 - 重置作用域单词的重复次数, 间隔, 易记因子, 到期日为默认值, 重置读写会很慢 diff --git a/README/p7.png b/README/p7.png index 5621c8b..341f590 100644 Binary files a/README/p7.png and b/README/p7.png differ diff --git a/README/p8.gif b/README/p8.gif new file mode 100644 index 0000000..35240c7 Binary files /dev/null and b/README/p8.gif differ diff --git a/esbuild.config.mjs b/esbuild.config.mjs new file mode 100644 index 0000000..a5de8b8 --- /dev/null +++ b/esbuild.config.mjs @@ -0,0 +1,49 @@ +import esbuild from "esbuild"; +import process from "process"; +import builtins from "builtin-modules"; + +const banner = +`/* +THIS IS A GENERATED/BUNDLED FILE BY ESBUILD +if you want to view the source, please visit the github repository of this plugin +*/ +`; + +const prod = (process.argv[2] === "production"); + +const context = await esbuild.context({ + banner: { + js: banner, + }, + entryPoints: ["main.ts"], + bundle: true, + external: [ + "obsidian", + "electron", + "@codemirror/autocomplete", + "@codemirror/collab", + "@codemirror/commands", + "@codemirror/language", + "@codemirror/lint", + "@codemirror/search", + "@codemirror/state", + "@codemirror/view", + "@lezer/common", + "@lezer/highlight", + "@lezer/lr", + ...builtins], + format: "cjs", + target: "es2018", + logLevel: "info", + sourcemap: prod ? false : "inline", + treeShaking: true, + outfile: "main.js", + minify: prod, +}); + +if (prod) { + await context.rebuild(); + process.exit(0); +} else { + await context.watch(); +} diff --git a/main.ts b/main.ts new file mode 100644 index 0000000..39f2f37 --- /dev/null +++ b/main.ts @@ -0,0 +1,1186 @@ +import { App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, TFile, Setting, TFolder, MarkdownRenderer, normalizePath } from 'obsidian'; +const posTagger = require( 'wink-pos-tagger' ); +const dayjs = require("dayjs"); +import { supermemo, SuperMemoItem, SuperMemoGrade } from 'supermemo'; + +// 插件设置 +interface OpenWordsSettings { + folderPath: string; // 用户指定的单词文件夹路径 + indexPath: string; // 用户指定的索引文件夹路径 + enableWords1: boolean; + enableWords2: boolean; + enableWords3: boolean; + enableWords4: boolean; + enableWords5: boolean; + enableWords6: boolean; + enableWords7: boolean; + enableWords8: boolean; +} + +// 默认设置 +const DEFAULT_SETTINGS: OpenWordsSettings = { + folderPath: normalizePath(""), + indexPath: normalizePath("索引"), + enableWords1: false, + enableWords2: false, + enableWords3: false, + enableWords4: false, + enableWords5: false, + enableWords6: false, + enableWords7: false, + enableWords8: false, +} + +// 单词卡片信息 +interface CardInfo extends SuperMemoItem { + front: string; + dueDate: string; + path: string; + isMastered: boolean; +} + +// 插件主类 +export default class OpenWords extends Plugin { + settings: OpenWordsSettings; // 插件设置 + settingsSnapshot: OpenWordsSettings; // 插件设置快照 + statusBarItem: HTMLElement; // 状态栏元素 + alllCards: Map = new Map(); // 存储所有单词的元数据 + allCards: Map = new Map(); // 存储作用域单词的元数据 + newCards: Map = new Map(); // 存储新单词的元数据 + dueCards: Map = new Map(); // 存储旧单词的元数据 + tagger = posTagger(); // 词性标注器实例 + + // 插件加载时执行的操作 + async onload() { + // 加载插件设置参数, 状态栏, 设置选项卡, 左侧工具栏按钮 + await this.loadSettings(); + this.statusBarItem = this.addStatusBarItem(); + this.addSettingTab(new OpenWordsSettingTab(this.app, this)); + const ribbonIconEl = this.addRibbonIcon('slack', 'OpenWords', async (evt: MouseEvent) => { + new LearningTypeModal(this.app, this).open(); + }); + + // 等待布局完成 + this.app.workspace.onLayoutReady(async () => { + // 学习模式命令 + this.addCommand({ + id: 'LearningTypeModal', + name: '学习模式', + callback: () => { + new LearningTypeModal(this.app, this).open(); + } + }); + // 添加双链命令 + this.addCommand({ + id: 'addDoubleBrackets', + name: '添加双链', + callback: () => { + this.addDoubleBrackets(); + } + }); + // 监听单词文件创建事件 + this.registerEvent(this.app.vault.on("create", (file: TFile) => { + if (file.path.endsWith(".md") && file.path.startsWith(this.settings.folderPath)) { + this.loadWordMetadata(file); + } + })); + // 监听单词文件删除事件 + this.registerEvent(this.app.vault.on("delete", (file: TFile) => { + if (file.path.endsWith(".md") && file.path.startsWith(this.settings.folderPath)) { + this.allCards.delete(file.basename); + this.newCards.delete(file.basename); + this.dueCards.delete(file.basename); + this.statusBarItem.setText(`${this.newCards.size} + ${this.dueCards.size} = ${this.allCards.size}`); + } + })); + // 监听单词文件缓存修改事件 + this.registerEvent(this.app.metadataCache.on("changed", (file) => { + if (file.path.endsWith(".md") && file.path.startsWith(this.settings.folderPath)) { + this.loadWordMetadata(file); + } + })); + // 扫描所有单词文件 + await this.scanAllNotes(); + }); + } + + // 加载单词元数据 + async loadWordMetadata(file: TFile) { + const allCards = this.allCards; + const newCards = this.newCards; + const dueCards = this.dueCards; + + // 先删除旧的单词元数据 + allCards.delete(file.basename); + newCards.delete(file.basename); + dueCards.delete(file.basename); + + // 从 metadataCache 获取文件的 FrontMatter + const fileCache = this.app.metadataCache.getFileCache(file); + const frontMatter = fileCache?.frontmatter; + + // 如果文件没有 FrontMatter,直接返回 + if (!frontMatter) { + return; + } + + const tags: string[] = frontMatter.tags || []; + const isMastered = frontMatter.掌握 === true; + console.log(frontMatter) + const isEnabled = + (this.settings.enableWords1 && tags.includes('级别/小学')) || + (this.settings.enableWords2 && tags.includes('级别/中考')) || + (this.settings.enableWords3 && tags.includes('级别/高考四级')) || + (this.settings.enableWords4 && tags.includes('级别/考研')) || + (this.settings.enableWords5 && tags.includes('级别/六级')) || + (this.settings.enableWords6 && tags.includes('级别/雅思')) || + (this.settings.enableWords7 && tags.includes('级别/托福')) || + (this.settings.enableWords8 && tags.includes('级别/GRE')); + + const card: CardInfo = { + front: file.basename, + path: file.path, + dueDate: frontMatter.到期日, + interval: frontMatter.间隔, + efactor: frontMatter.易记因子 * 0.01, + repetition: frontMatter.重复次数, + isMastered: isMastered, + }; + + const isMasteredOld = this.alllCards.get(card.front)?.isMastered; + this.alllCards.set(card.front, card); + + // 再添加新的单词元数据 + if (isEnabled && !isMastered) { + allCards.set(card.front, card); + if (frontMatter.重复次数 === 0) { + newCards.set(card.front, card); + } else { + dueCards.set(card.front, card); + } + } + + // 如果掌握状态发生变化,更新复选框 + if (isMastered !== isMasteredOld && isMasteredOld !== undefined) { + const newCheckbox = isMastered ? 'x' : ' '; + const oldCheckbox = isMasteredOld ? 'x' : ' '; + console.log(file, newCheckbox, oldCheckbox) + await this.syncMetadataToCheckbox(file, newCheckbox, oldCheckbox); + } + + this.statusBarItem.setText(`${this.newCards.size} + ${this.dueCards.size} = ${this.allCards.size}`); + } + + // 扫描所有单词文件 + async scanAllNotes() { + this.alllCards.clear(); + this.allCards.clear(); + this.newCards.clear(); + this.dueCards.clear(); + const files = this.app.vault.getMarkdownFiles(); + const filteredFiles = files.filter(file => file.path.startsWith(this.settings.folderPath)); + if (filteredFiles.length === 0) { + new Notice('指定的文件夹下没有 Markdown 文件!'); + this.statusBarItem.setText(`${this.newCards.size} + ${this.dueCards.size} = ${this.allCards.size}`); + return; + } + const notice = new Notice('缓存中...', 0); // 创建一个持续显示的 Notice + + await Promise.all(filteredFiles.map(async (file) => { + await this.loadWordMetadata(file); + notice.setMessage(`缓存中... ${this.allCards.size}/${filteredFiles.length}`); // 更新 Notice 的消息 + })); + notice.setMessage(`缓存完成!共 ${this.allCards.size} 个单词`); // 完成后更新消息 + setTimeout(() => notice.hide(), 2000); // 2 秒后自动隐藏 Notice + } + + // 更新单词属性 + async updateCard(card: CardInfo, grade: SuperMemoGrade) { + const result = supermemo(card, grade); + const newDate = dayjs().add(result.interval, 'day').format('YYYY-MM-DD'); + const file = this.app.vault.getFileByPath(card.path) as TFile; + this.newCards.delete(card.front); + this.dueCards.delete(card.front); + await this.app.fileManager.processFrontMatter(file, (frontMatter) => { + frontMatter.到期日 = newDate; + frontMatter.间隔 = result.interval; + frontMatter.易记因子 = Math.round(result.efactor * 100); + frontMatter.重复次数 = result.repetition; + }); + new Notice(`${card.front} \n易记因子: ${result.efactor.toFixed(2)} \n重复次数: ${result.repetition} \n间隔: ${result.interval} \n到期日: ${newDate}`); + + } + + // 重置单词属性 + async resetCard() { + if (this.allCards.size === 0) { + new Notice("没有单词需要重置!"); + return; + } + const notice = new Notice('重置中...', 0); // 创建一个持续显示的 Notice + let count = 0; // 计数器 + const cardList = Array.from(this.allCards.values()); // 将 Map 转换为数组 + for (const card of cardList) { + const file = this.app.vault.getFileByPath(card.path) as TFile; + await this.app.fileManager.processFrontMatter(file, (frontMatter) => { + frontMatter.到期日 = dayjs().format('YYYY-MM-DD'); + frontMatter.间隔 = 0; + frontMatter.易记因子 = 250; + frontMatter.重复次数 = 0; + }); + count++; // 增加计数器 + notice.setMessage(`重置中... ${count}/${this.allCards.size}`); // 更新 Notice 的消息 + }; + notice.setMessage(`重置完成!共 ${count} 个单词`); // 完成后更新消息 + setTimeout(() => notice.hide(), 2000); // 2 秒后自动隐藏 Notice + } + + // 建立单词双链 + async addDoubleBrackets() { + const unmasteredWords = new Set(Array.from(this.allCards.values()) + .filter(card => card.efactor <= 2.5) + .map(card => card.front) + ); + if (unmasteredWords.size === 0) { + new Notice("没有单词需要添加双链!"); + return; + } + + const activeView = this.app.workspace.getActiveViewOfType(MarkdownView); + if (activeView) { + const editor = activeView.editor; + const doc = editor.getDoc(); + const content = doc.getValue(); // 获取当前文档内容 + const words = content.split(/(\[\[.+?\]\]|\s+|\b)/); // 将文本拆分成单词, 保留双链、空格和分隔符 + const updatedWords = words.map((word) => { + const doubleBracketMatch = word.match(/^\[\[(.+?)(\|(.+?))?\]\]$/); // 检查是否是双链格式 [[名称|别名]] + if (doubleBracketMatch) { // 如果是双链格式 + const innerWord = doubleBracketMatch[1]; // 获取双链中的名称 + const alias = doubleBracketMatch[3]; // 获取双链中的别名 + const doc = this.tagger.tagSentence(innerWord); + const lemma = doc[0].lemma + // 如果双链中的名称不在单词表中,去除双链,保留别名或名称 + if (!unmasteredWords.has(lemma) && !unmasteredWords.has(innerWord)) { + return alias; // 如果有别名,保留别名;否则保留名称 + } + // 如果双链中的名称在单词表中,保持原样 + return word; + + } else { // 如果不是双链格式 + const doc = this.tagger.tagSentence(word); + const lemma = doc[0]?.lemma ?? word.toLowerCase(); // 获取动词的原形 + // 检查词干是否在单词表中 + if (unmasteredWords.has(lemma)) { + return `[[${lemma}|${word}]]`; // 如果匹配到单词表中的词干,添加双链 + } + if (unmasteredWords.has(word)) { + return `[[${word}|${word}]]`; // 如果匹配到单词表中的词干,添加双链 + } + return word; // 否则返回原始单词 + } + }); + const updatedContent = updatedWords.join(''); + + doc.setValue(updatedContent); // 用更新后的内容替换原文 + new Notice('已添加双链!'); + } + } + + // 生成单词索引 + async generateIndex() { + const notice = new Notice('索引中...', 0); // 创建一个持续显示的 Notice + const levels = [ + "级别/小学", "级别/中考", "级别/高考四级", "级别/考研", + "级别/六级", "级别/雅思", "级别/托福", "级别/GRE" + ]; + const wordsDir = this.settings.folderPath; // 单词文件夹路径 + const indexDir = this.settings.indexPath; // 索引文件夹路径 + + // 创建索引文件夹 (如果不存在) + const existingIndexFolder = this.app.vault.getFolderByPath(indexDir); + console.log(indexDir,existingIndexFolder) + if (!existingIndexFolder) { + await this.app.vault.createFolder(indexDir); + } + + // 遍历所有单词,记录每个单词的级别 + const wordRecords: Record = {}; + for (const level of levels) { + wordRecords[level] = {}; + } + + const files = this.app.vault.getMarkdownFiles().filter(file => file.path.startsWith(wordsDir)); + for (const file of files) { + const frontMatter = this.app.metadataCache.getFileCache(file)?.frontmatter; + if (!frontMatter) continue; // 如果没有 FrontMatter,跳过 + const tags: string[] = frontMatter.tags || []; + const isMastered = frontMatter?.掌握 === true; + for (const level of levels) { + if (tags.includes(level)) { + const letter = file.basename[0].toUpperCase(); // 获取单词首字母 + if (!wordRecords[level][letter]) { + wordRecords[level][letter] = []; + } + if (isMastered) + wordRecords[level][letter].push(`- [x] [[${file.basename}]]`); + else { + wordRecords[level][letter].push(`- [ ] [[${file.basename}]]`); + } + } + } + } + + const totalWordsList: Record = {}; // 记录每个级别的总单词数 + // 遍历级别,生成索引 + for (const level of levels) { + const levelName = level.split('/').pop(); // 获取级别名称 + const levelFolderPath = `${indexDir}/${levelName}`; + const existingLevelFolder = this.app.vault.getFolderByPath(levelFolderPath); + notice.setMessage(`索引中... ${levelName}`); // 更新 Notice 的消息 + + // 如果级别文件夹不存在,则创建 + if (!existingLevelFolder) { + await this.app.vault.createFolder(levelFolderPath); + } + + let totalWords = 0; // 统计总单词数 + const letterStats: { letter: string; count: number }[] = []; // 记录每个字母的单词数量 + + for (let i = 65; i <= 90; i++) { + const letter = String.fromCharCode(i); + const words = wordRecords[level][letter] || []; // 如果没有单词,返回空数组 + words.sort((a, b) => { + const extractName = (line: string) => { + const match = line.match(/\[\[(.+?)\]\]/); + return match ? match[1] : line; + }; + return extractName(a).localeCompare(extractName(b)); + }); // 按字母顺序排序 + totalWords += words.length; // 累加总单词数 + letterStats.push({ letter, count: words.length }); // 添加统计信息 + + // 创建或覆盖字母索引文件 + const letterFilePath = `${levelFolderPath}/${levelName}.${letter}.md`; + const content = words.join('\n'); + await this.writeFile(letterFilePath, `##### ${levelName}.${letter} ${words.length}\n${content}`); // 写入索引文件 + } + totalWordsList[level] = totalWords; // 记录每个级别的总单词数 + + // 生成总索引文件 + const totalIndexFilePath = `${levelFolderPath}/单词索引.${levelName}.md`; + const totalIndexContent = [ + `##### 单词索引.${levelName} ${totalWords}`, + `| 首字母 | 数量 |`, + `| :-------: | --: |`, + ...letterStats.map(stat => `| [${stat.letter}](${levelName}.${stat.letter}) | ${stat.count} |`) + ].join('\n'); + + await this.writeFile(totalIndexFilePath, totalIndexContent); // 写入索引文件 + } + + // 生成全索引 + const fullIndexFolderPath = `${indexDir}/全索引`; + notice.setMessage(`索引中... 全索引`); // 更新 Notice 的消息 + + const existingFullIndexFolder = this.app.vault.getFolderByPath(fullIndexFolderPath); + if (!existingFullIndexFolder) { + await this.app.vault.createFolder(fullIndexFolderPath); + } + + // 先收集所有字母到一个新的对象 + const allWordsByLetter: Record = {}; // { A: [...], B: [...], ... } + + for (const levelRecords of Object.values(wordRecords)) { + for (const [letter, words] of Object.entries(levelRecords)) { + if (!allWordsByLetter[letter]) { + allWordsByLetter[letter] = []; + } + allWordsByLetter[letter].push(...words); + } + } + + let totalWords = 0; + const letterStats: { letter: string; count: number }[] = []; + + for (let i = 65; i <= 90; i++) { + const letter = String.fromCharCode(i); + let words = allWordsByLetter[letter] || []; // 如果没有单词,返回空数组 + words = Array.from(new Set(words)); // 去重 + totalWords += words.length; // 累加总单词数 + letterStats.push({ letter, count: words.length }); + words.sort((a, b) => { + const extractName = (line: string) => { + const match = line.match(/\[\[(.+?)\]\]/); + return match ? match[1] : line; + }; + return extractName(a).localeCompare(extractName(b)); + }); + + // 创建或覆盖字母索引文件 + const letterFilePath = `${fullIndexFolderPath}/全索引.${letter}.md`; + const content = words.join('\n'); + await this.writeFile(letterFilePath, `##### 全索引.${letter} ${words.length}\n${content}`); // 写入索引文件 + } + + // 生成总索引文件 + const totalIndexFilePath = `${fullIndexFolderPath}/单词索引.全索引.md`; + const totalIndexContent = [ + `##### 单词索引.全索引 ${totalWords}`, + `| 首字母 | 数量 |`, + `| :-------: | --: |`, + ...letterStats.map(stat => `| [${stat.letter}](全索引.${stat.letter}) | ${stat.count} |`) + ].join('\n'); + + await this.writeFile(totalIndexFilePath, totalIndexContent); // 写入索引文件 + + + const finalIndexPath = `${indexDir}/英语单词.md`; + // 定义表头 + const header = [ + `##### [[英语单词说明|英语单词]]`, + ``, + `| | [n.](单词索引.名词) | [v.](单词索引.动词) | [adj.](单词索引.形容词) | [adv.](单词索引.副词) | [prep.](单词索引.介词) | [pron.](单词索引.代词) | [det.](单词索引.限定词) | [conj.](单词索引.连词) |`, + `| :--------------: | :------------: | :------------: | :---------------: | :--------------: | :---------------: | :---------------: | :---------------: | :---------------: |`, + `| [全索引](单词索引.全索引) | [小学](单词索引.小学) | [中考](单词索引.中考) | [高四](单词索引.高考四级) | [考研](单词索引.考研) | [六级](单词索引.六级) | [雅思](单词索引.雅思) | [托福](单词索引.托福) | [GRE](单词索引.GRE) |`, + `| ${this.alllCards.size} | ${totalWordsList["级别/小学"]} | ${totalWordsList["级别/中考"]} | ${totalWordsList["级别/高考四级"]} | ${totalWordsList["级别/考研"]} | ${totalWordsList["级别/六级"]} | ${totalWordsList["级别/雅思"]} | ${totalWordsList["级别/托福"]} | ${totalWordsList["级别/GRE"]} |` + ]; + + // 定义字母索引行 + const alphabetRows = []; + for (let i = 65; i <= 90; i++) { + const letter = String.fromCharCode(i); + alphabetRows.push( + `| [${letter}](全索引.${letter}) | [${letter}](小学.${letter}) | [${letter}](中考.${letter}) | [${letter}](高考四级.${letter}) | [${letter}](考研.${letter}) | [${letter}](六级.${letter}) | [${letter}](雅思.${letter}) | [${letter}](托福.${letter}) | [${letter}](GRE.${letter}) |` + ); + } + + // 合并表头和字母索引行 + const finalContent = [...header, ...alphabetRows].join('\n'); + await this.writeFile(finalIndexPath, finalContent); // 写入索引文件 + + notice.setMessage("索引生成完成!"); + setTimeout(() => notice.hide(), 2000); // 2 秒后自动隐藏 Notice + } + + // 覆盖写入文件 + async writeFile(filePath: string, content: string) { + const existingFile = this.app.vault.getFileByPath(filePath); + if (existingFile) { + await this.app.vault.process(existingFile as TFile, () => content); + } else { + await this.app.vault.create(filePath, content); + } + } + + // 监听单词属性变化并同步到复选框状态 + async syncMetadataToCheckbox(file: TFile, newCheckbox: string, oldCheckbox: string) { + const resolvedLinks = this.app.metadataCache.resolvedLinks; + const backlinks: Record = {}; + for (const [sourcePath, links] of Object.entries(resolvedLinks)) { + if (links[file.path]) { + backlinks[sourcePath] = links[file.path]; + } + } + for (const [sourcePath, _] of Object.entries(backlinks)) { + if (sourcePath.startsWith(this.settings.indexPath)) { + const sourceFile = this.app.vault.getFileByPath(sourcePath) + if (sourceFile) { + const newWord = `- [${newCheckbox}] [[${file.basename}]]`; + const oldWord = `- [${oldCheckbox}] [[${file.basename}]]`; + await this.app.vault.process(sourceFile as TFile, (data) => data.replace(oldWord, newWord)); + } + }; + } + } + + onunload() { + + } + + async loadSettings() { + this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + } + + async saveSettings() { + await this.saveData(this.settings); + } +} + +// 插件设置选项卡 +class OpenWordsSettingTab extends PluginSettingTab { + plugin: OpenWords; + + constructor(app: App, plugin: OpenWords) { + super(app, plugin); + this.plugin = plugin; + } + + display(): void { + const {containerEl} = this; + containerEl.empty(); + const textContainer = containerEl.createDiv({ cls: 'openwords-text-grid' }); + const toggleContainer = containerEl.createDiv({ cls: 'openwords-toggle-grid' }); + this.plugin.settingsSnapshot = Object.assign({}, this.plugin.settings); // 创建设置快照 + new Setting(textContainer) + .setName('单词文件夹路径') + .setDesc('指定存放单词文件的文件夹路径,默认为仓库:/') + .addText(text => text + .setValue(this.plugin.settings.folderPath) + .onChange(async (value) => { + this.plugin.settingsSnapshot.folderPath = normalizePath(value); + })); + new Setting(textContainer) + .setName('索引文件夹路径') + .setDesc('指定存放索引文件的文件夹路径,默认为仓库:索引') + .addText(text => text + .setValue(this.plugin.settings.indexPath) + .onChange(async (value) => { + this.plugin.settingsSnapshot.indexPath = normalizePath(value); + })); + new Setting(toggleContainer) + .setName('小学') + .setDesc('启用小学单词') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.enableWords1) + .onChange(async (value) => { + this.plugin.settingsSnapshot.enableWords1 = value; + })); + new Setting(toggleContainer) + .setName('中考') + .setDesc('启用中考单词') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.enableWords2) + .onChange(async (value) => { + this.plugin.settingsSnapshot.enableWords2 = value; + })); + new Setting(toggleContainer) + .setName('高四') + .setDesc('启用高四单词') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.enableWords3) + .onChange(async (value) => { + this.plugin.settingsSnapshot.enableWords3 = value; + })); + new Setting(toggleContainer) + .setName('考研') + .setDesc('启用考研单词') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.enableWords4) + .onChange(async (value) => { + this.plugin.settingsSnapshot.enableWords4 = value; + })); + new Setting(toggleContainer) + .setName('六级') + .setDesc('启用六级单词') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.enableWords5) + .onChange(async (value) => { + this.plugin.settingsSnapshot.enableWords5 = value; + })); + new Setting(toggleContainer) + .setName('雅思') + .setDesc('启用雅思单词') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.enableWords6) + .onChange(async (value) => { + this.plugin.settingsSnapshot.enableWords6 = value; + })); + new Setting(toggleContainer) + .setName('托福') + .setDesc('启用托福单词') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.enableWords7) + .onChange(async (value) => { + this.plugin.settingsSnapshot.enableWords7 = value; + })); + new Setting(toggleContainer) + .setName('GRE') + .setDesc('启用GRE单词') + .addToggle(toggle => toggle + .setValue(this.plugin.settings.enableWords8) + .onChange(async (value) => { + this.plugin.settingsSnapshot.enableWords8 = value; + })); + new Setting(containerEl) + .setName('应用设置并缓存') + .setDesc('保存设置并重新缓存单词状态') + .addButton(button => button + .setButtonText('应用') + .setCta() // 设置为主要按钮样式 + .onClick(async () => { + if (button.disabled) return; // 如果按钮已禁用,直接返回 + + button.setDisabled(true); // 禁用按钮 + button.setButtonText('处理中...'); // 更新按钮文本 + + try { + this.plugin.settings = {...this.plugin.settingsSnapshot}; // 更新插件设置 + await this.plugin.saveSettings(); // 保存设置 + await this.plugin.scanAllNotes(); // 重新缓存单词 + + } catch (error) { + console.error('缓存过程中发生错误:', error); + new Notice('缓存失败,请检查控制台日志!'); + } finally { + button.setDisabled(false); // 重新启用按钮 + button.setButtonText('应用'); // 恢复按钮文本 + } + })); + new Setting(containerEl) + .setName('生成索引') + .setDesc('按级别生成所有单词的首字母索引文件') + .addButton(button => button + .setButtonText('生成') + .onClick(async () => { + if (button.disabled) return; // 如果按钮已禁用,直接返回 + + button.setDisabled(true); // 禁用按钮 + button.setButtonText('处理中...'); // 更新按钮文本 + + try { + await this.plugin.generateIndex(); // 生成索引文件 + } catch (error) { + console.error('生成索引过程中发生错误:', error); + new Notice('生成索引失败,请检查控制台日志!'); + } finally { + button.setDisabled(false); // 重新启用按钮 + button.setButtonText('生成'); // 恢复按钮文本 + } + })); + new Setting(containerEl) + .setName('重置单词属性') + .setDesc('重置作用域单词的易记因子、重复次数、间隔和到期日') + .addButton(button => button + .setButtonText('重置') + .onClick(async () => { + if (button.disabled) return; // 如果按钮已禁用,直接返回 + + button.setDisabled(true); // 禁用按钮 + button.setButtonText('处理中...'); // 更新按钮文本 + + try { + await this.plugin.resetCard(); // 重置单词属性 + } catch (error) { + console.error('重置过程中发生错误:', error); + new Notice('重置失败,请检查控制台日志!'); + } finally { + button.setDisabled(false); // 重新启用按钮 + button.setButtonText('重置'); // 恢复按钮文本 + } + })); + } +} + +// 学习模式模态框 +class LearningTypeModal extends Modal { + plugin: OpenWords; + + constructor(app: App, plugin: OpenWords) { + super(app); + this.plugin = plugin; + } + + onOpen() { + this.modalEl.addClass('type-modal'); // 添加自定义样式类 + const { contentEl } = this; + contentEl.empty(); + + const title = contentEl.createDiv({ cls: 'type-title', text: '选择学习模式' }); + const buttonContainer = contentEl.createDiv({ cls: 'type-button-grid' }); + + new Setting(buttonContainer) + .setName(`学习新词 ( 重复次数为零, 剩余 ${this.plugin.newCards.size} )`) + .addButton(btn => btn + .setButtonText("开始") + .onClick(() => { + if (this.plugin.newCards.size > 0) { + this.close(); + new LearningModal(this.app, this.plugin, 'new').open(); + } else { + new Notice("没有新词可学了!"); + } + })); + + new Setting(buttonContainer) + .setName(`复习旧词 ( 重复次数不为零, 剩余 ${this.plugin.dueCards.size} )`) + .addButton(btn => btn + .setButtonText("开始") + .onClick(() => { + if (this.plugin.dueCards.size > 0) { + this.close(); + new LearningModal(this.app, this.plugin, 'review').open(); + } else { + new Notice("没有需要复习的卡片!"); + } + })); + + new Setting(buttonContainer) + .setName(`掌握列表 ( 所有单词 )`) + .addButton(btn => btn + .setButtonText("开始") + .onClick(() => { + this.close(); + new WordListModal(this.app, this.plugin).open(); + })); + + new Setting(buttonContainer) + .setName('默写单词 ( 作用域单词 )') + .addButton(btn => btn + .setButtonText('开始') + .onClick(() => { + this.close(); + new SpellingModal(this.app, this.plugin).open(); + })); + + new Setting(buttonContainer) + .setName(`添加双链 ( 作用域中易记因子 <= 2.5 )`) + .addButton(btn => btn + .setButtonText("开始") + .onClick(() => { + this.close(); + this.plugin.addDoubleBrackets(); + })); + } +} + +// 背单词模态框 +class LearningModal extends Modal { + plugin: OpenWords; + mode: 'new' | 'review'; + currentCard: CardInfo; + + constructor(app: App, plugin: OpenWords, mode: 'new' | 'review') { + super(app); + this.plugin = plugin; + this.mode = mode; + } + + onOpen() { + this.pickNextCard(); + this.render(); + + // 监听数字键 0-5 的按键事件 + const handleKeydown = (event: KeyboardEvent) => { + if (event.key >= '0' && event.key <= '5') { + const grade = parseInt(event.key) as SuperMemoGrade; + this.rateCard(grade); + } + }; + + window.addEventListener('keydown', handleKeydown); + + // 在模态框关闭时移除事件监听器 + this.onClose = () => { + window.removeEventListener('keydown', handleKeydown); + const { contentEl } = this; + contentEl.empty(); + }; + } + + pickNextCard() { + const now = dayjs(); // 获取当前时间 + let pool: CardInfo[]; + + // 新词池是指所有新词, 旧词池是指所有已过期的旧词 + if (this.mode === 'new') { + pool = Array.from(this.plugin.newCards.values()); // 将 Set 转换为数组 + if (pool.length === 0) { + this.close(); + new Notice("已完成所有新词!"); + return; + } + } else { + pool = Array.from(this.plugin.dueCards.values()) + .filter(card => dayjs(card.dueDate).isBefore(now)) // 筛选已过期的单词 + if (pool.length === 0) { + this.close(); + new Notice("没有需要复习的卡片!"); + return; + } + } + // 单词调度 70% 纯随机, 30% 从易记因子和重复次数最低的 20% 中随机 + const randomMode = Math.random() < 0.7; + if (randomMode) { + this.currentCard = pool[Math.floor(Math.random() * pool.length)]; + } else { + const sortedPool = pool.sort((a, b) => { + const efactorDiff = (a.efactor || 1) - (b.efactor || 1); // 易记因子升序 + if (efactorDiff !== 0) return efactorDiff; + return a.repetition - b.repetition; // 重复次数升序 + }); + const halfPool = sortedPool.slice(0, Math.ceil(sortedPool.length / 5)); // 取前 20% + this.currentCard = halfPool[Math.floor(Math.random() * halfPool.length)]; + } + } + + render() { + const { contentEl } = this; + contentEl.empty(); + + if (!this.currentCard) return; + + // 创建卡片容器并固定样式 + const cardContainer = contentEl.createDiv({ cls: 'anki-card' }); + + // 标记当前是否显示 Markdown 内容 + let isShowingMarkdown = false; + // 初始显示单词 + const wordContent = cardContainer.createDiv({ cls: 'anki-card-content' }); + wordContent.textContent = this.currentCard.front; + + // 添加鼠标悬浮事件切换内容 + cardContainer.addEventListener('mouseenter', async () => { + if (isShowingMarkdown) return; // 如果已经显示 Markdown 内容,则不重复加载 + + const file = this.plugin.app.vault.getAbstractFileByPath(this.currentCard.path); + if (file instanceof TFile) { + const markdownContent = await this.plugin.app.vault.read(file); + + // 清空卡片内容并渲染 Markdown 内容 + cardContainer.empty(); + const markdownRenderContainer = cardContainer.createDiv({ cls: 'anki-markdown-content' }); + await MarkdownRenderer.render( + this.app, + markdownContent, + markdownRenderContainer, + file.path, + this.plugin + ); + + isShowingMarkdown = true; + } else { + new Notice('无法加载单词的 Markdown 文件!'); + } + }); + + cardContainer.addEventListener('mouseleave', () => { + if (!isShowingMarkdown) return; // 如果已经显示单词内容,则不重复加载 + + // 切换回显示单词 + cardContainer.empty(); + const wordContent = cardContainer.createDiv({ cls: 'anki-card-content' }); + wordContent.textContent = this.currentCard.front; + isShowingMarkdown = false; + }); + + const settingsContainer = contentEl.createDiv({ cls: 'anki-settings' }); + + new Setting(settingsContainer) + .setName(`评分 0: 回答错误, 完全不会`) + .addButton(btn => btn + .setButtonText('0') + .onClick(() => this.rateCard(0 as SuperMemoGrade))) + new Setting(settingsContainer) + .setName(`评分 1: 回答错误, 看到正确答案后感觉很熟悉`) + .addButton(btn => btn + .setButtonText('1') + .onClick(() => this.rateCard(1 as SuperMemoGrade))) + new Setting(settingsContainer) + .setName(`评分 2: 回答错误, 看到正确答案后感觉很容易记住`) + .addButton(btn => btn + .setButtonText('2') + .onClick(() => this.rateCard(2 as SuperMemoGrade))) + new Setting(settingsContainer) + .setName(`评分 3: 回答正确, 需要花费很大力气才能回忆起来`) + .addButton(btn => btn + .setButtonText('3') + .onClick(() => this.rateCard(3 as SuperMemoGrade))) + new Setting(settingsContainer) + .setName(`评分 4: 回答正确, 需要经过一番犹豫才做出反应`) + .addButton(btn => btn + .setButtonText('4') + .onClick(() => this.rateCard(4 as SuperMemoGrade))) + new Setting(settingsContainer) + .setName(`评分 5: 回答正确, 完美响应`) + .addButton(btn => btn + .setButtonText('5') + .onClick(() => this.rateCard(5 as SuperMemoGrade))) + } + + async rateCard(grade: SuperMemoGrade) { + await this.plugin.updateCard(this.currentCard, grade); + this.pickNextCard(); + this.render(); + } + +} + +// 单词列表模态框 +class WordListModal extends Modal { + plugin: OpenWords; + selectedLetter: string | null = null; // 当前选中的首字母 + selectedLevel: string | null = null; // 当前选中的级别 + + constructor(app: App, plugin: OpenWords) { + super(app); + this.plugin = plugin; + } + + async onOpen() { + this.modalEl.addClass('word-list-modal'); + const { contentEl } = this; + contentEl.empty(); + const title = contentEl.createDiv({ cls: 'word-list-title', text: '掌握列表' }); + const filterContainer = contentEl.createDiv({ cls: 'word-list-filters' }); + const listContainer = contentEl.createDiv({ cls: 'word-list-container' }); + + // 添加首字母筛选 + const letterFilter = new Setting(filterContainer) + .setName('首字母筛选') + .addDropdown(dropdown => { + dropdown.addOption('', '全部'); + for (let i = 65; i <= 90; i++) { + const letter = String.fromCharCode(i); + dropdown.addOption(letter, letter); + } + dropdown.setValue(this.selectedLetter || ''); + dropdown.onChange(value => { + this.selectedLetter = value || null; + this.renderWordList(listContainer); + }); + }); + + // 添加级别筛选 + const levelFilter = new Setting(filterContainer) + .setName('级别筛选') + .addDropdown(dropdown => { + dropdown.addOption('', '全部'); + const levels = [ + '级别/小学', '级别/中考', '级别/高考四级', '级别/考研', + '级别/六级', '级别/雅思', '级别/托福', '级别/GRE' + ]; + levels.forEach(level => dropdown.addOption(level, level.split('/')[1])); + dropdown.setValue(this.selectedLevel || ''); + dropdown.onChange(value => { + this.selectedLevel = value || null; + this.renderWordList(listContainer); + }); + }); + + // 初始不渲染单词列表 + listContainer.createDiv({ text: '请选择筛选条件以查看单词列表。' }); + } + + renderWordList(container: HTMLElement) { + container.empty(); + + // 如果没有选择筛选条件,则不渲染内容 + if (!this.selectedLetter && !this.selectedLevel) { + container.createDiv({ text: '请选择筛选条件以查看单词列表。' }); + return; + } + + // 根据筛选条件过滤单词 + const filteredWords = Array.from(this.plugin.alllCards.values()).filter(card => { + const matchesLetter = this.selectedLetter + ? card.front.startsWith(this.selectedLetter.toLowerCase()) + : true; + const matchesLevel = this.selectedLevel + ? this.plugin.app.metadataCache.getFileCache(this.plugin.app.vault.getAbstractFileByPath(card.path) as TFile)?.frontmatter?.tags?.includes(this.selectedLevel) + : true; + return matchesLetter && matchesLevel; + }).sort((a, b) => a.front.localeCompare(b.front)); // 按字母顺序排序 + + // 渲染单词列表 + if (filteredWords.length === 0) { + container.createDiv({ text: '没有符合条件的单词。' }); + return; + } + + filteredWords.forEach(card => { + const wordItem = container.createDiv({ cls: 'word-list-item' }); + // 左侧显示单词 + const wordText = wordItem.createDiv({ cls: 'word-text', text: card.front }); + const toggleContainer = wordItem.createDiv({ cls: 'toggle-container' }); + + new Setting(toggleContainer) + // .setName(card.front) + .addToggle(toggle => { + toggle.setValue(card.isMastered) // 设置初始复选框状态 + .onChange(async (value) => { + // 更新单词的掌握状态 + await this.plugin.app.fileManager.processFrontMatter( + this.plugin.app.vault.getAbstractFileByPath(card.path) as TFile, + (frontMatter) => { + frontMatter.掌握 = value; + } + ); + new Notice(`单词 "${card.front}" 已更新为 ${value ? '掌握' : '未掌握'}`); + }); + }); + // 创建 Markdown 预览容器 + const previewContainer = wordText.createDiv({ cls: 'word-preview-inline' }); + + // 添加鼠标悬停事件以渲染 Markdown 内容 + wordText.addEventListener('mouseenter', async () => { + const file = this.plugin.app.vault.getAbstractFileByPath(card.path); + if (file instanceof TFile) { + const markdownContent = await this.plugin.app.vault.read(file); + previewContainer.empty(); + await MarkdownRenderer.render( + this.app, + markdownContent, + previewContainer, + file.path, + this.plugin + ); + } + }); + + // 鼠标离开时清空预览内容 + wordText.addEventListener('mouseleave', () => { + previewContainer.empty(); + }); + }); + } + + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} + +// 默写单词模态框 +class SpellingModal extends Modal { + plugin: OpenWords; + currentCard: CardInfo | null = null; + + constructor(app: App, plugin: OpenWords) { + super(app); + this.plugin = plugin; + } + + async onOpen() { + const { contentEl } = this; + contentEl.empty(); + this.modalEl.addClass('spelling-modal'); // 添加样式类 + + const title = contentEl.createDiv({ cls: 'spelling-title', text: '默写单词' }); + const wordMeaningContainer = contentEl.createDiv({ cls: 'word-meaning-container' }); + const inputContainer = contentEl.createDiv({ cls: 'input-container' }); + const feedbackContainer = contentEl.createDiv({ cls: 'feedback-container' }); + + // 初始化第一个单词 + this.pickNextCard(wordMeaningContainer, inputContainer, feedbackContainer); + + const handleKeydown = (event: KeyboardEvent) => { + if (event.key === 'Tab') { + event.preventDefault(); // 阻止页面滚动 + if (this.currentCard) { + title.setText(`${this.currentCard.front}`); // 显示答案 + } + } + }; + + const handleKeyup = (event: KeyboardEvent) => { + if (event.key === 'Tab') { + event.preventDefault(); // 阻止页面滚动 + title.setText('默写单词'); // 恢复标题 + } + }; + window.addEventListener('keydown', handleKeydown); + window.addEventListener('keyup', handleKeyup); + this.onClose = () => { + window.removeEventListener('keydown', handleKeydown); + window.removeEventListener('keyup', handleKeyup); + contentEl.empty(); + }; + } + + async pickNextCard( + wordMeaningContainer: HTMLElement, + inputContainer: HTMLElement, + feedbackContainer: HTMLElement + ) { + const cards = Array.from(this.plugin.allCards.values()); + if (cards.length === 0) { + feedbackContainer.setText('没有更多单词了!'); + return; + } + + // 随机选择一个单词 + this.currentCard = cards[Math.floor(Math.random() * cards.length)]; + + // 渲染单词的词义 + const file = this.plugin.app.vault.getAbstractFileByPath(this.currentCard.path); + if (file instanceof TFile) { + const content = await this.plugin.app.vault.read(file); + const match = content.match(/##### 词义\n(?:- .*\n?)*/g); + wordMeaningContainer.empty(); // 清空之前的内容 + if (match) { + await MarkdownRenderer.render( + this.app, + match[0], + wordMeaningContainer, + file.path, + this.plugin + ); + } else { + wordMeaningContainer.setText('未找到词义'); + } + } + + // 清空输入容器并生成字母输入框 + inputContainer.empty(); + feedbackContainer.setText(''); + if (this.currentCard) { + const word = this.currentCard.front; + const inputFields: HTMLInputElement[] = []; + + // 为每个字母生成一个输入框 + for (let i = 0; i < word.length; i++) { + const inputField = inputContainer.createEl('input', { + type: 'text', + cls: 'letter-input', + }); + + inputFields.push(inputField); + + // 自动跳转到下一个输入框 + inputField.addEventListener('input', () => { + if (inputField.value.length === 1 && i < word.length - 1) { + inputFields[i + 1].focus(); + } + this.checkSpelling(inputFields, word, feedbackContainer, wordMeaningContainer, inputContainer); + }); + + // 支持使用退格键返回上一个输入框 + inputField.addEventListener('keydown', (event) => { + if (event.key === 'Backspace' && inputField.value === '' && i > 0) { + inputFields[i - 1].focus(); + } + }); + } + + // 聚焦第一个输入框 + inputFields[0].focus(); + } + } + + checkSpelling( + inputFields: HTMLInputElement[], + word: string, + feedbackContainer: HTMLElement, + wordMeaningContainer: HTMLElement, + inputContainer: HTMLElement + ) { + const userInput = inputFields.map((field) => field.value).join(''); + if (userInput.length === word.length) { + if (userInput.toLowerCase() === word.toLowerCase()) { + feedbackContainer.setText('正确!'); + setTimeout(() => { + this.pickNextCard(wordMeaningContainer, inputContainer, feedbackContainer); + }, 500); + } else { + feedbackContainer.setText('错误,请重试!'); + inputFields.forEach((field) => (field.value = '')); // 清空所有输入框 + inputFields[0].focus(); // 聚焦第一个输入框 + } + } + } + + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..22d61e5 --- /dev/null +++ b/manifest.json @@ -0,0 +1,10 @@ +{ + "id": "openwords", + "name": "OpenWords", + "version": "1.0.0", + "minAppVersion": "1.8.10", + "description": "用于英语学习中背单词与单词管理的插件", + "author": "insile", + "authorUrl": "https://opentext.net.cn/", + "isDesktopOnly": false +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..07366ad --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2488 @@ +{ + "name": "openwords", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "openwords", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "dayjs": "^1.11.13", + "supermemo": "^2.0.23", + "wink-pos-tagger": "^2.2.2" + }, + "devDependencies": { + "@types/node": "^16.11.6", + "@types/wink-pos-tagger": "^2.2.6", + "@typescript-eslint/eslint-plugin": "5.29.0", + "@typescript-eslint/parser": "5.29.0", + "builtin-modules": "3.3.0", + "esbuild": "0.17.3", + "obsidian": "latest", + "tslib": "2.4.0", + "typescript": "4.7.4" + } + }, + "node_modules/@codemirror/state": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz", + "integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@marijn/find-cluster-break": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.36.6", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.36.6.tgz", + "integrity": "sha512-uxugGLet+Nzp0Jcit8Hn3LypM8ioMLKTsdf8FRoT3HWvZtb9GhaWMe0Cc15rz90Ljab4YFJiAulmIVB74OY0IQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@codemirror/state": "^6.5.0", + "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.6.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.1.tgz", + "integrity": "sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==", + "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.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "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.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "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/@types/wink-pos-tagger": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@types/wink-pos-tagger/-/wink-pos-tagger-2.2.6.tgz", + "integrity": "sha512-KWDONU9YjbYM61Xh2spF1espHRP31BgHocT3uXm1JWQaHik8IXeim3PpUBRKztVd9pyKDSnvmfqMEVAZsvSYCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/wink-tokenizer": "*" + } + }, + "node_modules/@types/wink-tokenizer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/wink-tokenizer/-/wink-tokenizer-4.0.6.tgz", + "integrity": "sha512-FSQP7MwLDWgSkYw1sJMmN4SFBJt/W6bDaHy/quOG2aq5DOB/ilHfY4x3IsAhGUmA45y3H29tM0tbq0Ut1LD7/Q==", + "dev": true, + "license": "MIT" + }, + "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.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "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.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "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/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "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/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/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "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/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "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.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "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.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "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.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "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": "Glob versions prior to v9 are no longer supported", + "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/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.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "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.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "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.8.7", + "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.8.7.tgz", + "integrity": "sha512-h4bWwNFAGRXlMlMAzdEiIM2ppTGlrh7uGOJS6w4gClrsjc+ei/3YAtU2VdFUlCiPuTHpY4aBpFJJW75S1Tl/JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/codemirror": "5.60.8", + "moment": "2.29.4" + }, + "peerDependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "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.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "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.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/supermemo": { + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/supermemo/-/supermemo-2.0.23.tgz", + "integrity": "sha512-nmWfFf3opwJahxHHBS2k3FtBnK0Ii4LPZ8YrGqu9uoDDyftQodlRP3tGtWRo5h7dJWR6aSuJKuD8iiYbiOA9bw==", + "license": "MIT" + }, + "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-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/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/wink-helpers": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wink-helpers/-/wink-helpers-2.0.0.tgz", + "integrity": "sha512-I/ZzXrHcNRXuoeFJmp2vMVqDI6UCK02Tds1WP4kSGAmx520gjL1BObVzF7d2ps24tyHIly9ngdB2jwhlFUjPvg==", + "license": "MIT" + }, + "node_modules/wink-lemmatizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/wink-lemmatizer/-/wink-lemmatizer-3.0.4.tgz", + "integrity": "sha512-EdLJfy1xLF2ze2cp9Z3qiEWjiq+V8ZVRWiWooCXTXR0AyPxY8ezm4E0puJ0yIj5szzED9tcXV2U7RboaGvboFw==", + "license": "MIT", + "dependencies": { + "wink-lexicon": "^2.2.0", + "wink-porter2-stemmer": "^2.0.0" + } + }, + "node_modules/wink-lexicon": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/wink-lexicon/-/wink-lexicon-2.2.0.tgz", + "integrity": "sha512-QIuHS9r/HV6q3PCCz6pymg4gbsryW9wDk8CHdU+sDn0kJcHpECNDIcdY0Q/mZpqxtFLp9dzIw7pjcStLBbGZGg==", + "license": "MIT" + }, + "node_modules/wink-porter2-stemmer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wink-porter2-stemmer/-/wink-porter2-stemmer-2.0.1.tgz", + "integrity": "sha512-0g+RkkqhRXFmSpJQStVXW5N/WsshWpJXsoDRW7DwVkGI2uDT6IBCoq3xdH5p6IHLaC6ygk7RWUsUx4alKxoagQ==", + "license": "MIT" + }, + "node_modules/wink-pos-tagger": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/wink-pos-tagger/-/wink-pos-tagger-2.2.2.tgz", + "integrity": "sha512-+bhkwqwwChqWR75ksFKVJZQagwu404UmnvFjxr+OWZ02/ZJAv19N/iqDpMeYRQRxatk5N+W9pXIKEDJsVrzGyw==", + "license": "MIT", + "dependencies": { + "wink-helpers": "^2.0.0", + "wink-lemmatizer": "^3.0.1", + "wink-lexicon": "^2.1.1", + "wink-porter2-stemmer": "^2.0.0", + "wink-tokenizer": "^5.2.1" + } + }, + "node_modules/wink-tokenizer": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/wink-tokenizer/-/wink-tokenizer-5.3.0.tgz", + "integrity": "sha512-O/yAw0g3FmSgeeQuYAJJfP7fVPB4A6ay0018qASh79aWmIOyPYy4j4r9EQT8xBjicja6lCLvgRVAybmEBaATQA==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^9.0.0" + } + }, + "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..63bcb86 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "openwords", + "version": "1.0.0", + "description": "用于英语学习中背单词与单词管理的插件", + "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", + "English", + "words", + "learning" + ], + "author": "insile", + "license": "MIT", + "devDependencies": { + "@types/node": "^16.11.6", + "@types/wink-pos-tagger": "^2.2.6", + "@typescript-eslint/eslint-plugin": "5.29.0", + "@typescript-eslint/parser": "5.29.0", + "builtin-modules": "3.3.0", + "esbuild": "0.17.3", + "obsidian": "latest", + "tslib": "2.4.0", + "typescript": "4.7.4" + }, + "dependencies": { + "dayjs": "^1.11.13", + "supermemo": "^2.0.23", + "wink-pos-tagger": "^2.2.2" + } +} diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..b51b59a --- /dev/null +++ b/styles.css @@ -0,0 +1,192 @@ +/* + +This CSS file will be included with your plugin, and +available in the app when your plugin is enabled. + +If your plugin does not need CSS, delete this file. + +*/ + +/* 学习模式标题 */ +.type-title { + text-align: center; + margin-bottom: 20px; + font-size: 1.5em; + font-weight: bold; +} + +/* 设置 */ +.openwords-toggle-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); /* 每行 4 列 */ + gap: 10px; /* 每个 toggle 之间的间距 */ + /* margin-top: 10px; */ +} +.openwords-toggle-grid .setting-item:first-child { + padding-top: 10px; + border-top: 1px solid var(--background-modifier-border) +} + +.type-modal{ + width: 650px; /* 设置模态框宽度 */ +} +/* 卡片容器样式 */ +.anki-card { + width: 500px; /* 固定宽度 */ + height: 300px; /* 固定高度 */ + display: flex; + justify-content: center; + align-items: center; + border: 1px solid var(--color-border); + border-radius: 8px; + margin: 20px auto; + background-color: var(--background-primary); + text-align: center; + cursor: pointer; /* 鼠标悬停时显示手型 */ +} +.anki-card:hover { + background-color: var(--background-modifier-hover); /* 鼠标悬停时背景变浅 */ +} + +/* 单词内容样式 */ +.anki-card-content { + font-size: 2.5em; /* 设置单词字体大小 */ + font-weight: bold; /* 设置单词加粗 */ + color: var(--text-normal); /* 设置单词颜色 */ +} + +/* Markdown 内容样式 */ +.anki-markdown-content { + width: 100%; + height: 100%; + overflow-y: auto; /* 添加垂直滚动条 */ + background-color: var(--background-secondary); /* 更柔和的背景颜色 */ + color: var(--text-muted); /* 使用正常文本颜色 */ + font-size: 1.1em; /* 稍微增大字体 */ + line-height: 1.6; /* 增加行高,提升可读性 */ + border-radius: 8px; /* 添加圆角 */ + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 添加阴影效果 */ + font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; /* 设置优雅的字体 */ + user-select: text; /* 允许文本选择 */ +} + +/* 设置容器样式 */ +.anki-settings { + margin-top: 20px; + font-size: 1em; /* 减小字体大小 */ +} + +.anki-settings .setting-item { + padding: 5px 10px; /* 减小内边距 */ +} + + +/* 单词列表模态框 */ +.word-list-modal{ + width: 400px; +} + +.word-list-title { + font-size: 1.5em; + font-weight: bold; + margin-bottom: 1em; + text-align: center; +} + +.word-list-filters { + display: flex; + justify-content: space-between; + margin-bottom: 1em; +} + +.word-list-container { + display: flex; + flex-direction: column; + gap: 0.5em; +} + +.word-list-filters .setting-item:first-child { + padding-top: 10px; + border-top: 1px solid var(--background-modifier-border) +} + +/* 单词项容器样式 */ +.word-list-item { + display: flex; /* 设置为水平布局 */ + justify-content: space-between; /* 左右对齐 */ + border-bottom: 1px solid var(--background-modifier-border); + position: relative; /* 为预览容器提供定位上下文 */ +} + +/* Markdown 预览容器样式 */ +.word-preview-inline { + font-size: 1em; /* 设置预览内容字体大小 */ + line-height: 1.5; /* 设置行高 */ + overflow-y: auto; /* 添加垂直滚动条 */ + max-height: 300px; /* 设置最大高度 */ + position: absolute; /* 设置绝对定位 */ + top: 100%; /* 显示在单词项的下方 */ + left: 0; + width: 100%; + z-index: 10; /* 确保预览内容在最上层 */ + background-color: var(--background-secondary); + border: 1px solid var(--background-modifier-border); + border-radius: 5px; + padding: 10px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + display: none; /* 默认隐藏 */ + user-select: text; /* 允许文本选择 */ +} + +/* 鼠标悬停时显示预览内容 */ +.word-text:hover .word-preview-inline { + display: block; /* 鼠标悬停时显示预览内容 */ +} + +/* 单词文本样式 */ +.word-text { + font-size: 1.1em; + color: var(--text-normal); + cursor: pointer; +} + +/* 默写单词模态框样式 */ +.spelling-modal { + width: auto; + margin: 0 auto; + padding: 20px; + border-radius: 8px; + background-color: var(--background-primary); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); +} + +.spelling-title { + font-size: 1.5em; + font-weight: bold; + text-align: center; + margin-bottom: 20px; +} + +.input-container { + display: flex; + justify-content: center; + gap: 10px; + margin-bottom: 20px; +} + +.letter-input { + width: 50px !important; + height: 50px !important; + text-align: center; + font-size: 1.5em !important; + border: 1px solid var(--background-modifier-border); + border-radius: 5px; + outline: none; +} + +.feedback-container { + margin-top: 10px; + text-align: center; + font-size: 1em; + color: var(--text-accent); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..c44b729 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,24 @@ +{ + "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" + ] +} diff --git a/version-bump.mjs b/version-bump.mjs new file mode 100644 index 0000000..d409fa0 --- /dev/null +++ b/version-bump.mjs @@ -0,0 +1,14 @@ +import { readFileSync, writeFileSync } from "fs"; + +const targetVersion = process.env.npm_package_version; + +// read minAppVersion from manifest.json and bump version to target version +let manifest = JSON.parse(readFileSync("manifest.json", "utf8")); +const { minAppVersion } = manifest; +manifest.version = targetVersion; +writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t")); + +// update versions.json with target version and minAppVersion from manifest.json +let versions = JSON.parse(readFileSync("versions.json", "utf8")); +versions[targetVersion] = minAppVersion; +writeFileSync("versions.json", JSON.stringify(versions, null, "\t")); diff --git a/versions.json b/versions.json new file mode 100644 index 0000000..60d5f65 --- /dev/null +++ b/versions.json @@ -0,0 +1,3 @@ +{ + "1.0.0": "1.8.10" +}