From 1ecb9542c07456a877840433148dccb3e36ea4a8 Mon Sep 17 00:00:00 2001 From: pseudometa <73286100+chrisgrieser@users.noreply.github.com> Date: Sat, 7 May 2022 13:09:13 +0200 Subject: [PATCH 01/53] Update settings.ts (#46) --- src/settings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings.ts b/src/settings.ts index 65d8101..4ba96f2 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -85,7 +85,7 @@ export class SettingsTab extends PluginSettingTab { } export const DEFAULT_SETTINGS: OmnisearchSettings = { - showIndexingNotices: true, + showIndexingNotices: false, respectExcluded: true, weightBasename: 2, weightH1: 1.5, From a395a77e5b0b36ebcfadf870f2813767823d9f5c Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 11 May 2022 09:26:51 +0200 Subject: [PATCH 02/53] Simpler code --- src/settings.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/settings.ts b/src/settings.ts index 4ba96f2..26c9a67 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -26,9 +26,7 @@ export class SettingsTab extends PluginSettingTab { containerEl.empty() // Title - const title = document.createElement('h2') - title.textContent = 'Omnisearch settings' - containerEl.appendChild(title) + containerEl.createEl('h2', { text: 'Omnisearch settings' }) // Show notices new Setting(containerEl) From 0cdb3c84a9de05a5add188c6275773d693fff3dc Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 11 May 2022 09:28:25 +0200 Subject: [PATCH 03/53] #34 - aliases have the same weight as the basename --- src/__tests__/utils-tests.ts | 41 ++++++++++++++++++++++++++++++++++++ src/globals.ts | 1 + src/search.ts | 26 ++++++++++++++++------- src/settings.ts | 2 +- src/types.d.ts | 4 ++++ src/utils.ts | 7 ++++++ 6 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 src/__tests__/utils-tests.ts diff --git a/src/__tests__/utils-tests.ts b/src/__tests__/utils-tests.ts new file mode 100644 index 0000000..4333720 --- /dev/null +++ b/src/__tests__/utils-tests.ts @@ -0,0 +1,41 @@ +import type { CachedMetadata } from 'obsidian' +import { getAliasesFromMetadata } from '../utils' + +describe('Utils', () => { + describe('getAliasesFromMetadata', () => { + it('should return an empty string if no metadata is provided', () => { + // Act + const actual = getAliasesFromMetadata(null) + // Assert + expect(actual).toBe('') + }) + it('should return an empty string if no aliases are provided', () => { + // Arrange + const metadata = {} as CachedMetadata + // Act + const actual = getAliasesFromMetadata(metadata) + // Assert + expect(actual).toBe('') + }) + it('should join aliases with a comma', () => { + // Arrange + const metadata = { + frontmatter: { aliases: ['foo', 'bar'] }, + } as CachedMetadata + // Act + const actual = getAliasesFromMetadata(metadata) + // Assert + expect(actual).toBe('foo, bar') + }) + it('should return a single alias if only one is provided', () => { + // Arrange + const metadata = { + frontmatter: { aliases: 'foo, bar' }, + } as CachedMetadata + // Act + const actual = getAliasesFromMetadata(metadata) + // Assert + expect(actual).toBe('foo, bar') + }) + }) +}) diff --git a/src/globals.ts b/src/globals.ts index f1c65e1..d4637dd 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -24,6 +24,7 @@ export type IndexedNote = { path: string basename: string content: string + aliases: string headings1: string headings2: string headings3: string diff --git a/src/search.ts b/src/search.ts index f0f7993..133ef01 100644 --- a/src/search.ts +++ b/src/search.ts @@ -9,6 +9,7 @@ import { } from './globals' import { extractHeadingsFromCache, + getAliasesFromMetadata, stringsToRegex, stripMarkdownCharacters, wait, @@ -40,7 +41,14 @@ export async function initGlobalSearchIndex(): Promise { minisearchInstance = new MiniSearch({ tokenize, idField: 'path', - fields: ['basename', 'content', 'headings1', 'headings2', 'headings3'], + fields: [ + 'basename', + 'aliases', + 'content', + 'headings1', + 'headings2', + 'headings3', + ], }) // Index files that are already present @@ -84,6 +92,7 @@ async function search(query: Query): Promise { combineWith: 'AND', boost: { basename: settings.weightBasename, + aliases: settings.weightBasename, headings1: settings.weightH1, headings2: settings.weightH2, headings3: settings.weightH3, @@ -208,7 +217,7 @@ export async function addToIndex(file: TAbstractFile): Promise { } try { // console.log(`Omnisearch - adding ${file.path} to index`) - const fileCache = app.metadataCache.getFileCache(file) + const metadata = app.metadataCache.getFileCache(file) if (indexedNotes[file.path]) { throw new Error(`${file.basename} is already indexed`) @@ -222,14 +231,15 @@ export async function addToIndex(file: TAbstractFile): Promise { basename: file.basename, content, path: file.path, - headings1: fileCache - ? extractHeadingsFromCache(fileCache, 1).join(' ') + aliases: getAliasesFromMetadata(metadata), + headings1: metadata + ? extractHeadingsFromCache(metadata, 1).join(' ') : '', - headings2: fileCache - ? extractHeadingsFromCache(fileCache, 2).join(' ') + headings2: metadata + ? extractHeadingsFromCache(metadata, 2).join(' ') : '', - headings3: fileCache - ? extractHeadingsFromCache(fileCache, 3).join(' ') + headings3: metadata + ? extractHeadingsFromCache(metadata, 3).join(' ') : '', } minisearchInstance.add(note) diff --git a/src/settings.ts b/src/settings.ts index 26c9a67..6ca5dcb 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -55,7 +55,7 @@ export class SettingsTab extends PluginSettingTab { new Setting(containerEl).setName('Results weighting').setHeading() new Setting(containerEl) - .setName(`File name (default: ${DEFAULT_SETTINGS.weightBasename})`) + .setName(`File name & declared aliases (default: ${DEFAULT_SETTINGS.weightBasename})`) .addSlider(cb => this.weightSlider(cb, 'weightBasename')) new Setting(containerEl) diff --git a/src/types.d.ts b/src/types.d.ts index 1c3ff4c..cccea5a 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -4,4 +4,8 @@ declare module 'obsidian' { interface MetadataCache { isUserIgnored?(path: string): boolean } + + interface FrontMatterCache { + aliases?: string[] | string + } } diff --git a/src/utils.ts b/src/utils.ts index 0fd1940..a4866bf 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -147,3 +147,10 @@ export async function filterAsync( export function stripMarkdownCharacters(text: string): string { return text.replace(/(\*|_)+(.+?)(\*|_)+/g, (match, p1, p2) => p2) } + +export function getAliasesFromMetadata( + metadata: CachedMetadata | null, +): string { + const arrOrString = metadata?.frontmatter?.aliases ?? [] + return Array.isArray(arrOrString) ? arrOrString.join(', ') : arrOrString +} From 10a1bf5effda3115ccad17f98c7a267d03a8895f Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 11 May 2022 16:08:49 +0200 Subject: [PATCH 04/53] Hide matches count when 0 --- src/components/ResultItemVault.svelte | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/ResultItemVault.svelte b/src/components/ResultItemVault.svelte index 5430c13..03de740 100644 --- a/src/components/ResultItemVault.svelte +++ b/src/components/ResultItemVault.svelte @@ -17,9 +17,11 @@ $: cleanedContent = makeExcerpt(note.content, note.matches[0]?.offset ?? -1) {@html note.basename.replace(reg, highlighter)} - - {matches.length} {matches.length > 1 ? "matches" : "match"} - + {#if matches.length > 0} + + {matches.length} {matches.length > 1 ? "matches" : "match"} + + {/if}
{@html cleanedContent.replace(reg, highlighter)}
From 1d4500fce62ab539a7e99c7c662ae2e63d7d738b Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 11 May 2022 16:09:42 +0200 Subject: [PATCH 05/53] Updated dependencies --- package.json | 14 +- pnpm-lock.yaml | 633 ++++++++++++++++++++++++++----------------------- tsconfig.json | 5 +- 3 files changed, 345 insertions(+), 307 deletions(-) diff --git a/package.json b/package.json index 44a7df1..f395082 100644 --- a/package.json +++ b/package.json @@ -15,14 +15,14 @@ "author": "Simon Cambier", "license": "GPL-3", "devDependencies": { - "@babel/preset-env": "^7.16.11", + "@babel/preset-env": "^7.17.10", "@babel/preset-typescript": "^7.16.7", "@testing-library/jest-dom": "^5.16.4", "@tsconfig/svelte": "^3.0.0", - "@types/jest": "^27.4.1", - "@types/node": "^16.11.27", - "@typescript-eslint/eslint-plugin": "^5.20.0", - "@typescript-eslint/parser": "^5.20.0", + "@types/jest": "^27.5.0", + "@types/node": "^16.11.34", + "@typescript-eslint/eslint-plugin": "^5.23.0", + "@typescript-eslint/parser": "^5.23.0", "babel-jest": "^27.5.1", "builtin-modules": "^3.2.0", "esbuild": "0.13.12", @@ -38,11 +38,11 @@ "obsidian": "latest", "prettier": "^2.6.2", "prettier-eslint": "^13.0.0", - "svelte": "^3.47.0", + "svelte": "^3.48.0", "svelte-jester": "^2.3.2", "svelte-preprocess": "^4.10.6", "tslib": "2.3.1", - "typescript": "^4.6.3" + "typescript": "^4.6.4" }, "dependencies": { "minisearch": "^5.0.0-beta1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d9db0d6..e1e0110 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,14 +1,14 @@ lockfileVersion: 5.3 specifiers: - '@babel/preset-env': ^7.16.11 + '@babel/preset-env': ^7.17.10 '@babel/preset-typescript': ^7.16.7 '@testing-library/jest-dom': ^5.16.4 '@tsconfig/svelte': ^3.0.0 - '@types/jest': ^27.4.1 - '@types/node': ^16.11.27 - '@typescript-eslint/eslint-plugin': ^5.20.0 - '@typescript-eslint/parser': ^5.20.0 + '@types/jest': ^27.5.0 + '@types/node': ^16.11.34 + '@typescript-eslint/eslint-plugin': ^5.23.0 + '@typescript-eslint/parser': ^5.23.0 babel-jest: ^27.5.1 builtin-modules: ^3.2.0 esbuild: 0.13.12 @@ -25,52 +25,53 @@ specifiers: obsidian: latest prettier: ^2.6.2 prettier-eslint: ^13.0.0 - svelte: ^3.47.0 + svelte: ^3.48.0 svelte-jester: ^2.3.2 svelte-preprocess: ^4.10.6 tslib: 2.3.1 - typescript: ^4.6.3 + typescript: ^4.6.4 dependencies: minisearch: 5.0.0-beta1 devDependencies: - '@babel/preset-env': 7.16.11 + '@babel/preset-env': 7.17.10 '@babel/preset-typescript': 7.16.7 '@testing-library/jest-dom': 5.16.4 '@tsconfig/svelte': 3.0.0 - '@types/jest': 27.4.1 - '@types/node': 16.11.27 - '@typescript-eslint/eslint-plugin': 5.20.0_4fbab8ed861393b891eae3bdfcc6594e - '@typescript-eslint/parser': 5.20.0_eslint@7.12.1+typescript@4.6.3 + '@types/jest': 27.5.0 + '@types/node': 16.11.34 + '@typescript-eslint/eslint-plugin': 5.23.0_8d5dd86e19d360799b5f51045840aced + '@typescript-eslint/parser': 5.23.0_eslint@7.12.1+typescript@4.6.4 babel-jest: 27.5.1 builtin-modules: 3.2.0 esbuild: 0.13.12 esbuild-plugin-copy: 1.3.0_esbuild@0.13.12 - esbuild-svelte: 0.7.0_esbuild@0.13.12+svelte@3.47.0 + esbuild-svelte: 0.7.0_esbuild@0.13.12+svelte@3.48.0 eslint: 7.12.1 eslint-config-standard: 16.0.3_0fed5a0754053d34bf68c4e5b9539157 eslint-plugin-import: 2.22.1_eslint@7.12.1 eslint-plugin-node: 11.1.0_eslint@7.12.1 eslint-plugin-promise: 5.0.0_eslint@7.12.1 - eslint-plugin-svelte3: 3.4.1_eslint@7.12.1+svelte@3.47.0 + eslint-plugin-svelte3: 3.4.1_eslint@7.12.1+svelte@3.48.0 jest: 27.5.1 - obsidian: 0.14.6 + obsidian: 0.14.8 prettier: 2.6.2 prettier-eslint: 13.0.0 - svelte: 3.47.0 - svelte-jester: 2.3.2_jest@27.5.1+svelte@3.47.0 - svelte-preprocess: 4.10.6_svelte@3.47.0+typescript@4.6.3 + svelte: 3.48.0 + svelte-jester: 2.3.2_jest@27.5.1+svelte@3.48.0 + svelte-preprocess: 4.10.6_svelte@3.48.0+typescript@4.6.4 tslib: 2.3.1 - typescript: 4.6.3 + typescript: 4.6.4 packages: - /@ampproject/remapping/2.1.2: - resolution: {integrity: sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==} + /@ampproject/remapping/2.2.0: + resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} engines: {node: '>=6.0.0'} dependencies: - '@jridgewell/trace-mapping': 0.3.9 + '@jridgewell/gen-mapping': 0.1.1 + '@jridgewell/trace-mapping': 0.3.11 dev: true /@babel/code-frame/7.16.7: @@ -80,25 +81,25 @@ packages: '@babel/highlight': 7.17.9 dev: true - /@babel/compat-data/7.17.7: - resolution: {integrity: sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==} + /@babel/compat-data/7.17.10: + resolution: {integrity: sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==} engines: {node: '>=6.9.0'} dev: true - /@babel/core/7.17.9: - resolution: {integrity: sha512-5ug+SfZCpDAkVp9SFIZAzlW18rlzsOcJGaetCjkySnrXXDUw9AR8cDUm1iByTmdWM6yxX6/zycaV76w3YTF2gw==} + /@babel/core/7.17.10: + resolution: {integrity: sha512-liKoppandF3ZcBnIYFjfSDHZLKdLHGJRkoWtG8zQyGJBQfIYobpnVGI5+pLBNtS6psFLDzyq8+h5HiVljW9PNA==} engines: {node: '>=6.9.0'} dependencies: - '@ampproject/remapping': 2.1.2 + '@ampproject/remapping': 2.2.0 '@babel/code-frame': 7.16.7 - '@babel/generator': 7.17.9 - '@babel/helper-compilation-targets': 7.17.7_@babel+core@7.17.9 + '@babel/generator': 7.17.10 + '@babel/helper-compilation-targets': 7.17.10_@babel+core@7.17.10 '@babel/helper-module-transforms': 7.17.7 '@babel/helpers': 7.17.9 - '@babel/parser': 7.17.9 + '@babel/parser': 7.17.10 '@babel/template': 7.16.7 - '@babel/traverse': 7.17.9 - '@babel/types': 7.17.0 + '@babel/traverse': 7.17.10 + '@babel/types': 7.17.10 convert-source-map: 1.8.0 debug: 4.3.4 gensync: 1.0.0-beta.2 @@ -108,20 +109,20 @@ packages: - supports-color dev: true - /@babel/generator/7.17.9: - resolution: {integrity: sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ==} + /@babel/generator/7.17.10: + resolution: {integrity: sha512-46MJZZo9y3o4kmhBVc7zW7i8dtR1oIK/sdO5NcfcZRhTGYi+KKJRtHNgsU6c4VUcJmUNV/LQdebD/9Dlv4K+Tg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 + '@jridgewell/gen-mapping': 0.1.1 jsesc: 2.5.2 - source-map: 0.5.7 dev: true /@babel/helper-annotate-as-pure/7.16.7: resolution: {integrity: sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 dev: true /@babel/helper-builder-binary-assignment-operator-visitor/7.16.7: @@ -129,31 +130,31 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/helper-explode-assignable-expression': 7.16.7 - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 dev: true - /@babel/helper-compilation-targets/7.17.7: - resolution: {integrity: sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==} + /@babel/helper-compilation-targets/7.17.10: + resolution: {integrity: sha512-gh3RxjWbauw/dFiU/7whjd0qN9K6nPJMqe6+Er7rOavFh0CQUSwhAE3IcTho2rywPJFxej6TUUHDkWcYI6gGqQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.17.7 + '@babel/compat-data': 7.17.10 '@babel/helper-validator-option': 7.16.7 - browserslist: 4.20.2 + browserslist: 4.20.3 semver: 6.3.0 dev: true - /@babel/helper-compilation-targets/7.17.7_@babel+core@7.17.9: - resolution: {integrity: sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==} + /@babel/helper-compilation-targets/7.17.10_@babel+core@7.17.10: + resolution: {integrity: sha512-gh3RxjWbauw/dFiU/7whjd0qN9K6nPJMqe6+Er7rOavFh0CQUSwhAE3IcTho2rywPJFxej6TUUHDkWcYI6gGqQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.17.7 - '@babel/core': 7.17.9 + '@babel/compat-data': 7.17.10 + '@babel/core': 7.17.10 '@babel/helper-validator-option': 7.16.7 - browserslist: 4.20.2 + browserslist: 4.20.3 semver: 6.3.0 dev: true @@ -189,10 +190,10 @@ packages: peerDependencies: '@babel/core': ^7.4.0-0 dependencies: - '@babel/helper-compilation-targets': 7.17.7 + '@babel/helper-compilation-targets': 7.17.10 '@babel/helper-module-imports': 7.16.7 '@babel/helper-plugin-utils': 7.16.7 - '@babel/traverse': 7.17.9 + '@babel/traverse': 7.17.10 debug: 4.3.4 lodash.debounce: 4.0.8 resolve: 1.22.0 @@ -205,14 +206,14 @@ packages: resolution: {integrity: sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 dev: true /@babel/helper-explode-assignable-expression/7.16.7: resolution: {integrity: sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 dev: true /@babel/helper-function-name/7.17.9: @@ -220,28 +221,28 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.16.7 - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 dev: true /@babel/helper-hoist-variables/7.16.7: resolution: {integrity: sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 dev: true /@babel/helper-member-expression-to-functions/7.17.7: resolution: {integrity: sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 dev: true /@babel/helper-module-imports/7.16.7: resolution: {integrity: sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 dev: true /@babel/helper-module-transforms/7.17.7: @@ -254,8 +255,8 @@ packages: '@babel/helper-split-export-declaration': 7.16.7 '@babel/helper-validator-identifier': 7.16.7 '@babel/template': 7.16.7 - '@babel/traverse': 7.17.9 - '@babel/types': 7.17.0 + '@babel/traverse': 7.17.10 + '@babel/types': 7.17.10 transitivePeerDependencies: - supports-color dev: true @@ -264,7 +265,7 @@ packages: resolution: {integrity: sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 dev: true /@babel/helper-plugin-utils/7.16.7: @@ -278,7 +279,7 @@ packages: dependencies: '@babel/helper-annotate-as-pure': 7.16.7 '@babel/helper-wrap-function': 7.16.8 - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 transitivePeerDependencies: - supports-color dev: true @@ -290,8 +291,8 @@ packages: '@babel/helper-environment-visitor': 7.16.7 '@babel/helper-member-expression-to-functions': 7.17.7 '@babel/helper-optimise-call-expression': 7.16.7 - '@babel/traverse': 7.17.9 - '@babel/types': 7.17.0 + '@babel/traverse': 7.17.10 + '@babel/types': 7.17.10 transitivePeerDependencies: - supports-color dev: true @@ -300,21 +301,21 @@ packages: resolution: {integrity: sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 dev: true /@babel/helper-skip-transparent-expression-wrappers/7.16.0: resolution: {integrity: sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 dev: true /@babel/helper-split-export-declaration/7.16.7: resolution: {integrity: sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 dev: true /@babel/helper-validator-identifier/7.16.7: @@ -333,8 +334,8 @@ packages: dependencies: '@babel/helper-function-name': 7.17.9 '@babel/template': 7.16.7 - '@babel/traverse': 7.17.9 - '@babel/types': 7.17.0 + '@babel/traverse': 7.17.10 + '@babel/types': 7.17.10 transitivePeerDependencies: - supports-color dev: true @@ -344,8 +345,8 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.16.7 - '@babel/traverse': 7.17.9 - '@babel/types': 7.17.0 + '@babel/traverse': 7.17.10 + '@babel/types': 7.17.10 transitivePeerDependencies: - supports-color dev: true @@ -359,8 +360,8 @@ packages: js-tokens: 4.0.0 dev: true - /@babel/parser/7.17.9: - resolution: {integrity: sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg==} + /@babel/parser/7.17.10: + resolution: {integrity: sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==} engines: {node: '>=6.0.0'} hasBin: true dev: true @@ -489,8 +490,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.17.7 - '@babel/helper-compilation-targets': 7.17.7 + '@babel/compat-data': 7.17.10 + '@babel/helper-compilation-targets': 7.17.10 '@babel/helper-plugin-utils': 7.16.7 '@babel/plugin-syntax-object-rest-spread': 7.8.3 '@babel/plugin-transform-parameters': 7.16.7 @@ -561,12 +562,12 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.17.9: + /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.17.10: resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@babel/helper-plugin-utils': 7.16.7 dev: true @@ -578,12 +579,12 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.17.9: + /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.17.10: resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@babel/helper-plugin-utils': 7.16.7 dev: true @@ -595,12 +596,12 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.17.9: + /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.17.10: resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@babel/helper-plugin-utils': 7.16.7 dev: true @@ -637,12 +638,12 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.17.9: + /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.17.10: resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@babel/helper-plugin-utils': 7.16.7 dev: true @@ -654,12 +655,12 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.17.9: + /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.17.10: resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@babel/helper-plugin-utils': 7.16.7 dev: true @@ -671,12 +672,12 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.17.9: + /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.17.10: resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@babel/helper-plugin-utils': 7.16.7 dev: true @@ -688,12 +689,12 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.17.9: + /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.17.10: resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@babel/helper-plugin-utils': 7.16.7 dev: true @@ -705,12 +706,12 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.17.9: + /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.17.10: resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@babel/helper-plugin-utils': 7.16.7 dev: true @@ -722,12 +723,12 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.17.9: + /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.17.10: resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@babel/helper-plugin-utils': 7.16.7 dev: true @@ -739,12 +740,12 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.17.9: + /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.17.10: resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@babel/helper-plugin-utils': 7.16.7 dev: true @@ -756,12 +757,12 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.17.9: + /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.17.10: resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@babel/helper-plugin-utils': 7.16.7 dev: true @@ -783,18 +784,18 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.17.9: + /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.17.10: resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-typescript/7.16.7: - resolution: {integrity: sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==} + /@babel/plugin-syntax-typescript/7.17.10: + resolution: {integrity: sha512-xJefea1DWXW09pW4Tm9bjwVlPDyYA2it3fWlmEjpYz6alPvTUjL0EOzNzI/FEOyI3r4/J7uVH5UqKgl1TQ5hqQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -802,13 +803,13 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-syntax-typescript/7.16.7_@babel+core@7.17.9: - resolution: {integrity: sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==} + /@babel/plugin-syntax-typescript/7.17.10_@babel+core@7.17.10: + resolution: {integrity: sha512-xJefea1DWXW09pW4Tm9bjwVlPDyYA2it3fWlmEjpYz6alPvTUjL0EOzNzI/FEOyI3r4/J7uVH5UqKgl1TQ5hqQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@babel/helper-plugin-utils': 7.16.7 dev: true @@ -932,7 +933,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-compilation-targets': 7.17.7 + '@babel/helper-compilation-targets': 7.17.10 '@babel/helper-function-name': 7.17.9 '@babel/helper-plugin-utils': 7.16.7 dev: true @@ -1009,8 +1010,8 @@ packages: - supports-color dev: true - /@babel/plugin-transform-named-capturing-groups-regex/7.16.8: - resolution: {integrity: sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==} + /@babel/plugin-transform-named-capturing-groups-regex/7.17.10: + resolution: {integrity: sha512-v54O6yLaJySCs6mGzaVOUw9T967GnH38T6CQSAtnzdNPwu84l2qAjssKzo/WSO8Yi7NF+7ekm5cVbF/5qiIgNA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1129,7 +1130,7 @@ packages: dependencies: '@babel/helper-create-class-features-plugin': 7.17.9 '@babel/helper-plugin-utils': 7.16.7 - '@babel/plugin-syntax-typescript': 7.16.7 + '@babel/plugin-syntax-typescript': 7.17.10 transitivePeerDependencies: - supports-color dev: true @@ -1153,14 +1154,14 @@ packages: '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/preset-env/7.16.11: - resolution: {integrity: sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==} + /@babel/preset-env/7.17.10: + resolution: {integrity: sha512-YNgyBHZQpeoBSRBg0xixsZzfT58Ze1iZrajvv0lJc70qDDGuGfonEnMGfWeSY0mQ3JTuCWFbMkzFRVafOyJx4g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.17.7 - '@babel/helper-compilation-targets': 7.17.7 + '@babel/compat-data': 7.17.10 + '@babel/helper-compilation-targets': 7.17.10 '@babel/helper-plugin-utils': 7.16.7 '@babel/helper-validator-option': 7.16.7 '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.16.7 @@ -1212,7 +1213,7 @@ packages: '@babel/plugin-transform-modules-commonjs': 7.17.9 '@babel/plugin-transform-modules-systemjs': 7.17.8 '@babel/plugin-transform-modules-umd': 7.16.7 - '@babel/plugin-transform-named-capturing-groups-regex': 7.16.8 + '@babel/plugin-transform-named-capturing-groups-regex': 7.17.10 '@babel/plugin-transform-new-target': 7.16.7 '@babel/plugin-transform-object-super': 7.16.7 '@babel/plugin-transform-parameters': 7.16.7 @@ -1227,11 +1228,11 @@ packages: '@babel/plugin-transform-unicode-escapes': 7.16.7 '@babel/plugin-transform-unicode-regex': 7.16.7 '@babel/preset-modules': 0.1.5 - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 babel-plugin-polyfill-corejs2: 0.3.1 babel-plugin-polyfill-corejs3: 0.5.2 babel-plugin-polyfill-regenerator: 0.3.1 - core-js-compat: 3.22.2 + core-js-compat: 3.22.5 semver: 6.3.0 transitivePeerDependencies: - supports-color @@ -1245,7 +1246,7 @@ packages: '@babel/helper-plugin-utils': 7.16.7 '@babel/plugin-proposal-unicode-property-regex': 7.16.7 '@babel/plugin-transform-dotall-regex': 7.16.7 - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 esutils: 2.0.3 dev: true @@ -1274,30 +1275,30 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.16.7 - '@babel/parser': 7.17.9 - '@babel/types': 7.17.0 + '@babel/parser': 7.17.10 + '@babel/types': 7.17.10 dev: true - /@babel/traverse/7.17.9: - resolution: {integrity: sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw==} + /@babel/traverse/7.17.10: + resolution: {integrity: sha512-VmbrTHQteIdUUQNTb+zE12SHS/xQVIShmBPhlNP12hD5poF2pbITW1Z4172d03HegaQWhLffdkRJYtAzp0AGcw==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.16.7 - '@babel/generator': 7.17.9 + '@babel/generator': 7.17.10 '@babel/helper-environment-visitor': 7.16.7 '@babel/helper-function-name': 7.17.9 '@babel/helper-hoist-variables': 7.16.7 '@babel/helper-split-export-declaration': 7.16.7 - '@babel/parser': 7.17.9 - '@babel/types': 7.17.0 + '@babel/parser': 7.17.10 + '@babel/types': 7.17.10 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: true - /@babel/types/7.17.0: - resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==} + /@babel/types/7.17.10: + resolution: {integrity: sha512-9O26jG0mBYfGkUYCYZRnBwbVLd1UZOICEr2Em6InB6jVfsAv1GKgwXHmrSg+WFWDmeKTA6vyTZiN8tCSM5Oo3A==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-validator-identifier': 7.16.7 @@ -1373,7 +1374,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 16.11.27 + '@types/node': 16.11.34 chalk: 4.1.2 jest-message-util: 27.5.1 jest-util: 27.5.1 @@ -1394,7 +1395,7 @@ packages: '@jest/test-result': 27.5.1 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.11.27 + '@types/node': 16.11.34 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.8.1 @@ -1431,7 +1432,7 @@ packages: dependencies: '@jest/fake-timers': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.11.27 + '@types/node': 16.11.34 jest-mock: 27.5.1 dev: true @@ -1441,7 +1442,7 @@ packages: dependencies: '@jest/types': 27.5.1 '@sinonjs/fake-timers': 8.1.0 - '@types/node': 16.11.27 + '@types/node': 16.11.34 jest-message-util: 27.5.1 jest-mock: 27.5.1 jest-util: 27.5.1 @@ -1470,7 +1471,7 @@ packages: '@jest/test-result': 27.5.1 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.11.27 + '@types/node': 16.11.34 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -1529,7 +1530,7 @@ packages: resolution: {integrity: sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@jest/types': 27.5.1 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 @@ -1554,25 +1555,38 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 16.11.27 + '@types/node': 16.11.34 '@types/yargs': 16.0.4 chalk: 4.1.2 dev: true - /@jridgewell/resolve-uri/3.0.6: - resolution: {integrity: sha512-R7xHtBSNm+9SyvpJkdQl+qrM3Hm2fea3Ef197M3mUug+v+yR+Rhfbs7PBtcBUVnIWJ4JcAdjvij+c8hXS9p5aw==} + /@jridgewell/gen-mapping/0.1.1: + resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.1 + '@jridgewell/sourcemap-codec': 1.4.13 + dev: true + + /@jridgewell/resolve-uri/3.0.7: + resolution: {integrity: sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==} engines: {node: '>=6.0.0'} dev: true - /@jridgewell/sourcemap-codec/1.4.11: - resolution: {integrity: sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==} + /@jridgewell/set-array/1.1.1: + resolution: {integrity: sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==} + engines: {node: '>=6.0.0'} dev: true - /@jridgewell/trace-mapping/0.3.9: - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + /@jridgewell/sourcemap-codec/1.4.13: + resolution: {integrity: sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==} + dev: true + + /@jridgewell/trace-mapping/0.3.11: + resolution: {integrity: sha512-RllI476aSMsxzeI9TtlSMoNTgHDxEmnl6GkkHwhr0vdL8W+0WuesyI8Vd3rBOfrwtPXbPxdT9ADJdiOKgzxPQA==} dependencies: - '@jridgewell/resolve-uri': 3.0.6 - '@jridgewell/sourcemap-codec': 1.4.11 + '@jridgewell/resolve-uri': 3.0.7 + '@jridgewell/sourcemap-codec': 1.4.13 dev: true /@nodelib/fs.scandir/2.1.5: @@ -1618,7 +1632,7 @@ packages: chalk: 3.0.0 css: 3.0.0 css.escape: 1.5.1 - dom-accessibility-api: 0.5.13 + dom-accessibility-api: 0.5.14 lodash: 4.17.21 redent: 3.0.0 dev: true @@ -1635,30 +1649,30 @@ packages: /@types/babel__core/7.1.19: resolution: {integrity: sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==} dependencies: - '@babel/parser': 7.17.9 - '@babel/types': 7.17.0 + '@babel/parser': 7.17.10 + '@babel/types': 7.17.10 '@types/babel__generator': 7.6.4 '@types/babel__template': 7.4.1 - '@types/babel__traverse': 7.17.0 + '@types/babel__traverse': 7.17.1 dev: true /@types/babel__generator/7.6.4: resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} dependencies: - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 dev: true /@types/babel__template/7.4.1: resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} dependencies: - '@babel/parser': 7.17.9 - '@babel/types': 7.17.0 + '@babel/parser': 7.17.10 + '@babel/types': 7.17.10 dev: true - /@types/babel__traverse/7.17.0: - resolution: {integrity: sha512-r8aveDbd+rzGP+ykSdF3oPuTVRWRfbBiHl0rVDM2yNEmSMXfkObQLV46b4RnCv3Lra51OlfnZhkkFaDl2MIRaA==} + /@types/babel__traverse/7.17.1: + resolution: {integrity: sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==} dependencies: - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 dev: true /@types/codemirror/0.0.108: @@ -1678,7 +1692,7 @@ packages: /@types/graceful-fs/4.1.5: resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} dependencies: - '@types/node': 16.11.27 + '@types/node': 16.11.34 dev: true /@types/istanbul-lib-coverage/2.0.4: @@ -1697,8 +1711,8 @@ packages: '@types/istanbul-lib-report': 3.0.0 dev: true - /@types/jest/27.4.1: - resolution: {integrity: sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw==} + /@types/jest/27.5.0: + resolution: {integrity: sha512-9RBFx7r4k+msyj/arpfaa0WOOEcaAZNmN+j80KFbFCoSqCJGHTz7YMAMGQW9Xmqm5w6l5c25vbSjMwlikJi5+g==} dependencies: jest-matcher-utils: 27.5.1 pretty-format: 27.5.1 @@ -1712,8 +1726,8 @@ packages: resolution: {integrity: sha1-7ihweulOEdK4J7y+UnC86n8+ce4=} dev: true - /@types/node/16.11.27: - resolution: {integrity: sha512-C1pD3kgLoZ56Uuy5lhfOxie4aZlA3UMGLX9rXteq4WitEZH6Rl80mwactt9QG0w0gLFlN/kLBTFnGXtDVWvWQw==} + /@types/node/16.11.34: + resolution: {integrity: sha512-UrWGDyLAlQ2Z8bNOGWTsqbP9ZcBeTYBVuTRNxXTztBy5KhWUFI3BaeDWoCP/CzV/EVGgO1NTYzv9ZytBI9GAEw==} dev: true /@types/prettier/2.6.0: @@ -1727,7 +1741,7 @@ packages: /@types/sass/1.43.1: resolution: {integrity: sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==} dependencies: - '@types/node': 16.11.27 + '@types/node': 16.11.34 dev: true /@types/stack-utils/2.0.1: @@ -1743,7 +1757,7 @@ packages: /@types/testing-library__jest-dom/5.14.3: resolution: {integrity: sha512-oKZe+Mf4ioWlMuzVBaXQ9WDnEm1+umLx0InILg+yvZVBBDmzV5KfZyLrCvadtWcx8+916jLmHafcmqqffl+iIw==} dependencies: - '@types/jest': 27.4.1 + '@types/jest': 27.5.0 dev: true /@types/yargs-parser/21.0.0: @@ -1756,8 +1770,8 @@ packages: '@types/yargs-parser': 21.0.0 dev: true - /@typescript-eslint/eslint-plugin/5.20.0_4fbab8ed861393b891eae3bdfcc6594e: - resolution: {integrity: sha512-fapGzoxilCn3sBtC6NtXZX6+P/Hef7VDbyfGqTTpzYydwhlkevB+0vE0EnmHPVTVSy68GUncyJ/2PcrFBeCo5Q==} + /@typescript-eslint/eslint-plugin/5.23.0_8d5dd86e19d360799b5f51045840aced: + resolution: {integrity: sha512-hEcSmG4XodSLiAp1uxv/OQSGsDY6QN3TcRU32gANp+19wGE1QQZLRS8/GV58VRUoXhnkuJ3ZxNQ3T6Z6zM59DA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 @@ -1767,18 +1781,18 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.20.0_eslint@7.12.1+typescript@4.6.3 - '@typescript-eslint/scope-manager': 5.20.0 - '@typescript-eslint/type-utils': 5.20.0_eslint@7.12.1+typescript@4.6.3 - '@typescript-eslint/utils': 5.20.0_eslint@7.12.1+typescript@4.6.3 + '@typescript-eslint/parser': 5.23.0_eslint@7.12.1+typescript@4.6.4 + '@typescript-eslint/scope-manager': 5.23.0 + '@typescript-eslint/type-utils': 5.23.0_eslint@7.12.1+typescript@4.6.4 + '@typescript-eslint/utils': 5.23.0_eslint@7.12.1+typescript@4.6.4 debug: 4.3.4 eslint: 7.12.1 functional-red-black-tree: 1.0.1 ignore: 5.2.0 regexpp: 3.2.0 semver: 7.3.7 - tsutils: 3.21.0_typescript@4.6.3 - typescript: 4.6.3 + tsutils: 3.21.0_typescript@4.6.4 + typescript: 4.6.4 transitivePeerDependencies: - supports-color dev: true @@ -1821,8 +1835,8 @@ packages: - supports-color dev: true - /@typescript-eslint/parser/5.20.0_eslint@7.12.1+typescript@4.6.3: - resolution: {integrity: sha512-UWKibrCZQCYvobmu3/N8TWbEeo/EPQbS41Ux1F9XqPzGuV7pfg6n50ZrFo6hryynD8qOTTfLHtHjjdQtxJ0h/w==} + /@typescript-eslint/parser/5.23.0_eslint@7.12.1+typescript@4.6.4: + resolution: {integrity: sha512-V06cYUkqcGqpFjb8ttVgzNF53tgbB/KoQT/iB++DOIExKmzI9vBJKjZKt/6FuV9c+zrDsvJKbJ2DOCYwX91cbw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -1831,26 +1845,26 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.20.0 - '@typescript-eslint/types': 5.20.0 - '@typescript-eslint/typescript-estree': 5.20.0_typescript@4.6.3 + '@typescript-eslint/scope-manager': 5.23.0 + '@typescript-eslint/types': 5.23.0 + '@typescript-eslint/typescript-estree': 5.23.0_typescript@4.6.4 debug: 4.3.4 eslint: 7.12.1 - typescript: 4.6.3 + typescript: 4.6.4 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager/5.20.0: - resolution: {integrity: sha512-h9KtuPZ4D/JuX7rpp1iKg3zOH0WNEa+ZIXwpW/KWmEFDxlA/HSfCMhiyF1HS/drTICjIbpA6OqkAhrP/zkCStg==} + /@typescript-eslint/scope-manager/5.23.0: + resolution: {integrity: sha512-EhjaFELQHCRb5wTwlGsNMvzK9b8Oco4aYNleeDlNuL6qXWDF47ch4EhVNPh8Rdhf9tmqbN4sWDk/8g+Z/J8JVw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.20.0 - '@typescript-eslint/visitor-keys': 5.20.0 + '@typescript-eslint/types': 5.23.0 + '@typescript-eslint/visitor-keys': 5.23.0 dev: true - /@typescript-eslint/type-utils/5.20.0_eslint@7.12.1+typescript@4.6.3: - resolution: {integrity: sha512-WxNrCwYB3N/m8ceyoGCgbLmuZwupvzN0rE8NBuwnl7APgjv24ZJIjkNzoFBXPRCGzLNkoU/WfanW0exvp/+3Iw==} + /@typescript-eslint/type-utils/5.23.0_eslint@7.12.1+typescript@4.6.4: + resolution: {integrity: sha512-iuI05JsJl/SUnOTXA9f4oI+/4qS/Zcgk+s2ir+lRmXI+80D8GaGwoUqs4p+X+4AxDolPpEpVUdlEH4ADxFy4gw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '*' @@ -1859,11 +1873,11 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/utils': 5.20.0_eslint@7.12.1+typescript@4.6.3 + '@typescript-eslint/utils': 5.23.0_eslint@7.12.1+typescript@4.6.4 debug: 4.3.4 eslint: 7.12.1 - tsutils: 3.21.0_typescript@4.6.3 - typescript: 4.6.3 + tsutils: 3.21.0_typescript@4.6.4 + typescript: 4.6.4 transitivePeerDependencies: - supports-color dev: true @@ -1873,8 +1887,8 @@ packages: engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} dev: true - /@typescript-eslint/types/5.20.0: - resolution: {integrity: sha512-+d8wprF9GyvPwtoB4CxBAR/s0rpP25XKgnOvMf/gMXYDvlUC3rPFHupdTQ/ow9vn7UDe5rX02ovGYQbv/IUCbg==} + /@typescript-eslint/types/5.23.0: + resolution: {integrity: sha512-NfBsV/h4dir/8mJwdZz7JFibaKC3E/QdeMEDJhiAE3/eMkoniZ7MjbEMCGXw6MZnZDMN3G9S0mH/6WUIj91dmw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -1900,8 +1914,8 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree/5.20.0_typescript@4.6.3: - resolution: {integrity: sha512-36xLjP/+bXusLMrT9fMMYy1KJAGgHhlER2TqpUVDYUQg4w0q/NW/sg4UGAgVwAqb8V4zYg43KMUpM8vV2lve6w==} + /@typescript-eslint/typescript-estree/5.23.0_typescript@4.6.4: + resolution: {integrity: sha512-xE9e0lrHhI647SlGMl+m+3E3CKPF1wzvvOEWnuE3CCjjT7UiRnDGJxmAcVKJIlFgK6DY9RB98eLr1OPigPEOGg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -1909,28 +1923,28 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.20.0 - '@typescript-eslint/visitor-keys': 5.20.0 + '@typescript-eslint/types': 5.23.0 + '@typescript-eslint/visitor-keys': 5.23.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 semver: 7.3.7 - tsutils: 3.21.0_typescript@4.6.3 - typescript: 4.6.3 + tsutils: 3.21.0_typescript@4.6.4 + typescript: 4.6.4 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils/5.20.0_eslint@7.12.1+typescript@4.6.3: - resolution: {integrity: sha512-lHONGJL1LIO12Ujyx8L8xKbwWSkoUKFSO+0wDAqGXiudWB2EO7WEUT+YZLtVbmOmSllAjLb9tpoIPwpRe5Tn6w==} + /@typescript-eslint/utils/5.23.0_eslint@7.12.1+typescript@4.6.4: + resolution: {integrity: sha512-dbgaKN21drqpkbbedGMNPCtRPZo1IOUr5EI9Jrrh99r5UW5Q0dz46RKXeSBoPV+56R6dFKpbrdhgUNSJsDDRZA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: '@types/json-schema': 7.0.11 - '@typescript-eslint/scope-manager': 5.20.0 - '@typescript-eslint/types': 5.20.0 - '@typescript-eslint/typescript-estree': 5.20.0_typescript@4.6.3 + '@typescript-eslint/scope-manager': 5.23.0 + '@typescript-eslint/types': 5.23.0 + '@typescript-eslint/typescript-estree': 5.23.0_typescript@4.6.4 eslint: 7.12.1 eslint-scope: 5.1.1 eslint-utils: 3.0.0_eslint@7.12.1 @@ -1946,11 +1960,11 @@ packages: eslint-visitor-keys: 1.3.0 dev: true - /@typescript-eslint/visitor-keys/5.20.0: - resolution: {integrity: sha512-1flRpNF+0CAQkMNlTJ6L/Z5jiODG/e5+7mk6XwtPOUS3UrTz3UOiAg9jG2VtKsWI6rZQfy4C6a232QNRZTRGlg==} + /@typescript-eslint/visitor-keys/5.23.0: + resolution: {integrity: sha512-Vd4mFNchU62sJB8pX19ZSPog05B0Y0CE2UxAZPT5k4iqhRYjPnqyY3woMxCd0++t9OTqkgjST+1ydLBi7e2Fvg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.20.0 + '@typescript-eslint/types': 5.23.0 eslint-visitor-keys: 3.3.0 dev: true @@ -1984,8 +1998,8 @@ packages: hasBin: true dev: true - /acorn/8.7.0: - resolution: {integrity: sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==} + /acorn/8.7.1: + resolution: {integrity: sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==} engines: {node: '>=0.4.0'} hasBin: true dev: true @@ -2083,13 +2097,13 @@ packages: engines: {node: '>=6.0'} dev: true - /array-includes/3.1.4: - resolution: {integrity: sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==} + /array-includes/3.1.5: + resolution: {integrity: sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.19.5 + es-abstract: 1.20.0 get-intrinsic: 1.1.1 is-string: 1.0.7 dev: true @@ -2105,7 +2119,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.19.5 + es-abstract: 1.20.0 es-shim-unscopables: 1.0.0 dev: true @@ -2142,18 +2156,18 @@ packages: - supports-color dev: true - /babel-jest/27.5.1_@babel+core@7.17.9: + /babel-jest/27.5.1_@babel+core@7.17.10: resolution: {integrity: sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} peerDependencies: '@babel/core': ^7.8.0 dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 '@types/babel__core': 7.1.19 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 27.5.1_@babel+core@7.17.9 + babel-preset-jest: 27.5.1_@babel+core@7.17.10 chalk: 4.1.2 graceful-fs: 4.2.10 slash: 3.0.0 @@ -2185,9 +2199,9 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@babel/template': 7.16.7 - '@babel/types': 7.17.0 + '@babel/types': 7.17.10 '@types/babel__core': 7.1.19 - '@types/babel__traverse': 7.17.0 + '@types/babel__traverse': 7.17.1 dev: true /babel-plugin-polyfill-corejs2/0.3.1: @@ -2195,7 +2209,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.17.7 + '@babel/compat-data': 7.17.10 '@babel/helper-define-polyfill-provider': 0.3.1 semver: 6.3.0 transitivePeerDependencies: @@ -2208,7 +2222,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/helper-define-polyfill-provider': 0.3.1 - core-js-compat: 3.22.2 + core-js-compat: 3.22.5 transitivePeerDependencies: - supports-color dev: true @@ -2242,24 +2256,24 @@ packages: '@babel/plugin-syntax-top-level-await': 7.14.5 dev: true - /babel-preset-current-node-syntax/1.0.1_@babel+core@7.17.9: + /babel-preset-current-node-syntax/1.0.1_@babel+core@7.17.10: resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.17.9 - '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.17.9 - '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.17.9 - '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.17.9 - '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.17.9 - '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.17.9 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.17.9 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.17.9 - '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.17.9 - '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.17.9 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.17.9 - '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.17.9 - '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.17.9 + '@babel/core': 7.17.10 + '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.17.10 + '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.17.10 + '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.17.10 + '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.17.10 + '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.17.10 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.17.10 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.17.10 + '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.17.10 + '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.17.10 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.17.10 + '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.17.10 + '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.17.10 dev: true /babel-preset-jest/27.5.1: @@ -2272,15 +2286,15 @@ packages: babel-preset-current-node-syntax: 1.0.1 dev: true - /babel-preset-jest/27.5.1_@babel+core@7.17.9: + /babel-preset-jest/27.5.1_@babel+core@7.17.10: resolution: {integrity: sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 babel-plugin-jest-hoist: 27.5.1 - babel-preset-current-node-syntax: 1.0.1_@babel+core@7.17.9 + babel-preset-current-node-syntax: 1.0.1_@babel+core@7.17.10 dev: true /balanced-match/1.0.2: @@ -2305,15 +2319,15 @@ packages: resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} dev: true - /browserslist/4.20.2: - resolution: {integrity: sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==} + /browserslist/4.20.3: + resolution: {integrity: sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001332 - electron-to-chromium: 1.4.118 + caniuse-lite: 1.0.30001339 + electron-to-chromium: 1.4.137 escalade: 3.1.1 - node-releases: 2.0.3 + node-releases: 2.0.4 picocolors: 1.0.0 dev: true @@ -2358,8 +2372,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite/1.0.30001332: - resolution: {integrity: sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw==} + /caniuse-lite/1.0.30001339: + resolution: {integrity: sha512-Es8PiVqCe+uXdms0Gu5xP5PF2bxLR7OBp3wUzUnuO7OHzhOfCyg3hdiGWVPVxhiuniOzng+hTc1u3fEQ0TlkSQ==} dev: true /chalk/1.1.3: @@ -2476,10 +2490,10 @@ packages: safe-buffer: 5.1.2 dev: true - /core-js-compat/3.22.2: - resolution: {integrity: sha512-Fns9lU06ZJ07pdfmPMu7OnkIKGPKDzXKIiuGlSvHHapwqMUF2QnnsWwtueFZtSyZEilP0o6iUeHQwpn7LxtLUw==} + /core-js-compat/3.22.5: + resolution: {integrity: sha512-rEF75n3QtInrYICvJjrAgV03HwKiYvtKHdPtaba1KucG+cNZ4NJnH9isqt979e67KZlhpbCOTwnsvnIr+CVeOg==} dependencies: - browserslist: 4.20.2 + browserslist: 4.20.3 semver: 7.0.0 dev: true @@ -2628,8 +2642,8 @@ packages: esutils: 2.0.3 dev: true - /dom-accessibility-api/0.5.13: - resolution: {integrity: sha512-R305kwb5CcMDIpSHUnLyIAp7SrSPBx6F0VfQFB3M75xVMHhXJJIdePYgbPPh1o57vCHNu5QztokWUPsLjWzFqw==} + /dom-accessibility-api/0.5.14: + resolution: {integrity: sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==} dev: true /domexception/2.0.1: @@ -2639,8 +2653,8 @@ packages: webidl-conversions: 5.0.0 dev: true - /electron-to-chromium/1.4.118: - resolution: {integrity: sha512-maZIKjnYDvF7Fs35nvVcyr44UcKNwybr93Oba2n3HkKDFAtk0svERkLN/HyczJDS3Fo4wU9th9fUQd09ZLtj1w==} + /electron-to-chromium/1.4.137: + resolution: {integrity: sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==} dev: true /emittery/0.8.1: @@ -2669,16 +2683,18 @@ packages: is-arrayish: 0.2.1 dev: true - /es-abstract/1.19.5: - resolution: {integrity: sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==} + /es-abstract/1.20.0: + resolution: {integrity: sha512-URbD8tgRthKD3YcC39vbvSDrX23upXnPcnGAjQfgxXF5ID75YcENawc9ZX/9iTP9ptUyfCLIxTTuMYoRfiOVKA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 es-to-primitive: 1.2.1 function-bind: 1.1.1 + function.prototype.name: 1.1.5 get-intrinsic: 1.1.1 get-symbol-description: 1.0.0 has: 1.0.3 + has-property-descriptors: 1.0.0 has-symbols: 1.0.3 internal-slot: 1.0.3 is-callable: 1.2.4 @@ -2690,9 +2706,10 @@ packages: object-inspect: 1.12.0 object-keys: 1.1.1 object.assign: 4.1.2 - string.prototype.trimend: 1.0.4 - string.prototype.trimstart: 1.0.4 - unbox-primitive: 1.0.1 + regexp.prototype.flags: 1.4.3 + string.prototype.trimend: 1.0.5 + string.prototype.trimstart: 1.0.5 + unbox-primitive: 1.0.2 dev: true /es-shim-unscopables/1.0.0: @@ -2837,7 +2854,7 @@ packages: dev: true optional: true - /esbuild-svelte/0.7.0_esbuild@0.13.12+svelte@3.47.0: + /esbuild-svelte/0.7.0_esbuild@0.13.12+svelte@3.48.0: resolution: {integrity: sha512-hfiauhEXtGocUf7oVcxTrLhhF57ajBbvNCCClsS3KntEeITddKU+1WFhmsCt9SO0dQJlCFzJtpPu2dI7dRkXBw==} engines: {node: '>=12'} peerDependencies: @@ -2845,7 +2862,7 @@ packages: svelte: '>=3.43.0' dependencies: esbuild: 0.13.12 - svelte: 3.47.0 + svelte: 3.48.0 dev: true /esbuild-windows-32/0.13.12: @@ -2970,7 +2987,7 @@ packages: peerDependencies: eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 dependencies: - array-includes: 3.1.4 + array-includes: 3.1.5 array.prototype.flat: 1.3.0 contains-path: 0.1.0 debug: 2.6.9 @@ -3010,7 +3027,7 @@ packages: eslint: 7.12.1 dev: true - /eslint-plugin-svelte3/3.4.1_eslint@7.12.1+svelte@3.47.0: + /eslint-plugin-svelte3/3.4.1_eslint@7.12.1+svelte@3.48.0: resolution: {integrity: sha512-7p59WG8qV8L6wLdl4d/c3mdjkgVglQCdv5XOTk/iNPBKXuuV+Q0eFP5Wa6iJd/G2M1qR3BkLPEzaANOqKAZczw==} engines: {node: '>=10'} peerDependencies: @@ -3018,7 +3035,7 @@ packages: svelte: ^3.2.0 dependencies: eslint: 7.12.1 - svelte: 3.47.0 + svelte: 3.48.0 dev: true /eslint-scope/5.1.1: @@ -3301,10 +3318,24 @@ packages: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} dev: true + /function.prototype.name/1.1.5: + resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.0 + functions-have-names: 1.2.3 + dev: true + /functional-red-black-tree/1.0.1: resolution: {integrity: sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=} dev: true + /functions-have-names/1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: true + /gensync/1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -3682,8 +3713,8 @@ packages: resolution: {integrity: sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.17.9 - '@babel/parser': 7.17.9 + '@babel/core': 7.17.10 + '@babel/parser': 7.17.10 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 semver: 6.3.0 @@ -3735,7 +3766,7 @@ packages: '@jest/environment': 27.5.1 '@jest/test-result': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.11.27 + '@types/node': 16.11.34 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 @@ -3794,10 +3825,10 @@ packages: ts-node: optional: true dependencies: - '@babel/core': 7.17.9 + '@babel/core': 7.17.10 '@jest/test-sequencer': 27.5.1 '@jest/types': 27.5.1 - babel-jest: 27.5.1_@babel+core@7.17.9 + babel-jest: 27.5.1_@babel+core@7.17.10 chalk: 4.1.2 ci-info: 3.3.0 deepmerge: 4.2.2 @@ -3860,7 +3891,7 @@ packages: '@jest/environment': 27.5.1 '@jest/fake-timers': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.11.27 + '@types/node': 16.11.34 jest-mock: 27.5.1 jest-util: 27.5.1 jsdom: 16.7.0 @@ -3878,7 +3909,7 @@ packages: '@jest/environment': 27.5.1 '@jest/fake-timers': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.11.27 + '@types/node': 16.11.34 jest-mock: 27.5.1 jest-util: 27.5.1 dev: true @@ -3894,7 +3925,7 @@ packages: dependencies: '@jest/types': 27.5.1 '@types/graceful-fs': 4.1.5 - '@types/node': 16.11.27 + '@types/node': 16.11.34 anymatch: 3.1.2 fb-watchman: 2.0.1 graceful-fs: 4.2.10 @@ -3916,7 +3947,7 @@ packages: '@jest/source-map': 27.5.1 '@jest/test-result': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.11.27 + '@types/node': 16.11.34 chalk: 4.1.2 co: 4.6.0 expect: 27.5.1 @@ -3971,7 +4002,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 16.11.27 + '@types/node': 16.11.34 dev: true /jest-pnp-resolver/1.2.2_jest-resolve@27.5.1: @@ -4027,7 +4058,7 @@ packages: '@jest/test-result': 27.5.1 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.11.27 + '@types/node': 16.11.34 chalk: 4.1.2 emittery: 0.8.1 graceful-fs: 4.2.10 @@ -4084,7 +4115,7 @@ packages: resolution: {integrity: sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@types/node': 16.11.27 + '@types/node': 16.11.34 graceful-fs: 4.2.10 dev: true @@ -4092,16 +4123,16 @@ packages: resolution: {integrity: sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@babel/core': 7.17.9 - '@babel/generator': 7.17.9 - '@babel/plugin-syntax-typescript': 7.16.7_@babel+core@7.17.9 - '@babel/traverse': 7.17.9 - '@babel/types': 7.17.0 + '@babel/core': 7.17.10 + '@babel/generator': 7.17.10 + '@babel/plugin-syntax-typescript': 7.17.10_@babel+core@7.17.10 + '@babel/traverse': 7.17.10 + '@babel/types': 7.17.10 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/babel__traverse': 7.17.0 + '@types/babel__traverse': 7.17.1 '@types/prettier': 2.6.0 - babel-preset-current-node-syntax: 1.0.1_@babel+core@7.17.9 + babel-preset-current-node-syntax: 1.0.1_@babel+core@7.17.10 chalk: 4.1.2 expect: 27.5.1 graceful-fs: 4.2.10 @@ -4123,7 +4154,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 16.11.27 + '@types/node': 16.11.34 chalk: 4.1.2 ci-info: 3.3.0 graceful-fs: 4.2.10 @@ -4148,7 +4179,7 @@ packages: dependencies: '@jest/test-result': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.11.27 + '@types/node': 16.11.34 ansi-escapes: 4.3.2 chalk: 4.1.2 jest-util: 27.5.1 @@ -4159,7 +4190,7 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 16.11.27 + '@types/node': 16.11.34 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true @@ -4207,7 +4238,7 @@ packages: optional: true dependencies: abab: 2.0.6 - acorn: 8.7.0 + acorn: 8.7.1 acorn-globals: 6.0.0 cssom: 0.4.4 cssstyle: 2.3.0 @@ -4472,8 +4503,8 @@ packages: resolution: {integrity: sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=} dev: true - /node-releases/2.0.3: - resolution: {integrity: sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==} + /node-releases/2.0.4: + resolution: {integrity: sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==} dev: true /normalize-package-data/2.5.0: @@ -4526,11 +4557,11 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.19.5 + es-abstract: 1.20.0 dev: true - /obsidian/0.14.6: - resolution: {integrity: sha512-oXPJ8Zt10WhN19bk5l4mZuXRZbbdT1QoMgxGGJ0bB7UcJa0bozDzugS5L/QiV9gDoujpUPxDWNVahEel6r0Fpw==} + /obsidian/0.14.8: + resolution: {integrity: sha512-CQz+B2HSbhGVEBwZBL3rPl29ruOBmEhCbBmW7PIILnnRh6fFFvYy3kZLHVTUidzvRGZnEW/mQ7n9LXeJCp2a/Q==} dependencies: '@codemirror/state': 0.19.9 '@codemirror/view': 0.19.48 @@ -4831,6 +4862,15 @@ packages: '@babel/runtime': 7.17.9 dev: true + /regexp.prototype.flags/1.4.3: + resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + functions-have-names: 1.2.3 + dev: true + /regexpp/3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} @@ -5045,11 +5085,6 @@ packages: source-map: 0.6.1 dev: true - /source-map/0.5.7: - resolution: {integrity: sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=} - engines: {node: '>=0.10.0'} - dev: true - /source-map/0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -5123,18 +5158,20 @@ packages: strip-ansi: 6.0.1 dev: true - /string.prototype.trimend/1.0.4: - resolution: {integrity: sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==} + /string.prototype.trimend/1.0.5: + resolution: {integrity: sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==} dependencies: call-bind: 1.0.2 define-properties: 1.1.4 + es-abstract: 1.20.0 dev: true - /string.prototype.trimstart/1.0.4: - resolution: {integrity: sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==} + /string.prototype.trimstart/1.0.5: + resolution: {integrity: sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==} dependencies: call-bind: 1.0.2 define-properties: 1.1.4 + es-abstract: 1.20.0 dev: true /strip-ansi/3.0.1: @@ -5228,7 +5265,7 @@ packages: engines: {node: '>= 0.4'} dev: true - /svelte-jester/2.3.2_jest@27.5.1+svelte@3.47.0: + /svelte-jester/2.3.2_jest@27.5.1+svelte@3.48.0: resolution: {integrity: sha512-JtxSz4FWAaCRBXbPsh4LcDs4Ua7zdXgLC0TZvT1R56hRV0dymmNP+abw67DTPF7sQPyNxWsOKd0Sl7Q8SnP8kg==} engines: {node: '>=14'} peerDependencies: @@ -5236,10 +5273,10 @@ packages: svelte: '>= 3' dependencies: jest: 27.5.1 - svelte: 3.47.0 + svelte: 3.48.0 dev: true - /svelte-preprocess/4.10.6_svelte@3.47.0+typescript@4.6.3: + /svelte-preprocess/4.10.6_svelte@3.48.0+typescript@4.6.4: resolution: {integrity: sha512-I2SV1w/AveMvgIQlUF/ZOO3PYVnhxfcpNyGt8pxpUVhPfyfL/CZBkkw/KPfuFix5FJ9TnnNYMhACK3DtSaYVVQ==} engines: {node: '>= 9.11.2'} requiresBuild: true @@ -5286,12 +5323,12 @@ packages: magic-string: 0.25.9 sorcery: 0.10.0 strip-indent: 3.0.0 - svelte: 3.47.0 - typescript: 4.6.3 + svelte: 3.48.0 + typescript: 4.6.4 dev: true - /svelte/3.47.0: - resolution: {integrity: sha512-4JaJp3HEoTCGARRWZQIZDUanhYv0iyoHikklVHVLH9xFE9db22g4TDv7CPeNA8HD1JgjXI1vlhR1JZvvhaTu2Q==} + /svelte/3.48.0: + resolution: {integrity: sha512-fN2YRm/bGumvjUpu6yI3BpvZnpIm9I6A7HR4oUNYd7ggYyIwSA/BX7DJ+UXXffLp6XNcUijyLvttbPVCYa/3xQ==} engines: {node: '>= 8'} dev: true @@ -5393,14 +5430,14 @@ packages: typescript: 3.9.10 dev: true - /tsutils/3.21.0_typescript@4.6.3: + /tsutils/3.21.0_typescript@4.6.4: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 4.6.3 + typescript: 4.6.4 dev: true /type-check/0.3.2: @@ -5444,16 +5481,16 @@ packages: hasBin: true dev: true - /typescript/4.6.3: - resolution: {integrity: sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==} + /typescript/4.6.4: + resolution: {integrity: sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==} engines: {node: '>=4.2.0'} hasBin: true dev: true - /unbox-primitive/1.0.1: - resolution: {integrity: sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==} + /unbox-primitive/1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: - function-bind: 1.1.1 + call-bind: 1.0.2 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 diff --git a/tsconfig.json b/tsconfig.json index 0468412..cea71ac 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,6 +22,7 @@ ] }, "include": [ - "**/*.ts" -, "src/__tests__/event-bus-tests.mts" ] + "**/*.ts", + "src/__tests__/event-bus-tests.mts" + ] } \ No newline at end of file From 7efddcb616fd6580b8a0ba878492ea7fed73cb99 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 11 May 2022 16:11:14 +0200 Subject: [PATCH 06/53] Display full path as basename, getAliasesFromMetadata(): return an array instead of a string --- src/__tests__/utils-tests.ts | 30 +++++++++++++++++++----------- src/search.ts | 5 +++-- src/utils.ts | 6 ++++-- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/__tests__/utils-tests.ts b/src/__tests__/utils-tests.ts index 4333720..986b458 100644 --- a/src/__tests__/utils-tests.ts +++ b/src/__tests__/utils-tests.ts @@ -3,21 +3,19 @@ import { getAliasesFromMetadata } from '../utils' describe('Utils', () => { describe('getAliasesFromMetadata', () => { - it('should return an empty string if no metadata is provided', () => { + it('should return an empty array if no metadata is provided', () => { // Act const actual = getAliasesFromMetadata(null) // Assert - expect(actual).toBe('') + expect(actual).toEqual([]) }) - it('should return an empty string if no aliases are provided', () => { - // Arrange - const metadata = {} as CachedMetadata + it('should return an empty array if no aliases are provided', () => { // Act - const actual = getAliasesFromMetadata(metadata) + const actual = getAliasesFromMetadata({}) // Assert - expect(actual).toBe('') + expect(actual).toEqual([]) }) - it('should join aliases with a comma', () => { + it('should return the aliases array as-is', () => { // Arrange const metadata = { frontmatter: { aliases: ['foo', 'bar'] }, @@ -25,9 +23,9 @@ describe('Utils', () => { // Act const actual = getAliasesFromMetadata(metadata) // Assert - expect(actual).toBe('foo, bar') + expect(actual).toEqual(['foo', 'bar']) }) - it('should return a single alias if only one is provided', () => { + it('should convert the aliases string into an array', () => { // Arrange const metadata = { frontmatter: { aliases: 'foo, bar' }, @@ -35,7 +33,17 @@ describe('Utils', () => { // Act const actual = getAliasesFromMetadata(metadata) // Assert - expect(actual).toBe('foo, bar') + expect(actual).toEqual(['foo', 'bar']) + }) + it('should return an empty array if the aliases field is an empty string', () => { + // Arrange + const metadata = { + frontmatter: { aliases: '' }, + } as CachedMetadata + // Act + const actual = getAliasesFromMetadata(metadata) + // Assert + expect(actual).toEqual([]) }) }) }) diff --git a/src/search.ts b/src/search.ts index 133ef01..b75c1d2 100644 --- a/src/search.ts +++ b/src/search.ts @@ -228,10 +228,10 @@ export async function addToIndex(file: TAbstractFile): Promise { // Make the document and index it const note: IndexedNote = { - basename: file.basename, + basename: file.path, content, path: file.path, - aliases: getAliasesFromMetadata(metadata), + aliases: getAliasesFromMetadata(metadata).join(''), headings1: metadata ? extractHeadingsFromCache(metadata, 1).join(' ') : '', @@ -242,6 +242,7 @@ export async function addToIndex(file: TAbstractFile): Promise { ? extractHeadingsFromCache(metadata, 3).join(' ') : '', } + minisearchInstance.add(note) indexedNotes[note.path] = note } diff --git a/src/utils.ts b/src/utils.ts index a4866bf..b96e150 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -150,7 +150,9 @@ export function stripMarkdownCharacters(text: string): string { export function getAliasesFromMetadata( metadata: CachedMetadata | null, -): string { +): string[] { const arrOrString = metadata?.frontmatter?.aliases ?? [] - return Array.isArray(arrOrString) ? arrOrString.join(', ') : arrOrString + return (Array.isArray(arrOrString) ? arrOrString : arrOrString.split(',')) + .map(s => s ? s.trim() : s) + .filter(s => !!s) } From 71b5ef929bc598fa58766da5f00b926e969d4817 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 11 May 2022 16:25:28 +0200 Subject: [PATCH 07/53] Moved some code --- src/query.ts | 330 +------------------------------------- src/utils.ts | 4 +- src/vendor/parse-query.ts | 330 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 333 insertions(+), 331 deletions(-) create mode 100644 src/vendor/parse-query.ts diff --git a/src/query.ts b/src/query.ts index 1726cbb..e6d0f5b 100644 --- a/src/query.ts +++ b/src/query.ts @@ -1,4 +1,5 @@ import { stripSurroundingQuotes } from './utils' +import { parseQuery } from './vendor/parse-query' type QueryToken = { /** @@ -48,333 +49,4 @@ export class Query { } } -/*! - * search-query-parser.js - * Original: https://github.com/nepsilon/search-query-parser - * Modified by Simon Cambier - * Copyright(c) 2014-2019 - * MIT Licensed - */ -interface SearchParserOptions { - offsets?: boolean - tokenize: true - keywords?: string[] - ranges?: string[] - alwaysArray?: boolean -} - -interface ISearchParserDictionary { - [key: string]: any -} - -type SearchParserKeyWordOffset = { - keyword: string - value?: string -} - -type SearchParserTextOffset = { - text: string -} - -type SearchParserOffset = ( - | SearchParserKeyWordOffset - | SearchParserTextOffset -) & { - offsetStart: number - offsetEnd: number -} - -interface SearchParserResult extends ISearchParserDictionary { - text: string[] - offsets: SearchParserOffset[] - exclude: { text: string[] } -} - -function parseQuery( - string: string, - options: SearchParserOptions, -): SearchParserResult { - // Set a default options object when none is provided - if (!options) { - options = { offsets: true, tokenize: true } - } - else { - // If options offsets was't passed, set it to true - options.offsets = - typeof options.offsets === 'undefined' ? true : options.offsets - } - - if (!string) { - string = '' - } - - // Our object to store the query object - const query: SearchParserResult = { - text: [], - offsets: [], - exclude: { text: [] }, - } - // When offsets is true, create their array - if (options.offsets) { - query.offsets = [] - } - const exclusion: ISearchParserDictionary & { text: string[] } = { text: [] } - const terms = [] - // Get a list of search terms respecting single and double quotes - const regex = - /(\S+:'(?:[^'\\]|\\.)*')|(\S+:"(?:[^"\\]|\\.)*")|(-?"(?:[^"\\]|\\.)*")|(-?'(?:[^'\\]|\\.)*')|\S+|\S+:\S+/g - let match - while ((match = regex.exec(string)) !== null) { - let term = match[0] - const sepIndex = term.indexOf(':') - - // Terms that contain a `:` - if (sepIndex !== -1) { - const key = term.slice(0, sepIndex) - let val = term.slice(sepIndex + 1) - - // Strip backslashes respecting escapes - val = (val + '').replace(/\\(.?)/g, function (s, n1) { - switch (n1) { - case '\\': - return '\\' - case '0': - return '\u0000' - case '': - return '' - default: - return n1 - } - }) - terms.push({ - keyword: key, - value: val, - offsetStart: match.index, - offsetEnd: match.index + term.length, - }) - } - - // Other terms - else { - let isExcludedTerm = false - if (term[0] === '-') { - isExcludedTerm = true - term = term.slice(1) - } - - // Strip backslashes respecting escapes - term = (term + '').replace(/\\(.?)/g, function (s, n1) { - switch (n1) { - case '\\': - return '\\' - case '0': - return '\u0000' - case '': - return '' - default: - return n1 - } - }) - - if (isExcludedTerm) { - exclusion.text.push(term) - } - else { - terms.push({ - text: term, - offsetStart: match.index, - offsetEnd: match.index + term.length, - }) - } - } - } - // Reverse to ensure proper order when pop()'ing. - terms.reverse() - // For each search term - let term - while ((term = terms.pop())) { - // When just a simple term - if (term.text) { - // We add it as pure text - query.text.push(term.text) - // When offsets is true, push a new offset - if (options.offsets) { - query.offsets.push(term) - } - } - // We got an advanced search syntax - else if (term.keyword) { - let key = term.keyword - // Check if the key is a registered keyword - options.keywords = options.keywords || [] - let isKeyword = false - let isExclusion = false - if (!/^-/.test(key)) { - isKeyword = !(options.keywords.indexOf(key) === -1) - } - else if (key[0] === '-') { - const _key = key.slice(1) - isKeyword = !(options.keywords.indexOf(_key) === -1) - if (isKeyword) { - key = _key - isExclusion = true - } - } - - // Check if the key is a registered range - options.ranges = options.ranges || [] - const isRange = !(options.ranges.indexOf(key) === -1) - // When the key matches a keyword - if (isKeyword) { - // When offsets is true, push a new offset - if (options.offsets) { - query.offsets.push({ - keyword: key, - value: term.value, - offsetStart: isExclusion ? term.offsetStart + 1 : term.offsetStart, - offsetEnd: term.offsetEnd, - }) - } - - const value = term.value - // When value is a thing - if (value.length) { - // Get an array of values when several are there - const values = value.split(',') - if (isExclusion) { - if (exclusion[key]) { - // ...many times... - if (exclusion[key] instanceof Array) { - // ...and got several values this time... - if (values.length > 1) { - // ... concatenate both arrays. - exclusion[key] = exclusion[key].concat(values) - } - else { - // ... append the current single value. - exclusion[key].push(value) - } - } - // We saw that keyword only once before - else { - // Put both the current value and the new - // value in an array - exclusion[key] = [exclusion[key]] - exclusion[key].push(value) - } - } - // First time we see that keyword - else { - // ...and got several values this time... - if (values.length > 1) { - // ...add all values seen. - exclusion[key] = values - } - // Got only a single value this time - else { - // Record its value as a string - if (options.alwaysArray) { - // ...but we always return an array if option alwaysArray is true - exclusion[key] = [value] - } - else { - // Record its value as a string - exclusion[key] = value - } - } - } - } - else { - // If we already have seen that keyword... - if (query[key]) { - // ...many times... - if (query[key] instanceof Array) { - // ...and got several values this time... - if (values.length > 1) { - // ... concatenate both arrays. - query[key] = query[key].concat(values) - } - else { - // ... append the current single value. - query[key].push(value) - } - } - // We saw that keyword only once before - else { - // Put both the current value and the new - // value in an array - query[key] = [query[key]] - query[key].push(value) - } - } - // First time we see that keyword - else { - // ...and got several values this time... - if (values.length > 1) { - // ...add all values seen. - query[key] = values - } - // Got only a single value this time - else { - if (options.alwaysArray) { - // ...but we always return an array if option alwaysArray is true - query[key] = [value] - } - else { - // Record its value as a string - query[key] = value - } - } - } - } - } - } - // The key allows a range - else if (isRange) { - // When offsets is true, push a new offset - if (options.offsets) { - query.offsets.push(term) - } - - const value = term.value - // Range are separated with a dash - const rangeValues = value.split('-') - // When both end of the range are specified - // keyword:XXXX-YYYY - query[key] = {} - if (rangeValues.length === 2) { - query[key].from = rangeValues[0] - query[key].to = rangeValues[1] - } - // When pairs of ranges are specified - // keyword:XXXX-YYYY,AAAA-BBBB - // else if (!rangeValues.length % 2) { - // } - // When only getting a single value, - // or an odd number of values - else { - query[key].from = value - } - } - else { - // We add it as pure text - const text = term.keyword + ':' + term.value - query.text.push(text) - - // When offsets is true, push a new offset - if (options.offsets) { - query.offsets.push({ - text: text, - offsetStart: term.offsetStart, - offsetEnd: term.offsetEnd, - }) - } - } - } - } - - // Return forged query object - query.exclude = exclusion - return query -} diff --git a/src/utils.ts b/src/utils.ts index b96e150..b0f0076 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -153,6 +153,6 @@ export function getAliasesFromMetadata( ): string[] { const arrOrString = metadata?.frontmatter?.aliases ?? [] return (Array.isArray(arrOrString) ? arrOrString : arrOrString.split(',')) - .map(s => s ? s.trim() : s) - .filter(s => !!s) + .map(s => (s ? s.trim() : s)) + .filter(s => !!s) } diff --git a/src/vendor/parse-query.ts b/src/vendor/parse-query.ts new file mode 100644 index 0000000..4543b88 --- /dev/null +++ b/src/vendor/parse-query.ts @@ -0,0 +1,330 @@ +/*! + * search-query-parser.js + * Original: https://github.com/nepsilon/search-query-parser + * Modified by Simon Cambier + * Copyright(c) 2014-2019 + * MIT Licensed + */ + +interface SearchParserOptions { + offsets?: boolean + tokenize: true + keywords?: string[] + ranges?: string[] + alwaysArray?: boolean +} + +interface ISearchParserDictionary { + [key: string]: any +} + +type SearchParserKeyWordOffset = { + keyword: string + value?: string +} + +type SearchParserTextOffset = { + text: string +} + +type SearchParserOffset = ( + | SearchParserKeyWordOffset + | SearchParserTextOffset +) & { + offsetStart: number + offsetEnd: number +} + +interface SearchParserResult extends ISearchParserDictionary { + text: string[] + offsets: SearchParserOffset[] + exclude: { text: string[] } +} + +export function parseQuery( + string: string, + options: SearchParserOptions, +): SearchParserResult { + // Set a default options object when none is provided + if (!options) { + options = { offsets: true, tokenize: true } + } + else { + // If options offsets was't passed, set it to true + options.offsets = + typeof options.offsets === 'undefined' ? true : options.offsets + } + + if (!string) { + string = '' + } + + // Our object to store the query object + const query: SearchParserResult = { + text: [], + offsets: [], + exclude: { text: [] }, + } + // When offsets is true, create their array + if (options.offsets) { + query.offsets = [] + } + const exclusion: ISearchParserDictionary & { text: string[] } = { text: [] } + const terms = [] + // Get a list of search terms respecting single and double quotes + const regex = + /(\S+:'(?:[^'\\]|\\.)*')|(\S+:"(?:[^"\\]|\\.)*")|(-?"(?:[^"\\]|\\.)*")|(-?'(?:[^'\\]|\\.)*')|\S+|\S+:\S+/g + let match + while ((match = regex.exec(string)) !== null) { + let term = match[0] + const sepIndex = term.indexOf(':') + + // Terms that contain a `:` + if (sepIndex !== -1) { + const key = term.slice(0, sepIndex) + let val = term.slice(sepIndex + 1) + + // Strip backslashes respecting escapes + val = (val + '').replace(/\\(.?)/g, function (s, n1) { + switch (n1) { + case '\\': + return '\\' + case '0': + return '\u0000' + case '': + return '' + default: + return n1 + } + }) + terms.push({ + keyword: key, + value: val, + offsetStart: match.index, + offsetEnd: match.index + term.length, + }) + } + + // Other terms + else { + let isExcludedTerm = false + if (term[0] === '-') { + isExcludedTerm = true + term = term.slice(1) + } + + // Strip backslashes respecting escapes + term = (term + '').replace(/\\(.?)/g, function (s, n1) { + switch (n1) { + case '\\': + return '\\' + case '0': + return '\u0000' + case '': + return '' + default: + return n1 + } + }) + + if (isExcludedTerm) { + exclusion.text.push(term) + } + else { + terms.push({ + text: term, + offsetStart: match.index, + offsetEnd: match.index + term.length, + }) + } + } + } + // Reverse to ensure proper order when pop()'ing. + terms.reverse() + // For each search term + let term + while ((term = terms.pop())) { + // When just a simple term + if (term.text) { + // We add it as pure text + query.text.push(term.text) + // When offsets is true, push a new offset + if (options.offsets) { + query.offsets.push(term) + } + } + // We got an advanced search syntax + else if (term.keyword) { + let key = term.keyword + // Check if the key is a registered keyword + options.keywords = options.keywords || [] + let isKeyword = false + let isExclusion = false + if (!/^-/.test(key)) { + isKeyword = !(options.keywords.indexOf(key) === -1) + } + else if (key[0] === '-') { + const _key = key.slice(1) + isKeyword = !(options.keywords.indexOf(_key) === -1) + if (isKeyword) { + key = _key + isExclusion = true + } + } + + // Check if the key is a registered range + options.ranges = options.ranges || [] + const isRange = !(options.ranges.indexOf(key) === -1) + // When the key matches a keyword + if (isKeyword) { + // When offsets is true, push a new offset + if (options.offsets) { + query.offsets.push({ + keyword: key, + value: term.value, + offsetStart: isExclusion ? term.offsetStart + 1 : term.offsetStart, + offsetEnd: term.offsetEnd, + }) + } + + const value = term.value + // When value is a thing + if (value.length) { + // Get an array of values when several are there + const values = value.split(',') + if (isExclusion) { + if (exclusion[key]) { + // ...many times... + if (exclusion[key] instanceof Array) { + // ...and got several values this time... + if (values.length > 1) { + // ... concatenate both arrays. + exclusion[key] = exclusion[key].concat(values) + } + else { + // ... append the current single value. + exclusion[key].push(value) + } + } + // We saw that keyword only once before + else { + // Put both the current value and the new + // value in an array + exclusion[key] = [exclusion[key]] + exclusion[key].push(value) + } + } + // First time we see that keyword + else { + // ...and got several values this time... + if (values.length > 1) { + // ...add all values seen. + exclusion[key] = values + } + // Got only a single value this time + else { + // Record its value as a string + if (options.alwaysArray) { + // ...but we always return an array if option alwaysArray is true + exclusion[key] = [value] + } + else { + // Record its value as a string + exclusion[key] = value + } + } + } + } + else { + // If we already have seen that keyword... + if (query[key]) { + // ...many times... + if (query[key] instanceof Array) { + // ...and got several values this time... + if (values.length > 1) { + // ... concatenate both arrays. + query[key] = query[key].concat(values) + } + else { + // ... append the current single value. + query[key].push(value) + } + } + // We saw that keyword only once before + else { + // Put both the current value and the new + // value in an array + query[key] = [query[key]] + query[key].push(value) + } + } + // First time we see that keyword + else { + // ...and got several values this time... + if (values.length > 1) { + // ...add all values seen. + query[key] = values + } + // Got only a single value this time + else { + if (options.alwaysArray) { + // ...but we always return an array if option alwaysArray is true + query[key] = [value] + } + else { + // Record its value as a string + query[key] = value + } + } + } + } + } + } + // The key allows a range + else if (isRange) { + // When offsets is true, push a new offset + if (options.offsets) { + query.offsets.push(term) + } + + const value = term.value + // Range are separated with a dash + const rangeValues = value.split('-') + // When both end of the range are specified + // keyword:XXXX-YYYY + query[key] = {} + if (rangeValues.length === 2) { + query[key].from = rangeValues[0] + query[key].to = rangeValues[1] + } + // When pairs of ranges are specified + // keyword:XXXX-YYYY,AAAA-BBBB + // else if (!rangeValues.length % 2) { + // } + // When only getting a single value, + // or an odd number of values + else { + query[key].from = value + } + } + else { + // We add it as pure text + const text = term.keyword + ':' + term.value + query.text.push(text) + + // When offsets is true, push a new offset + if (options.offsets) { + query.offsets.push({ + text: text, + offsetStart: term.offsetStart, + offsetEnd: term.offsetEnd, + }) + } + } + } + } + + // Return forged query object + query.exclude = exclusion + return query +} From cfe72f350877b72ab90602495e23103d8d92b472 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Fri, 13 May 2022 22:44:40 +0200 Subject: [PATCH 08/53] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cbc39fd..894b317 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ ### New * #42 Files that are present in Obsidian's "Excluded Files" list are downranked by a factor of 3 (_desktop only_) -## 1.2.1 +## 1.1.1 ### Fixes * Fixed a crash when no results were returned @@ -28,4 +28,4 @@ This works as a "post-search" filter and does not allow for partial words search ## 1.0.0 * First non-beta release -* Includes Vault search and In-File search \ No newline at end of file +* Includes Vault search and In-File search From 57721295c537ca1f4d29443ac5dcec3397221d9c Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Sat, 14 May 2022 21:11:41 +0200 Subject: [PATCH 09/53] Also check the note's title for quoted terms --- src/search.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/search.ts b/src/search.ts index b75c1d2..12e87ca 100644 --- a/src/search.ts +++ b/src/search.ts @@ -115,10 +115,11 @@ async function search(query: Query): Promise { const exactTerms = query.getExactTerms() if (exactTerms.length) { results = results.filter(r => { + const title = indexedNotes[r.id]?.path.toLowerCase() ?? '' const content = stripMarkdownCharacters( indexedNotes[r.id]?.content ?? '', ).toLowerCase() - return exactTerms.every(q => content.includes(q)) + return exactTerms.every(q => content.includes(q) || title.includes(q)) }) } From 69e062bc694e64e826f2a54a1582f274baa5d6a4 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Sat, 14 May 2022 21:11:54 +0200 Subject: [PATCH 10/53] Removed useless code --- src/utils.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index b0f0076..5b7c742 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -61,19 +61,6 @@ export function stringsToRegex(strings: string[]): RegExp { return new RegExp(strings.map(s => `(${escapeRegex(s)})`).join('|'), 'gi') } -export function replaceAll( - text: string, - terms: string[], - cb: (t: string) => string, -): string { - terms.sort((a, b) => a.length - b.length) - const regs = terms.map(term => new RegExp(escapeRegex(term), 'gi')) - for (const reg of regs) { - text = text.replaceAll(reg, cb) - } - return text -} - export function extractHeadingsFromCache( cache: CachedMetadata, level: number, From 6852c26958a00c8e065496f69770c1a577b38fbb Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Sun, 15 May 2022 09:08:06 +0200 Subject: [PATCH 11/53] #50 - Handling compositionStart/End events --- src/components/InputSearch.svelte | 3 +++ src/globals.ts | 8 ++++++++ src/modals.ts | 8 +++++--- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/components/InputSearch.svelte b/src/components/InputSearch.svelte index 7c13437..88c7902 100644 --- a/src/components/InputSearch.svelte +++ b/src/components/InputSearch.svelte @@ -1,5 +1,6 @@ + \ No newline at end of file diff --git a/src/components/ResultItemContainer.svelte b/src/components/ResultItemContainer.svelte index c65c61d..2eac865 100644 --- a/src/components/ResultItemContainer.svelte +++ b/src/components/ResultItemContainer.svelte @@ -1,8 +1,9 @@
+ {#if glyph} + + {/if}
diff --git a/src/components/ResultItemVault.svelte b/src/components/ResultItemVault.svelte index 03de740..8c33e81 100644 --- a/src/components/ResultItemVault.svelte +++ b/src/components/ResultItemVault.svelte @@ -1,4 +1,5 @@ - + {@html note.basename.replace(reg, highlighter)} diff --git a/src/globals.ts b/src/globals.ts index c21aa31..10b6cd5 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -28,6 +28,8 @@ export type IndexedNote = { headings1: string headings2: string headings3: string + + doesNotExist?: boolean } export type SearchMatch = { diff --git a/src/main.ts b/src/main.ts index 19b2860..e967b5c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,9 +1,9 @@ import { Plugin, TFile } from 'obsidian' import { + addNonExistingToIndex, addToIndex, initGlobalSearchIndex, removeFromIndex, - removeFromIndexByPath, } from './search' import { OmnisearchInFileModal, OmnisearchVaultModal } from './modals' import { loadSettings, SettingsTab } from './settings' @@ -39,19 +39,21 @@ export default class OmnisearchPlugin extends Plugin { ) this.registerEvent( this.app.vault.on('delete', file => { - removeFromIndex(file) + removeFromIndex(file.path) + // Re-index the note as non-existing file + addNonExistingToIndex(file.name) }), ) this.registerEvent( this.app.vault.on('modify', async file => { - removeFromIndex(file) + removeFromIndex(file.path) await addToIndex(file) }), ) this.registerEvent( this.app.vault.on('rename', async (file, oldPath) => { if (file instanceof TFile && file.path.endsWith('.md')) { - removeFromIndexByPath(oldPath) + removeFromIndex(oldPath) await addToIndex(file) } }), diff --git a/src/notes.ts b/src/notes.ts index 2020b4f..4d23364 100644 --- a/src/notes.ts +++ b/src/notes.ts @@ -1,7 +1,27 @@ -import { MarkdownView } from 'obsidian' -import type { ResultNote } from './globals' +import { MarkdownView, TFile, type CachedMetadata } from 'obsidian' +import type { IndexedNote, ResultNote } from './globals' import { stringsToRegex } from './utils' +/** + * This is an in-memory cache of the notes, with all their computed fields + * used by the search engine. + * This cache allows us to quickly de-index notes when they are deleted or updated. + */ +export let notesCache: Record = {} + +export function resetNotesCache(): void { + notesCache = {} +} +export function getNoteFromCache(key: string): IndexedNote | undefined { + return notesCache[key] +} +export function addNoteToCache(key: string, note: IndexedNote): void { + notesCache[key] = note +} +export function removeNoteFromCache(key: string): void { + delete notesCache[key] +} + export async function openNote( item: ResultNote, newPane = false, @@ -40,3 +60,23 @@ export async function createNote(name: string): Promise { console.error(e) } } + +/** + * For a given file, returns a list of links leading to notes that don't exist + * @param file + * @param metadata + * @returns + */ +export function getNonExistingNotes( + file: TFile, + metadata: CachedMetadata, +): string[] { + return (metadata.links ?? []) + .map(l => { + const path = l.link.split(/[\^#]+/)[0] // Remove anchors and headings + return app.metadataCache.getFirstLinkpathDest(path, file.path) + ? '' + : l.link + }) + .filter(l => !!l) +} diff --git a/src/search.ts b/src/search.ts index 12e87ca..666761a 100644 --- a/src/search.ts +++ b/src/search.ts @@ -16,9 +16,15 @@ import { } from './utils' import type { Query } from './query' import { settings } from './settings' +import { + removeNoteFromCache, + getNoteFromCache, + getNonExistingNotes, + resetNotesCache, + addNoteToCache, +} from './notes' let minisearchInstance: MiniSearch -let indexedNotes: Record = {} const tokenize = (text: string): string[] => { const tokens = text.split(SPACE_OR_PUNCTUATION) @@ -37,7 +43,7 @@ const tokenize = (text: string): string[] => { * and adds all the notes to the index */ export async function initGlobalSearchIndex(): Promise { - indexedNotes = {} + resetNotesCache() minisearchInstance = new MiniSearch({ tokenize, idField: 'path', @@ -73,9 +79,6 @@ export async function initGlobalSearchIndex(): Promise { }ms`, ) } - - // Listen to the query input to trigger a search - // subscribeToQuery() } /** @@ -115,20 +118,20 @@ async function search(query: Query): Promise { const exactTerms = query.getExactTerms() if (exactTerms.length) { results = results.filter(r => { - const title = indexedNotes[r.id]?.path.toLowerCase() ?? '' + const title = getNoteFromCache(r.id)?.path.toLowerCase() ?? '' const content = stripMarkdownCharacters( - indexedNotes[r.id]?.content ?? '', + getNoteFromCache(r.id)?.content ?? '', ).toLowerCase() return exactTerms.every(q => content.includes(q) || title.includes(q)) }) } - // // If the search query contains exclude terms, filter out results that have them + // If the search query contains exclude terms, filter out results that have them const exclusions = query.exclusions if (exclusions.length) { results = results.filter(r => { const content = stripMarkdownCharacters( - indexedNotes[r.id]?.content ?? '', + getNoteFromCache(r.id)?.content ?? '', ).toLowerCase() return exclusions.every(q => !content.includes(q.value)) }) @@ -145,7 +148,9 @@ async function search(query: Query): Promise { export function getMatches(text: string, reg: RegExp): SearchMatch[] { let match: RegExpExecArray | null = null const matches: SearchMatch[] = [] + let count = 0 // TODO: FIXME: this is a hack to avoid infinite loops while ((match = reg.exec(text)) !== null) { + if (++count > 100) break const m = match[0] if (m) matches.push({ match: m, offset: match.index }) } @@ -181,7 +186,7 @@ export async function getSuggestions( // Map the raw results to get usable suggestions const suggestions = results.map(result => { - const note = indexedNotes[result.id] + const note = getNoteFromCache(result.id) if (!note) { throw new Error(`Note "${result.id}" not indexed`) } @@ -216,11 +221,27 @@ export async function addToIndex(file: TAbstractFile): Promise { if (!(file instanceof TFile) || file.extension !== 'md') { return } + + // Check if the file was already indexed as non-existent, + // and if so, remove it from the index (before adding it again) + if (getNoteFromCache(file.path)?.doesNotExist) { + removeFromIndex(file.path) + } + try { // console.log(`Omnisearch - adding ${file.path} to index`) - const metadata = app.metadataCache.getFileCache(file) - if (indexedNotes[file.path]) { + // Look for links that lead to non-existing files, + // and index them as well + const metadata = app.metadataCache.getFileCache(file) + if (metadata) { + const nonExisting = getNonExistingNotes(file, metadata) + for (const name of nonExisting.filter(o => !getNoteFromCache(o))) { + addNonExistingToIndex(name) + } + } + + if (getNoteFromCache(file.path)) { throw new Error(`${file.basename} is already indexed`) } @@ -245,7 +266,7 @@ export async function addToIndex(file: TAbstractFile): Promise { } minisearchInstance.add(note) - indexedNotes[note.path] = note + addNoteToCache(note.path, note) } catch (e) { console.trace('Error while indexing ' + file.basename) @@ -254,25 +275,42 @@ export async function addToIndex(file: TAbstractFile): Promise { } /** - * Removes a file from the index - * @param file - * @returns + * Index a non-existing note. + * Useful to find internal links that lead (yet) to nowhere + * @param name */ -export function removeFromIndex(file: TAbstractFile): void { - if (file instanceof TFile && file.path.endsWith('.md')) { - // console.log(`Omnisearch - removing ${file.path} from index`) - return removeFromIndexByPath(file.path) - } +export function addNonExistingToIndex(name: string): void { + const filename = name + (name.endsWith('.md') ? '' : '.md') + const note = { + path: filename, + basename: name, + content: '', + aliases: '', + headings1: '', + headings2: '', + headings3: '', + doesNotExist: true, + } as IndexedNote + minisearchInstance.add(note) + addNoteToCache(filename, note) } /** * Removes a file from the index, by its path * @param path */ -export function removeFromIndexByPath(path: string): void { - const note = indexedNotes[path] +export function removeFromIndex(path: string): void { + if (!path.endsWith('.md')) { + console.info(`"${path}" is not a .md file`) + return + } + const note = getNoteFromCache(path) if (note) { + // Delete the original minisearchInstance.remove(note) - delete indexedNotes[path] + removeNoteFromCache(path) + } + else { + console.warn(`not not found under path ${path}`) } } diff --git a/src/vendor/parse-query.ts b/src/vendor/parse-query.ts index 4543b88..281a13b 100644 --- a/src/vendor/parse-query.ts +++ b/src/vendor/parse-query.ts @@ -75,7 +75,9 @@ export function parseQuery( const regex = /(\S+:'(?:[^'\\]|\\.)*')|(\S+:"(?:[^"\\]|\\.)*")|(-?"(?:[^"\\]|\\.)*")|(-?'(?:[^'\\]|\\.)*')|\S+|\S+:\S+/g let match + let count = 0 // TODO: FIXME: this is a hack to avoid infinite loops while ((match = regex.exec(string)) !== null) { + if (++count > 100) break let term = match[0] const sepIndex = term.indexOf(':') From 3faf6b53a0ad25b79549a110176422ae2ffd7702 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Tue, 17 May 2022 22:18:50 +0200 Subject: [PATCH 14/53] 1.3.0-beta --- manifest-beta.json | 2 +- package.json | 2 +- versions.json | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/manifest-beta.json b/manifest-beta.json index e7fd777..bfb6ad8 100644 --- a/manifest-beta.json +++ b/manifest-beta.json @@ -1,7 +1,7 @@ { "id": "omnisearch", "name": "Omnisearch", - "version": "1.2.1", + "version": "1.3.0-beta", "minAppVersion": "0.14.2", "description": "A search engine that just works", "author": "Simon Cambier", diff --git a/package.json b/package.json index f395082..2cab684 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scambier.obsidian-search", - "version": "1.2.1", + "version": "1.3.0-beta", "description": "A search engine for Obsidian", "main": "dist/main.js", "scripts": { diff --git a/versions.json b/versions.json index 4d87ca5..dc8500a 100644 --- a/versions.json +++ b/versions.json @@ -19,5 +19,6 @@ "1.1.0": "0.14.2", "1.1.1": "0.14.2", "1.2.0": "0.14.2", - "1.2.1": "0.14.2" + "1.2.1": "0.14.2", + "1.3.0-beta": "0.14.2" } \ No newline at end of file From 1e3a9d001f05d33aeffb9f93abc46fef7cd78912 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 18 May 2022 17:51:32 +0200 Subject: [PATCH 15/53] Squashed some bugs related to non-existent notes indexing --- src/globals.ts | 1 + src/main.ts | 3 --- src/notes.ts | 14 +++++++++++++- src/search.ts | 15 ++++++++++++--- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/globals.ts b/src/globals.ts index 10b6cd5..7d5531a 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -30,6 +30,7 @@ export type IndexedNote = { headings3: string doesNotExist?: boolean + parent?: string } export type SearchMatch = { diff --git a/src/main.ts b/src/main.ts index e967b5c..9fb4d13 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,5 @@ import { Plugin, TFile } from 'obsidian' import { - addNonExistingToIndex, addToIndex, initGlobalSearchIndex, removeFromIndex, @@ -40,8 +39,6 @@ export default class OmnisearchPlugin extends Plugin { this.registerEvent( this.app.vault.on('delete', file => { removeFromIndex(file.path) - // Re-index the note as non-existing file - addNonExistingToIndex(file.name) }), ) this.registerEvent( diff --git a/src/notes.ts b/src/notes.ts index 4d23364..e131ef5 100644 --- a/src/notes.ts +++ b/src/notes.ts @@ -15,6 +15,9 @@ export function resetNotesCache(): void { export function getNoteFromCache(key: string): IndexedNote | undefined { return notesCache[key] } +export function getNonExistingNotesFromCache(): IndexedNote[] { + return Object.values(notesCache).filter(note => note.doesNotExist) +} export function addNoteToCache(key: string, note: IndexedNote): void { notesCache[key] = note } @@ -73,10 +76,19 @@ export function getNonExistingNotes( ): string[] { return (metadata.links ?? []) .map(l => { - const path = l.link.split(/[\^#]+/)[0] // Remove anchors and headings + const path = removeAnchors(l.link) return app.metadataCache.getFirstLinkpathDest(path, file.path) ? '' : l.link }) .filter(l => !!l) } + +/** + * Removes anchors and headings + * @param name + * @returns + */ +export function removeAnchors(name: string): string { + return name.split(/[\^#]+/)[0] +} diff --git a/src/search.ts b/src/search.ts index 666761a..3a92836 100644 --- a/src/search.ts +++ b/src/search.ts @@ -22,6 +22,8 @@ import { getNonExistingNotes, resetNotesCache, addNoteToCache, + removeAnchors, + getNonExistingNotesFromCache, } from './notes' let minisearchInstance: MiniSearch @@ -237,7 +239,7 @@ export async function addToIndex(file: TAbstractFile): Promise { if (metadata) { const nonExisting = getNonExistingNotes(file, metadata) for (const name of nonExisting.filter(o => !getNoteFromCache(o))) { - addNonExistingToIndex(name) + addNonExistingToIndex(name, file.path) } } @@ -279,7 +281,10 @@ export async function addToIndex(file: TAbstractFile): Promise { * Useful to find internal links that lead (yet) to nowhere * @param name */ -export function addNonExistingToIndex(name: string): void { +export function addNonExistingToIndex(name: string, parent:string): void { + name = removeAnchors(name) + if (getNoteFromCache(name)) return + const filename = name + (name.endsWith('.md') ? '' : '.md') const note = { path: filename, @@ -289,7 +294,9 @@ export function addNonExistingToIndex(name: string): void { headings1: '', headings2: '', headings3: '', + doesNotExist: true, + parent, } as IndexedNote minisearchInstance.add(note) addNoteToCache(filename, note) @@ -306,9 +313,11 @@ export function removeFromIndex(path: string): void { } const note = getNoteFromCache(path) if (note) { - // Delete the original minisearchInstance.remove(note) removeNoteFromCache(path) + getNonExistingNotesFromCache().filter(n => n.parent === path).forEach(n => { + removeFromIndex(n.path) + }) } else { console.warn(`not not found under path ${path}`) From f4b4b806ee6d7b36f7d206cae748e251c46e29ab Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 18 May 2022 17:53:20 +0200 Subject: [PATCH 16/53] 1.3.1-beta --- manifest-beta.json | 2 +- package.json | 2 +- versions.json | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/manifest-beta.json b/manifest-beta.json index bfb6ad8..cc7b0e3 100644 --- a/manifest-beta.json +++ b/manifest-beta.json @@ -1,7 +1,7 @@ { "id": "omnisearch", "name": "Omnisearch", - "version": "1.3.0-beta", + "version": "1.3.1-beta", "minAppVersion": "0.14.2", "description": "A search engine that just works", "author": "Simon Cambier", diff --git a/package.json b/package.json index 2cab684..d8df938 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scambier.obsidian-search", - "version": "1.3.0-beta", + "version": "1.3.1-beta", "description": "A search engine for Obsidian", "main": "dist/main.js", "scripts": { diff --git a/versions.json b/versions.json index dc8500a..ac25311 100644 --- a/versions.json +++ b/versions.json @@ -20,5 +20,6 @@ "1.1.1": "0.14.2", "1.2.0": "0.14.2", "1.2.1": "0.14.2", - "1.3.0-beta": "0.14.2" + "1.3.0-beta": "0.14.2", + "1.3.1-beta": "0.14.2" } \ No newline at end of file From eb32b0af24181fe63fa3adaadeb8a6efbe8978ca Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Sat, 21 May 2022 18:59:15 +0200 Subject: [PATCH 17/53] Fixed #52 --- src/components/ModalVault.svelte | 10 ++++++++-- src/notes.ts | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/ModalVault.svelte b/src/components/ModalVault.svelte index fe11acb..e92c8ac 100644 --- a/src/components/ModalVault.svelte +++ b/src/components/ModalVault.svelte @@ -3,7 +3,7 @@ let lastSearch = "" - {@html note.basename.replace(reg, highlighter)} + {@html title.replace(reg, highlighter)} {#if matches.length > 0} diff --git a/src/search.ts b/src/search.ts index ea14ee6..74bcd37 100644 --- a/src/search.ts +++ b/src/search.ts @@ -252,7 +252,7 @@ export async function addToIndex(file: TAbstractFile): Promise { // Make the document and index it const note: IndexedNote = { - basename: file.path, + basename: file.basename, content, path: file.path, aliases: getAliasesFromMetadata(metadata).join(''), diff --git a/src/settings.ts b/src/settings.ts index eceb548..417b0e7 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -9,9 +9,10 @@ interface WeightingSettings { } export interface OmnisearchSettings extends WeightingSettings { - showIndexingNotices: boolean respectExcluded: boolean reindexInRealTime: boolean + showIndexingNotices: boolean + showShortName: boolean CtrlJK: boolean CtrlNP: boolean } @@ -28,19 +29,31 @@ export class SettingsTab extends PluginSettingTab { const { containerEl } = this containerEl.empty() - // Title + // Settings main title containerEl.createEl('h2', { text: 'Omnisearch settings' }) - // Show notices - new Setting(containerEl) - .setName('Show indexing notices') - .setDesc('Show a notice when indexing is done, usually at startup.') - .addToggle(toggle => - toggle.setValue(settings.showIndexingNotices).onChange(async v => { - settings.showIndexingNotices = v - await saveSettings(this.plugin) - }), - ) + // #region Behavior + + new Setting(containerEl).setName('Behavior').setHeading() + + // Index in real-time, desktop only + if (require('electron')) { + new Setting(containerEl) + .setName('Reindex in real-time') + .setDesc( + "By default, notes a reindexed when Obsidian focus is lost. Enable this to reindex in real-time. May affect Obsidian's performances when editing large notes.", + ) + .addToggle(toggle => + toggle.setValue(settings.reindexInRealTime).onChange(async v => { + settings.reindexInRealTime = v + await saveSettings(this.plugin) + }), + ) + } + else { + // No real time indexing on mobile + settings.reindexInRealTime = false + } // Respect excluded files new Setting(containerEl) @@ -55,24 +68,37 @@ export class SettingsTab extends PluginSettingTab { }), ) - // Index in real-time, desktop only - if (require('electron')) { - new Setting(containerEl) - .setName('Reindex in real-time') - .setDesc( - 'By default, notes a reindexed when Obsidian focus is lost. Enable this to reindex in real-time. May affect performances.', - ) - .addToggle(toggle => - toggle.setValue(settings.reindexInRealTime).onChange(async v => { - settings.reindexInRealTime = v - await saveSettings(this.plugin) - }), - ) - } - else { - // No real time indexing on mobile - settings.reindexInRealTime = false - } + // #endregion Behavior + + // #region User Interface + + new Setting(containerEl).setName('User Interface').setHeading() + + // Show notices + new Setting(containerEl) + .setName('Show indexing notices') + .setDesc('Show a notice when indexing is done, usually at startup.') + .addToggle(toggle => + toggle.setValue(settings.showIndexingNotices).onChange(async v => { + settings.showIndexingNotices = v + await saveSettings(this.plugin) + }), + ) + + // Display note names without the full path + new Setting(containerEl) + .setName('Hide full path in results list') + .setDesc( + 'In the search results, only show the note name, without the full path.', + ) + .addToggle(toggle => + toggle.setValue(settings.showShortName).onChange(async v => { + settings.showShortName = v + await saveSettings(this.plugin) + }), + ) + + // #endregion User Interface // #region Results Weighting @@ -135,10 +161,12 @@ export class SettingsTab extends PluginSettingTab { } export const DEFAULT_SETTINGS: OmnisearchSettings = { - showIndexingNotices: false, respectExcluded: true, reindexInRealTime: false, + showIndexingNotices: false, + showShortName: false, + weightBasename: 2, weightH1: 1.5, weightH2: 1.3, From c92cce03f7530651a05afc008312b671ace78c19 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Sat, 4 Jun 2022 09:30:51 +0200 Subject: [PATCH 35/53] Update CHANGELOG.md --- CHANGELOG.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 894b317..c580562 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,28 @@ # Omnisearch Changelog -## 1.2.0, 1.2.1 +## 1.3.x + +### New + +* Chinese support by @aidenlx in https://github.com/scambier/obsidian-omnisearch/pull/37 + * You need to install https://github.com/aidenlx/cm-chs-patch to enable this feature +* Settings page https://github.com/scambier/obsidian-omnisearch/issues/41 +* Do not show indexing Notice by default by @chrisgrieser in https://github.com/scambier/obsidian-omnisearch/pull/46 +* Include notes that don't exist https://github.com/scambier/obsidian-omnisearch/issues/14 + +### Improved + +* Better accessibility https://github.com/scambier/obsidian-omnisearch/issues/50 +* Note aliases are now scored as high as the filename in search results https://github.com/scambier/obsidian-omnisearch/issues/34 +* By default, reindexing is now done when the app is out of focus, and not after each save https://github.com/scambier/obsidian-omnisearch/issues/57 + * On mobile, indexing is only done at startup + +### Fixed + +* Showing an error when a note can't be created https://github.com/scambier/obsidian-omnisearch/issues/52 + + +## 1.2.x ### New * #42 Files that are present in Obsidian's "Excluded Files" list are downranked by a factor of 3 (_desktop only_) From d672403d3d4e2df9e1f1c10391a128caca680069 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Sat, 4 Jun 2022 18:19:34 +0200 Subject: [PATCH 36/53] #26 - Only if Vim mode is enabled --- src/modals.ts | 4 ++-- src/settings.ts | 4 ++-- src/types.d.ts | 6 +++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/modals.ts b/src/modals.ts index 768a49e..77cc04f 100644 --- a/src/modals.ts +++ b/src/modals.ts @@ -37,7 +37,7 @@ abstract class OmnisearchModal extends Modal { ] as const) { for (const modifier of ['Ctrl', 'Meta'] as const) { this.scope.register([modifier], key.k, e => { - if (settings.CtrlJK) { + if (settings.CtrlJK && this.app.vault.getConfig('vimMode')) { e.preventDefault() eventBus.emit('arrow-' + key.dir) } @@ -52,7 +52,7 @@ abstract class OmnisearchModal extends Modal { ] as const) { for (const modifier of ['Ctrl', 'Meta'] as const) { this.scope.register([modifier], key.k, e => { - if (settings.CtrlNP) { + if (settings.CtrlNP && this.app.vault.getConfig('vimMode')) { e.preventDefault() eventBus.emit('arrow-' + key.dir) } diff --git a/src/settings.ts b/src/settings.ts index 417b0e7..5c5a836 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -129,7 +129,7 @@ export class SettingsTab extends PluginSettingTab { new Setting(containerEl).setName('Shortcuts').setHeading() new Setting(containerEl) - .setName('Use [Ctrl/Cmd]+j/k to navigate up/down in the results') + .setName('Use [Ctrl/Cmd]+j/k to navigate up/down in the results, if Vim mode is enabled') .addToggle(toggle => toggle.setValue(settings.CtrlJK).onChange(async v => { settings.CtrlJK = v @@ -138,7 +138,7 @@ export class SettingsTab extends PluginSettingTab { ) new Setting(containerEl) - .setName('Use [Ctrl/Cmd]+n/p to navigate up/down in the results') + .setName('Use [Ctrl/Cmd]+n/p to navigate up/down in the results, if Vim mode is enabled') .addToggle(toggle => toggle.setValue(settings.CtrlNP).onChange(async v => { settings.CtrlNP = v diff --git a/src/types.d.ts b/src/types.d.ts index ad8686a..ff21c9a 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -1,4 +1,4 @@ -import type { MetadataCache, ViewState } from 'obsidian' +import type { MetadataCache, ViewState, Vault } from 'obsidian' declare module 'obsidian' { interface MetadataCache { @@ -14,4 +14,8 @@ declare module 'obsidian' { file?: string } } + + interface Vault { + getConfig(string): unknown + } } From 7cd4f6c502319e31b8e54447ea9716b0b9d03f24 Mon Sep 17 00:00:00 2001 From: Michael Naumov Date: Mon, 6 Jun 2022 00:42:29 -0600 Subject: [PATCH 37/53] Save/load index to files, improve logging --- src/globals.ts | 4 ++- src/notes.ts | 31 +++++++++++++++++++ src/search.ts | 81 +++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 101 insertions(+), 15 deletions(-) diff --git a/src/globals.ts b/src/globals.ts index 7d5531a..b51ad3e 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -22,7 +22,9 @@ export type SearchNote = { export type IndexedNote = { path: string - basename: string + basename: string, + mtime: number, + content: string aliases: string headings1: string diff --git a/src/notes.ts b/src/notes.ts index e37466d..4bebb2c 100644 --- a/src/notes.ts +++ b/src/notes.ts @@ -14,9 +14,29 @@ import { stringsToRegex } from './utils' */ export let notesCache: Record = {} +const notesCacheFilePath = `${app.vault.configDir}/plugins/omnisearch/notesCache.json` + export function resetNotesCache(): void { notesCache = {} } + +export async function loadNotesCache(): Promise { + if (await app.vault.adapter.exists(notesCacheFilePath)) { + try { + const json = await app.vault.adapter.read(notesCacheFilePath) + notesCache = JSON.parse(json) + console.log("Notes cache loaded from the file") + } + catch(e) { + console.trace("Could not load Notes cache from the file") + console.error(e) + } + } + + if (!notesCache) { + notesCache = {} + } +} export function getNoteFromCache(key: string): IndexedNote | undefined { return notesCache[key] } @@ -117,3 +137,14 @@ export function getNonExistingNotes( export function removeAnchors(name: string): string { return name.split(/[\^#]+/)[0] } + +export async function saveNotesCacheToFile(): Promise { + const json = JSON.stringify(notesCache) + await app.vault.adapter.write(notesCacheFilePath, json) + console.log("Notes cache saved to the file") +} + +export function isCacheOutdated(file: TFile): boolean { + const indexedNote = getNoteFromCache(file.path) + return !indexedNote || indexedNote.mtime !== file.stat.mtime +} \ No newline at end of file diff --git a/src/search.ts b/src/search.ts index 74bcd37..f9ee16f 100644 --- a/src/search.ts +++ b/src/search.ts @@ -24,9 +24,14 @@ import { addNoteToCache, removeAnchors, getNonExistingNotesFromCache, + loadNotesCache, + saveNotesCacheToFile, + isCacheOutdated } from './notes' let minisearchInstance: MiniSearch +let isIndexChanged: boolean +const searchIndexFilePath = `${app.vault.configDir}/plugins/omnisearch/searchIndex.json` const tokenize = (text: string): string[] => { const tokens = text.split(SPACE_OR_PUNCTUATION) @@ -45,8 +50,7 @@ const tokenize = (text: string): string[] => { * and adds all the notes to the index */ export async function initGlobalSearchIndex(): Promise { - resetNotesCache() - minisearchInstance = new MiniSearch({ + const options = { tokenize, idField: 'path', fields: [ @@ -57,29 +61,58 @@ export async function initGlobalSearchIndex(): Promise { 'headings2', 'headings3', ], - }) + } + + if (await app.vault.adapter.exists(searchIndexFilePath)) { + try { + const json = await app.vault.adapter.read(searchIndexFilePath) + minisearchInstance = MiniSearch.loadJSON(json, options) + console.log("MiniSearch index loaded from the file") + } + catch(e) { + console.trace("Could not load MiniSearch index from the file") + console.error(e) + } + } + + if (!minisearchInstance) { + minisearchInstance = new MiniSearch(options) + resetNotesCache() + } + + await loadNotesCache() // Index files that are already present const start = new Date().getTime() - const files = app.vault.getMarkdownFiles() + const files = app.vault.getMarkdownFiles().filter(file => isCacheOutdated(file)) // This is basically the same behavior as MiniSearch's `addAllAsync()`. // We index files by batches of 10 - if (files.length) { - console.log('Omnisearch - indexing ' + files.length + ' files') - } + console.log('Omnisearch - indexing ' + files.length + ' modified notes') + for (let i = 0; i < files.length; ++i) { if (i % 10 === 0) await wait(0) const file = files[i] - if (file) await addToIndex(file) + if (file) { + if (getNoteFromCache(file.path)) { + removeFromIndex(file.path) + } + await addToIndex(file) + } } - if (files.length > 0 && settings.showIndexingNotices) { - new Notice( - `Omnisearch - Indexed ${files.length} notes in ${ - new Date().getTime() - start - }ms`, - ) + if (files.length > 0) { + const message = `Omnisearch - Indexed ${files.length} modified notes in ${ + new Date().getTime() - start + }ms` + + console.log(message) + + if (settings.showIndexingNotices) { + new Notice(message) + } + + await saveIndexToFile() } } @@ -255,6 +288,8 @@ export async function addToIndex(file: TAbstractFile): Promise { basename: file.basename, content, path: file.path, + mtime: file.stat.mtime, + aliases: getAliasesFromMetadata(metadata).join(''), headings1: metadata ? extractHeadingsFromCache(metadata, 1).join(' ') @@ -268,6 +303,7 @@ export async function addToIndex(file: TAbstractFile): Promise { } minisearchInstance.add(note) + isIndexChanged = true addNoteToCache(note.path, note) } catch (e) { @@ -289,6 +325,8 @@ export function addNonExistingToIndex(name: string, parent: string): void { const note = { path: filename, basename: name, + mtime: 0, + content: '', aliases: '', headings1: '', @@ -299,6 +337,7 @@ export function addNonExistingToIndex(name: string, parent: string): void { parent, } as IndexedNote minisearchInstance.add(note) + isIndexChanged = true addNoteToCache(filename, note) } @@ -314,6 +353,7 @@ export function removeFromIndex(path: string): void { const note = getNoteFromCache(path) if (note) { minisearchInstance.remove(note) + isIndexChanged = true removeNoteFromCache(path) getNonExistingNotesFromCache() .filter(n => n.parent === path) @@ -336,4 +376,17 @@ export async function reindexNotes(): Promise { await addToIndex(note) } notesToReindex.clear() + + await saveIndexToFile() } + +async function saveIndexToFile(): Promise { + if (minisearchInstance && isIndexChanged) { + const json = JSON.stringify(minisearchInstance) + await app.vault.adapter.write(searchIndexFilePath, json) + console.log("MiniSearch index saved to the file") + + await saveNotesCacheToFile() + isIndexChanged = false + } +} \ No newline at end of file From 9b1123dee8a84147dadf7bd9aa5afa5a4359b5cf Mon Sep 17 00:00:00 2001 From: Michael Naumov Date: Mon, 6 Jun 2022 08:12:51 -0600 Subject: [PATCH 38/53] Add storeIndexInFile setting --- src/notes.ts | 3 ++- src/search.ts | 30 ++++++++++++++++++++---------- src/settings.ts | 12 ++++++++++++ 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/notes.ts b/src/notes.ts index 4bebb2c..9bceaff 100644 --- a/src/notes.ts +++ b/src/notes.ts @@ -6,6 +6,7 @@ import { } from 'obsidian' import type { IndexedNote, ResultNote } from './globals' import { stringsToRegex } from './utils' +import { settings } from './settings' /** * This is an in-memory cache of the notes, with all their computed fields @@ -21,7 +22,7 @@ export function resetNotesCache(): void { } export async function loadNotesCache(): Promise { - if (await app.vault.adapter.exists(notesCacheFilePath)) { + if (settings.storeIndexInFile && await app.vault.adapter.exists(notesCacheFilePath)) { try { const json = await app.vault.adapter.read(notesCacheFilePath) notesCache = JSON.parse(json) diff --git a/src/search.ts b/src/search.ts index f9ee16f..8653a1c 100644 --- a/src/search.ts +++ b/src/search.ts @@ -63,11 +63,12 @@ export async function initGlobalSearchIndex(): Promise { ], } - if (await app.vault.adapter.exists(searchIndexFilePath)) { + if (settings.storeIndexInFile && await app.vault.adapter.exists(searchIndexFilePath)) { try { const json = await app.vault.adapter.read(searchIndexFilePath) minisearchInstance = MiniSearch.loadJSON(json, options) console.log("MiniSearch index loaded from the file") + await loadNotesCache() } catch(e) { console.trace("Could not load MiniSearch index from the file") @@ -80,16 +81,25 @@ export async function initGlobalSearchIndex(): Promise { resetNotesCache() } - await loadNotesCache() - // Index files that are already present const start = new Date().getTime() - const files = app.vault.getMarkdownFiles().filter(file => isCacheOutdated(file)) + + const allFiles = app.vault.getMarkdownFiles() + + let files + let notesSuffix + if (settings.storeIndexInFile) { + files = allFiles.filter(file => isCacheOutdated(file)) + notesSuffix = 'modified notes' + } else { + files = allFiles + notesSuffix = 'notes' + } + + console.log(`Omnisearch - indexing ${files.length} ${notesSuffix}`) // This is basically the same behavior as MiniSearch's `addAllAsync()`. // We index files by batches of 10 - console.log('Omnisearch - indexing ' + files.length + ' modified notes') - for (let i = 0; i < files.length; ++i) { if (i % 10 === 0) await wait(0) const file = files[i] @@ -102,9 +112,9 @@ export async function initGlobalSearchIndex(): Promise { } if (files.length > 0) { - const message = `Omnisearch - Indexed ${files.length} modified notes in ${ - new Date().getTime() - start - }ms` + const message = `Omnisearch - Indexed ${files.length} ${notesSuffix} in ${ + new Date().getTime() - start + }ms` console.log(message) @@ -381,7 +391,7 @@ export async function reindexNotes(): Promise { } async function saveIndexToFile(): Promise { - if (minisearchInstance && isIndexChanged) { + if (settings.storeIndexInFile && minisearchInstance && isIndexChanged) { const json = JSON.stringify(minisearchInstance) await app.vault.adapter.write(searchIndexFilePath, json) console.log("MiniSearch index saved to the file") diff --git a/src/settings.ts b/src/settings.ts index 5c5a836..45ce43a 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -15,6 +15,7 @@ export interface OmnisearchSettings extends WeightingSettings { showShortName: boolean CtrlJK: boolean CtrlNP: boolean + storeIndexInFile: boolean } export class SettingsTab extends PluginSettingTab { @@ -68,6 +69,15 @@ export class SettingsTab extends PluginSettingTab { }), ) + new Setting(containerEl) + .setName('Store index in file') + .addToggle(toggle => + toggle.setValue(settings.storeIndexInFile).onChange(async v => { + settings.storeIndexInFile = v + await saveSettings(this.plugin) + }), + ) + // #endregion Behavior // #region User Interface @@ -174,6 +184,8 @@ export const DEFAULT_SETTINGS: OmnisearchSettings = { CtrlJK: false, CtrlNP: false, + + storeIndexInFile: false } as const export let settings: OmnisearchSettings = Object.assign({}, DEFAULT_SETTINGS) From ff38f8258bf2a2988049ba7dbaf286c21f66eb44 Mon Sep 17 00:00:00 2001 From: Michael Naumov Date: Mon, 6 Jun 2022 08:16:24 -0600 Subject: [PATCH 39/53] Use singe quotes consistently --- src/notes.ts | 6 +++--- src/search.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/notes.ts b/src/notes.ts index 9bceaff..a21bbab 100644 --- a/src/notes.ts +++ b/src/notes.ts @@ -26,10 +26,10 @@ export async function loadNotesCache(): Promise { try { const json = await app.vault.adapter.read(notesCacheFilePath) notesCache = JSON.parse(json) - console.log("Notes cache loaded from the file") + console.log('Notes cache loaded from the file') } catch(e) { - console.trace("Could not load Notes cache from the file") + console.trace('Could not load Notes cache from the file') console.error(e) } } @@ -142,7 +142,7 @@ export function removeAnchors(name: string): string { export async function saveNotesCacheToFile(): Promise { const json = JSON.stringify(notesCache) await app.vault.adapter.write(notesCacheFilePath, json) - console.log("Notes cache saved to the file") + console.log('Notes cache saved to the file') } export function isCacheOutdated(file: TFile): boolean { diff --git a/src/search.ts b/src/search.ts index 8653a1c..5e9acd2 100644 --- a/src/search.ts +++ b/src/search.ts @@ -67,11 +67,11 @@ export async function initGlobalSearchIndex(): Promise { try { const json = await app.vault.adapter.read(searchIndexFilePath) minisearchInstance = MiniSearch.loadJSON(json, options) - console.log("MiniSearch index loaded from the file") + console.log('MiniSearch index loaded from the file') await loadNotesCache() } catch(e) { - console.trace("Could not load MiniSearch index from the file") + console.trace('Could not load MiniSearch index from the file') console.error(e) } } @@ -394,7 +394,7 @@ async function saveIndexToFile(): Promise { if (settings.storeIndexInFile && minisearchInstance && isIndexChanged) { const json = JSON.stringify(minisearchInstance) await app.vault.adapter.write(searchIndexFilePath, json) - console.log("MiniSearch index saved to the file") + console.log('MiniSearch index saved to the file') await saveNotesCacheToFile() isIndexChanged = false From 0c031c6defa7b8312b76b7416477031084a80e7b Mon Sep 17 00:00:00 2001 From: Michael Naumov Date: Mon, 6 Jun 2022 08:19:49 -0600 Subject: [PATCH 40/53] Remove trailing commas --- src/globals.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/globals.ts b/src/globals.ts index b51ad3e..572729b 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -22,8 +22,8 @@ export type SearchNote = { export type IndexedNote = { path: string - basename: string, - mtime: number, + basename: string + mtime: number content: string aliases: string From f0e4eeaf054ddbd4407c24b7f2f93f49d522d8a9 Mon Sep 17 00:00:00 2001 From: Michael Naumov Date: Mon, 6 Jun 2022 11:02:32 -0600 Subject: [PATCH 41/53] Add trailing newline --- src/notes.ts | 2 +- src/search.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/notes.ts b/src/notes.ts index a21bbab..6713730 100644 --- a/src/notes.ts +++ b/src/notes.ts @@ -148,4 +148,4 @@ export async function saveNotesCacheToFile(): Promise { export function isCacheOutdated(file: TFile): boolean { const indexedNote = getNoteFromCache(file.path) return !indexedNote || indexedNote.mtime !== file.stat.mtime -} \ No newline at end of file +} diff --git a/src/search.ts b/src/search.ts index 5e9acd2..8111e94 100644 --- a/src/search.ts +++ b/src/search.ts @@ -399,4 +399,4 @@ async function saveIndexToFile(): Promise { await saveNotesCacheToFile() isIndexChanged = false } -} \ No newline at end of file +} From ca808502eb3fb016854a29a15928d2c085f66772 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Sat, 4 Jun 2022 18:59:19 +0200 Subject: [PATCH 42/53] #53 - Ignoring diacritics --- src/search.ts | 3 +++ src/settings.ts | 23 +++++++++++++++++++++-- src/utils.ts | 7 +++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/search.ts b/src/search.ts index 74bcd37..30736ea 100644 --- a/src/search.ts +++ b/src/search.ts @@ -10,6 +10,7 @@ import { import { extractHeadingsFromCache, getAliasesFromMetadata, + removeDiacritics, stringsToRegex, stripMarkdownCharacters, wait, @@ -48,6 +49,8 @@ export async function initGlobalSearchIndex(): Promise { resetNotesCache() minisearchInstance = new MiniSearch({ tokenize, + processTerm: term => + settings.ignoreDiacritics ? removeDiacritics(term) : term, idField: 'path', fields: [ 'basename', diff --git a/src/settings.ts b/src/settings.ts index 5c5a836..c284629 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -11,6 +11,7 @@ interface WeightingSettings { export interface OmnisearchSettings extends WeightingSettings { respectExcluded: boolean reindexInRealTime: boolean + ignoreDiacritics: boolean showIndexingNotices: boolean showShortName: boolean CtrlJK: boolean @@ -68,6 +69,19 @@ export class SettingsTab extends PluginSettingTab { }), ) + // Ignore diacritics + // new Setting(containerEl) + // .setName('Ignore diacritics') + // .setDesc( + // 'Normalize diacritics in search terms. Words like "brûlée" or "žluťoučký" will be indexed as "brulee" and "zlutoucky". Needs a restart to take effect.', + // ) + // .addToggle(toggle => + // toggle.setValue(settings.ignoreDiacritics).onChange(async v => { + // settings.ignoreDiacritics = v + // await saveSettings(this.plugin) + // }), + // ) + // #endregion Behavior // #region User Interface @@ -129,7 +143,9 @@ export class SettingsTab extends PluginSettingTab { new Setting(containerEl).setName('Shortcuts').setHeading() new Setting(containerEl) - .setName('Use [Ctrl/Cmd]+j/k to navigate up/down in the results, if Vim mode is enabled') + .setName( + 'Use [Ctrl/Cmd]+j/k to navigate up/down in the results, if Vim mode is enabled', + ) .addToggle(toggle => toggle.setValue(settings.CtrlJK).onChange(async v => { settings.CtrlJK = v @@ -138,7 +154,9 @@ export class SettingsTab extends PluginSettingTab { ) new Setting(containerEl) - .setName('Use [Ctrl/Cmd]+n/p to navigate up/down in the results, if Vim mode is enabled') + .setName( + 'Use [Ctrl/Cmd]+n/p to navigate up/down in the results, if Vim mode is enabled', + ) .addToggle(toggle => toggle.setValue(settings.CtrlNP).onChange(async v => { settings.CtrlNP = v @@ -163,6 +181,7 @@ export class SettingsTab extends PluginSettingTab { export const DEFAULT_SETTINGS: OmnisearchSettings = { respectExcluded: true, reindexInRealTime: false, + ignoreDiacritics: true, showIndexingNotices: false, showShortName: false, diff --git a/src/utils.ts b/src/utils.ts index 5b7c742..3b1748c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -143,3 +143,10 @@ export function getAliasesFromMetadata( .map(s => (s ? s.trim() : s)) .filter(s => !!s) } + +/** + * https://stackoverflow.com/a/37511463 + */ +export function removeDiacritics(str: string): string { + return str.normalize('NFD').replace(/\p{Diacritic}/gu, '') +} From 7b741fa3576fc6034a2cca8179b5c585abf0e895 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Tue, 7 Jun 2022 12:38:46 +0200 Subject: [PATCH 43/53] #53 - also remove diacritics from the cache --- src/search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.ts b/src/search.ts index 30736ea..637a3d7 100644 --- a/src/search.ts +++ b/src/search.ts @@ -251,7 +251,7 @@ export async function addToIndex(file: TAbstractFile): Promise { } // Fetch content from the cache to index it as-is - const content = await app.vault.cachedRead(file) + const content = removeDiacritics(await app.vault.cachedRead(file)) // Make the document and index it const note: IndexedNote = { From 8f954a3cda496fae12ec3ba3c6946196ab559928 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 8 Jun 2022 21:54:27 +0200 Subject: [PATCH 44/53] #53 - Fixed some highlighting issues --- src/notes.ts | 9 ++++++--- src/query.ts | 6 +++--- src/search.ts | 20 ++++++++++++-------- src/settings.ts | 24 ++++++++++++------------ 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/notes.ts b/src/notes.ts index 6713730..957cdbf 100644 --- a/src/notes.ts +++ b/src/notes.ts @@ -22,16 +22,19 @@ export function resetNotesCache(): void { } export async function loadNotesCache(): Promise { - if (settings.storeIndexInFile && await app.vault.adapter.exists(notesCacheFilePath)) { + if ( + settings.storeIndexInFile && + (await app.vault.adapter.exists(notesCacheFilePath)) + ) { try { const json = await app.vault.adapter.read(notesCacheFilePath) notesCache = JSON.parse(json) console.log('Notes cache loaded from the file') } - catch(e) { + catch (e) { console.trace('Could not load Notes cache from the file') console.error(e) - } + } } if (!notesCache) { diff --git a/src/query.ts b/src/query.ts index e6d0f5b..1bb8d2a 100644 --- a/src/query.ts +++ b/src/query.ts @@ -1,4 +1,5 @@ -import { stripSurroundingQuotes } from './utils' +import { settings } from './settings' +import { removeDiacritics, stripSurroundingQuotes } from './utils' import { parseQuery } from './vendor/parse-query' type QueryToken = { @@ -21,6 +22,7 @@ export class Query { public exclusions: QueryToken[] = [] constructor(text = '') { + if (settings.ignoreDiacritics) text = removeDiacritics(text) const tokens = parseQuery(text.toLowerCase(), { tokenize: true }) this.exclusions = tokens.exclude.text .map(this.formatToken) @@ -48,5 +50,3 @@ export class Query { } } } - - diff --git a/src/search.ts b/src/search.ts index 0b2c8ab..461b6ac 100644 --- a/src/search.ts +++ b/src/search.ts @@ -27,7 +27,7 @@ import { getNonExistingNotesFromCache, loadNotesCache, saveNotesCacheToFile, - isCacheOutdated + isCacheOutdated, } from './notes' let minisearchInstance: MiniSearch @@ -53,7 +53,7 @@ const tokenize = (text: string): string[] => { export async function initGlobalSearchIndex(): Promise { const options = { tokenize, - processTerm: term => + processTerm: (term: string) => settings.ignoreDiacritics ? removeDiacritics(term) : term, idField: 'path', fields: [ @@ -66,19 +66,22 @@ export async function initGlobalSearchIndex(): Promise { ], } - if (settings.storeIndexInFile && await app.vault.adapter.exists(searchIndexFilePath)) { + if ( + settings.storeIndexInFile && + (await app.vault.adapter.exists(searchIndexFilePath)) + ) { try { const json = await app.vault.adapter.read(searchIndexFilePath) minisearchInstance = MiniSearch.loadJSON(json, options) console.log('MiniSearch index loaded from the file') await loadNotesCache() } - catch(e) { + catch (e) { console.trace('Could not load MiniSearch index from the file') console.error(e) } } - + if (!minisearchInstance) { minisearchInstance = new MiniSearch(options) resetNotesCache() @@ -94,7 +97,8 @@ export async function initGlobalSearchIndex(): Promise { if (settings.storeIndexInFile) { files = allFiles.filter(file => isCacheOutdated(file)) notesSuffix = 'modified notes' - } else { + } + else { files = allFiles notesSuffix = 'notes' } @@ -116,8 +120,8 @@ export async function initGlobalSearchIndex(): Promise { if (files.length > 0) { const message = `Omnisearch - Indexed ${files.length} ${notesSuffix} in ${ - new Date().getTime() - start - }ms` + new Date().getTime() - start + }ms` console.log(message) diff --git a/src/settings.ts b/src/settings.ts index 5e3d369..45f7892 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -71,17 +71,17 @@ export class SettingsTab extends PluginSettingTab { ) // Ignore diacritics - // new Setting(containerEl) - // .setName('Ignore diacritics') - // .setDesc( - // 'Normalize diacritics in search terms. Words like "brûlée" or "žluťoučký" will be indexed as "brulee" and "zlutoucky". Needs a restart to take effect.', - // ) - // .addToggle(toggle => - // toggle.setValue(settings.ignoreDiacritics).onChange(async v => { - // settings.ignoreDiacritics = v - // await saveSettings(this.plugin) - // }), - // ) + new Setting(containerEl) + .setName('Ignore diacritics') + .setDesc( + 'EXPERIMENTAL - Normalize diacritics in search terms. Words like "brûlée" or "žluťoučký" will be indexed as "brulee" and "zlutoucky". Needs a restart to take effect.', + ) + .addToggle(toggle => + toggle.setValue(settings.ignoreDiacritics).onChange(async v => { + settings.ignoreDiacritics = v + await saveSettings(this.plugin) + }), + ) new Setting(containerEl) .setName('Store index in file') @@ -194,7 +194,7 @@ export class SettingsTab extends PluginSettingTab { export const DEFAULT_SETTINGS: OmnisearchSettings = { respectExcluded: true, reindexInRealTime: false, - ignoreDiacritics: true, + ignoreDiacritics: false, showIndexingNotices: false, showShortName: false, From 81d5b52a9cd7948e55b85a53cddc45e250059b74 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Wed, 8 Jun 2022 22:43:09 +0200 Subject: [PATCH 45/53] 1.3.5-beta1 --- manifest-beta.json | 2 +- package.json | 2 +- versions.json | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/manifest-beta.json b/manifest-beta.json index 10e672b..ef81511 100644 --- a/manifest-beta.json +++ b/manifest-beta.json @@ -1,7 +1,7 @@ { "id": "omnisearch", "name": "Omnisearch", - "version": "1.3.4", + "version": "1.3.5-beta1", "minAppVersion": "0.14.2", "description": "A search engine that just works", "author": "Simon Cambier", diff --git a/package.json b/package.json index bd40c5d..3529b77 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scambier.obsidian-search", - "version": "1.3.4", + "version": "1.3.5-beta1", "description": "A search engine for Obsidian", "main": "dist/main.js", "scripts": { diff --git a/versions.json b/versions.json index 84724ea..5f492ee 100644 --- a/versions.json +++ b/versions.json @@ -25,5 +25,6 @@ "1.3.2-beta": "0.14.2", "1.3.3-beta": "0.14.2", "1.3.3": "0.14.2", - "1.3.4": "0.14.2" + "1.3.4": "0.14.2", + "1.3.5-beta1": "0.14.2" } \ No newline at end of file From 1bd9e4254815435aab6e93c52eab6436bdeae6f2 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Mon, 13 Jun 2022 13:44:22 +0200 Subject: [PATCH 46/53] Update manifest-beta.json --- manifest-beta.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manifest-beta.json b/manifest-beta.json index ef81511..1ab6c30 100644 --- a/manifest-beta.json +++ b/manifest-beta.json @@ -1,10 +1,10 @@ { "id": "omnisearch", "name": "Omnisearch", - "version": "1.3.5-beta1", + "version": "1.3.4", "minAppVersion": "0.14.2", "description": "A search engine that just works", "author": "Simon Cambier", "authorUrl": "https://github.com/scambier/obsidian-omnisearch", "isDesktopOnly": false -} \ No newline at end of file +} From ac97a9c25a70a67fe55facf6cd8f9d7934e52b73 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Mon, 13 Jun 2022 13:47:55 +0200 Subject: [PATCH 47/53] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 18e9189..796936a 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Under the hood, it uses the excellent [MiniSearch](https://github.com/lucaong/mi ## Installation - Omnisearch is available on [the official Community Plugins repository](https://obsidian.md/plugins?search=Omnisearch). -- Beta releases can be installed through [BRAT](https://github.com/TfTHacker/obsidian42-brat). Be advised that those versions can be buggy. +- Beta releases can be installed through [BRAT](https://github.com/TfTHacker/obsidian42-brat). **Be advised that those versions can be buggy.** You can check the [CHANGELOG](./CHANGELOG.md) for more information on the different versions. From c0d2ab408223a22a255227edfad8a4b014fde5b8 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Mon, 13 Jun 2022 18:52:48 +0200 Subject: [PATCH 48/53] Fixed #66 - words with uppercase chars were not indexed/searched properly --- src/search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.ts b/src/search.ts index 461b6ac..a85403d 100644 --- a/src/search.ts +++ b/src/search.ts @@ -54,7 +54,7 @@ export async function initGlobalSearchIndex(): Promise { const options = { tokenize, processTerm: (term: string) => - settings.ignoreDiacritics ? removeDiacritics(term) : term, + (settings.ignoreDiacritics ? removeDiacritics(term) : term).toLowerCase(), idField: 'path', fields: [ 'basename', From f5d1cbe9327b05d8c733880595801707dc7440f5 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Mon, 13 Jun 2022 18:53:25 +0200 Subject: [PATCH 49/53] 1.3.5-beta2 --- manifest-beta.json | 4 ++-- package.json | 2 +- versions.json | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/manifest-beta.json b/manifest-beta.json index 1ab6c30..44ddd1a 100644 --- a/manifest-beta.json +++ b/manifest-beta.json @@ -1,10 +1,10 @@ { "id": "omnisearch", "name": "Omnisearch", - "version": "1.3.4", + "version": "1.3.5-beta2", "minAppVersion": "0.14.2", "description": "A search engine that just works", "author": "Simon Cambier", "authorUrl": "https://github.com/scambier/obsidian-omnisearch", "isDesktopOnly": false -} +} \ No newline at end of file diff --git a/package.json b/package.json index 3529b77..3a791b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scambier.obsidian-search", - "version": "1.3.5-beta1", + "version": "1.3.5-beta2", "description": "A search engine for Obsidian", "main": "dist/main.js", "scripts": { diff --git a/versions.json b/versions.json index 5f492ee..f603c89 100644 --- a/versions.json +++ b/versions.json @@ -26,5 +26,6 @@ "1.3.3-beta": "0.14.2", "1.3.3": "0.14.2", "1.3.4": "0.14.2", - "1.3.5-beta1": "0.14.2" + "1.3.5-beta1": "0.14.2", + "1.3.5-beta2": "0.14.2" } \ No newline at end of file From 21f936e4ee249828a9b2c185011157e1fdf1e257 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Fri, 17 Jun 2022 18:44:44 +0200 Subject: [PATCH 50/53] #57 - only update the index when Omnisearch is loaded --- src/components/ModalVault.svelte | 3 ++- src/main.ts | 39 ++++++++------------------------ src/search.ts | 6 ++++- src/settings.ts | 21 ----------------- 4 files changed, 17 insertions(+), 52 deletions(-) diff --git a/src/components/ModalVault.svelte b/src/components/ModalVault.svelte index e92c8ac..7293596 100644 --- a/src/components/ModalVault.svelte +++ b/src/components/ModalVault.svelte @@ -9,7 +9,7 @@ import InputSearch from "./InputSearch.svelte" import ModalContainer from "./ModalContainer.svelte" import { eventBus, type ResultNote } from "src/globals" import { createNote, openNote } from "src/notes" -import { getSuggestions } from "src/search" +import { getSuggestions, reindexNotes } from "src/search" import { loopIndex } from "src/utils" import { OmnisearchInFileModal, type OmnisearchVaultModal } from "src/modals" import ResultItemVault from "./ResultItemVault.svelte" @@ -29,6 +29,7 @@ $: if (searchQuery) { } onMount(() => { + reindexNotes() searchQuery = lastSearch eventBus.on("vault", "enter", onInputEnter) eventBus.on("vault", "shift-enter", onInputShiftEnter) diff --git a/src/main.ts b/src/main.ts index 1d36441..fca42cb 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,30 +3,21 @@ import { addNoteToReindex, addToIndex, initGlobalSearchIndex, - reindexNotes, removeFromIndex, } from './search' import { OmnisearchInFileModal, OmnisearchVaultModal } from './modals' -import { loadSettings, settings, SettingsTab } from './settings' +import { loadSettings, SettingsTab } from './settings' -let mainWindow: { on: any; off: any } | null = null -try { - mainWindow = require('electron').remote.getCurrentWindow() -} -catch (e) { - console.log("Can't load electron, mobile platform") -} - -const onBlur = (): void => { - reindexNotes() -} +// let mainWindow: { on: any; off: any } | null = null +// try { +// mainWindow = require('electron').remote.getCurrentWindow() +// } +// catch (e) { +// console.log("Can't load electron, mobile platform") +// } export default class OmnisearchPlugin extends Plugin { async onload(): Promise { - if (mainWindow) { - mainWindow.on('blur', onBlur) - } - await loadSettings(this) this.addSettingTab(new SettingsTab(this)) @@ -61,13 +52,7 @@ export default class OmnisearchPlugin extends Plugin { ) this.registerEvent( this.app.vault.on('modify', async file => { - if (settings.reindexInRealTime) { - removeFromIndex(file.path) - await addToIndex(file) - } - else { - addNoteToReindex(file) - } + addNoteToReindex(file) }), ) this.registerEvent( @@ -83,9 +68,5 @@ export default class OmnisearchPlugin extends Plugin { }) } - onunload(): void { - if (mainWindow) { - mainWindow.off('blur', onBlur) - } - } + onunload(): void {} } diff --git a/src/search.ts b/src/search.ts index a85403d..c28e2c4 100644 --- a/src/search.ts +++ b/src/search.ts @@ -388,9 +388,13 @@ export function addNoteToReindex(note: TAbstractFile): void { notesToReindex.add(note) } export async function reindexNotes(): Promise { + if (settings.showIndexingNotices && notesToReindex.size > 0) { + new Notice(`Omnisearch - Reindexing ${notesToReindex.size} notes`, 2000) + } for (const note of notesToReindex) { removeFromIndex(note.path) await addToIndex(note) + await wait(0) } notesToReindex.clear() @@ -401,7 +405,7 @@ async function saveIndexToFile(): Promise { if (settings.storeIndexInFile && minisearchInstance && isIndexChanged) { const json = JSON.stringify(minisearchInstance) await app.vault.adapter.write(searchIndexFilePath, json) - console.log('MiniSearch index saved to the file') + console.log('Omnisearch - Index saved on disk') await saveNotesCacheToFile() isIndexChanged = false diff --git a/src/settings.ts b/src/settings.ts index 45f7892..85a6e17 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -10,7 +10,6 @@ interface WeightingSettings { export interface OmnisearchSettings extends WeightingSettings { respectExcluded: boolean - reindexInRealTime: boolean ignoreDiacritics: boolean showIndexingNotices: boolean showShortName: boolean @@ -38,25 +37,6 @@ export class SettingsTab extends PluginSettingTab { new Setting(containerEl).setName('Behavior').setHeading() - // Index in real-time, desktop only - if (require('electron')) { - new Setting(containerEl) - .setName('Reindex in real-time') - .setDesc( - "By default, notes a reindexed when Obsidian focus is lost. Enable this to reindex in real-time. May affect Obsidian's performances when editing large notes.", - ) - .addToggle(toggle => - toggle.setValue(settings.reindexInRealTime).onChange(async v => { - settings.reindexInRealTime = v - await saveSettings(this.plugin) - }), - ) - } - else { - // No real time indexing on mobile - settings.reindexInRealTime = false - } - // Respect excluded files new Setting(containerEl) .setName('Respect Obsidian\'s "Excluded Files"') @@ -193,7 +173,6 @@ export class SettingsTab extends PluginSettingTab { export const DEFAULT_SETTINGS: OmnisearchSettings = { respectExcluded: true, - reindexInRealTime: false, ignoreDiacritics: false, showIndexingNotices: false, From 6e604988f4720d168a654c1a1cc2fefa6fdcae5a Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Fri, 17 Jun 2022 19:56:10 +0200 Subject: [PATCH 51/53] Fixed #48 - Highly favor tags in search results --- src/globals.ts | 1 + src/search.ts | 24 ++++++++++++++++++++++-- src/types.d.ts | 1 + src/utils.ts | 14 ++++++++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/globals.ts b/src/globals.ts index 572729b..772a6be 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -27,6 +27,7 @@ export type IndexedNote = { content: string aliases: string + tags: string[], headings1: string headings2: string headings3: string diff --git a/src/search.ts b/src/search.ts index c28e2c4..9a81a47 100644 --- a/src/search.ts +++ b/src/search.ts @@ -1,5 +1,5 @@ import { Notice, TAbstractFile, TFile } from 'obsidian' -import MiniSearch, { type SearchResult } from 'minisearch' +import MiniSearch, { type Options, type SearchResult } from 'minisearch' import { chsRegex, SPACE_OR_PUNCTUATION, @@ -10,6 +10,7 @@ import { import { extractHeadingsFromCache, getAliasesFromMetadata, + getTagsFromMetadata, removeDiacritics, stringsToRegex, stripMarkdownCharacters, @@ -51,7 +52,7 @@ const tokenize = (text: string): string[] => { * and adds all the notes to the index */ export async function initGlobalSearchIndex(): Promise { - const options = { + const options: Options = { tokenize, processTerm: (term: string) => (settings.ignoreDiacritics ? removeDiacritics(term) : term).toLowerCase(), @@ -64,6 +65,7 @@ export async function initGlobalSearchIndex(): Promise { 'headings2', 'headings3', ], + storeFields: ['tags'], } if ( @@ -234,6 +236,18 @@ export async function getSuggestions( } else { results = results.slice(0, 50) + + // Put the results with tags on top + const tags = query.segments + .filter(s => s.value.startsWith('#')) + .map(s => s.value) + for (const tag of tags) { + for (const result of results) { + if (result.tags.includes(tag)) { + result.score *= 100 + } + } + } } // Map the raw results to get usable suggestions @@ -243,6 +257,10 @@ export async function getSuggestions( throw new Error(`Note "${result.id}" not indexed`) } + // Remove '#' from tags, for highlighting + query.segments.forEach(s => { + s.value = s.value.replace(/^#/, '') + }) // Clean search matches that match quoted expressions, // and inject those expressions instead const foundWords = [ @@ -251,6 +269,7 @@ export async function getSuggestions( ), ...query.segments.filter(s => s.exact).map(s => s.value), ] + const matches = getMatches(note.content, stringsToRegex(foundWords)) const resultNote: ResultNote = { score: result.score, @@ -307,6 +326,7 @@ export async function addToIndex(file: TAbstractFile): Promise { path: file.path, mtime: file.stat.mtime, + tags: getTagsFromMetadata(metadata), aliases: getAliasesFromMetadata(metadata).join(''), headings1: metadata ? extractHeadingsFromCache(metadata, 1).join(' ') diff --git a/src/types.d.ts b/src/types.d.ts index ff21c9a..c29e77a 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -7,6 +7,7 @@ declare module 'obsidian' { interface FrontMatterCache { aliases?: string[] | string + tags?: string[] | string } interface ViewState { diff --git a/src/utils.ts b/src/utils.ts index 3b1748c..ba9aefc 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -144,6 +144,20 @@ export function getAliasesFromMetadata( .filter(s => !!s) } +export function getTagsFromMetadata(metadata: CachedMetadata | null): string[] { + const arrOrString = metadata?.frontmatter?.tags ?? [] + const fromFrontMatter = ( + Array.isArray(arrOrString) ? arrOrString : arrOrString.split(',') + ) + .map(s => (s ? s.trim() : s)) + .filter(s => !!s) + const fromBody = (metadata?.tags ?? []).map(t => t.tag) + + return [...fromFrontMatter, ...fromBody].map(t => + t[0] !== '#' ? '#' + t : t, + ) +} + /** * https://stackoverflow.com/a/37511463 */ From 08139e7785ab6eb33395a849bd601341975f79cb Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Fri, 17 Jun 2022 20:09:09 +0200 Subject: [PATCH 52/53] 1.3.5-beta3 --- manifest-beta.json | 2 +- package.json | 2 +- versions.json | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/manifest-beta.json b/manifest-beta.json index 44ddd1a..75e776d 100644 --- a/manifest-beta.json +++ b/manifest-beta.json @@ -1,7 +1,7 @@ { "id": "omnisearch", "name": "Omnisearch", - "version": "1.3.5-beta2", + "version": "1.3.5-beta3", "minAppVersion": "0.14.2", "description": "A search engine that just works", "author": "Simon Cambier", diff --git a/package.json b/package.json index 3a791b8..54b2351 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scambier.obsidian-search", - "version": "1.3.5-beta2", + "version": "1.3.5-beta3", "description": "A search engine for Obsidian", "main": "dist/main.js", "scripts": { diff --git a/versions.json b/versions.json index f603c89..f862abf 100644 --- a/versions.json +++ b/versions.json @@ -27,5 +27,6 @@ "1.3.3": "0.14.2", "1.3.4": "0.14.2", "1.3.5-beta1": "0.14.2", - "1.3.5-beta2": "0.14.2" + "1.3.5-beta2": "0.14.2", + "1.3.5-beta3": "0.14.2" } \ No newline at end of file From a923b68b880164826b2be56e50b87481f2cd1341 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Sun, 19 Jun 2022 20:14:55 +0200 Subject: [PATCH 53/53] Fixed #68 --- src/notes.ts | 4 ++-- src/search.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/notes.ts b/src/notes.ts index 957cdbf..8445058 100644 --- a/src/notes.ts +++ b/src/notes.ts @@ -47,8 +47,8 @@ export function getNoteFromCache(key: string): IndexedNote | undefined { export function getNonExistingNotesFromCache(): IndexedNote[] { return Object.values(notesCache).filter(note => note.doesNotExist) } -export function addNoteToCache(key: string, note: IndexedNote): void { - notesCache[key] = note +export function addNoteToCache(filename: string, note: IndexedNote): void { + notesCache[filename] = note } export function removeNoteFromCache(key: string): void { delete notesCache[key] diff --git a/src/search.ts b/src/search.ts index 9a81a47..d510afb 100644 --- a/src/search.ts +++ b/src/search.ts @@ -356,9 +356,9 @@ export async function addToIndex(file: TAbstractFile): Promise { */ export function addNonExistingToIndex(name: string, parent: string): void { name = removeAnchors(name) - if (getNoteFromCache(name)) return - const filename = name + (name.endsWith('.md') ? '' : '.md') + if (getNoteFromCache(filename)) return + const note = { path: filename, basename: name,