diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 6786fd7..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,608 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "adobe-cmap-parser" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3aaf5066d68c8ec9656cfd3a96bc9de83d4883f183d6c6b8d742e36a4819dda" -dependencies = [ - "pom 1.1.0", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - -[[package]] -name = "bumpalo" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "const_fn" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - -[[package]] -name = "dtoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" - -[[package]] -name = "encoding" -version = "0.2.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" -dependencies = [ - "encoding-index-japanese", - "encoding-index-korean", - "encoding-index-simpchinese", - "encoding-index-singlebyte", - "encoding-index-tradchinese", -] - -[[package]] -name = "encoding-index-japanese" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-korean" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-simpchinese" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-singlebyte" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-tradchinese" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding_index_tests" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" - -[[package]] -name = "euclid" -version = "0.20.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb7ef65b3777a325d1eeefefab5b6d4959da54747e33bd6258e789640f307ad" -dependencies = [ - "num-traits", -] - -[[package]] -name = "flate2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" - -[[package]] -name = "js-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "libc" -version = "0.2.134" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" - -[[package]] -name = "linked-hash-map" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "lopdf" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49a0272112719d0037ab63d4bb67f73ba659e1e90bc38f235f163a457ac16f3" -dependencies = [ - "dtoa", - "encoding", - "flate2", - "itoa 0.4.8", - "linked-hash-map", - "log", - "lzw", - "pom 3.2.0", - "time", -] - -[[package]] -name = "lzw" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" - -[[package]] -name = "miniz_oxide" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" -dependencies = [ - "adler", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "obsidian-search" -version = "0.1.0" -dependencies = [ - "js-sys", - "pdf-extract", - "wasm-bindgen", -] - -[[package]] -name = "once_cell" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" - -[[package]] -name = "pdf-extract" -version = "0.6.5-alpha.0" -source = "git+https://github.com/scambier/pdf-extract#8f01969a0bb49bd71195dd4fd5c87a4a0b5f4b48" -dependencies = [ - "adobe-cmap-parser", - "encoding", - "euclid", - "linked-hash-map", - "lopdf", - "postscript", - "type1-encoding-parser", - "unicode-normalization", -] - -[[package]] -name = "pom" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f6ce597ecdcc9a098e7fddacb1065093a3d66446fa16c675e7e71d1b5c28e6" - -[[package]] -name = "pom" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e2192780e9f8e282049ff9bffcaa28171e1cb0844f49ed5374e518ae6024ec" - -[[package]] -name = "postscript" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1825c05c4f9e2f781202d1a02fff5e5f722bbafca542d818364e1b1ea22575" - -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro2" -version = "1.0.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "ryu" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "serde" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" - -[[package]] -name = "serde_derive" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" -dependencies = [ - "itoa 1.0.3", - "ryu", - "serde", -] - -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1", - "syn", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - -[[package]] -name = "syn" -version = "1.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "time" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" -dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros", - "version_check", - "winapi", -] - -[[package]] -name = "time-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] - -[[package]] -name = "time-macros-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "type1-encoding-parser" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d6cc09e1a99c7e01f2afe4953789311a1c50baebbdac5b477ecf78e2e92a5b" -dependencies = [ - "pom 1.1.0", -] - -[[package]] -name = "unicode-ident" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasm-bindgen" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 9d09afa..0000000 --- a/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "obsidian-search" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -crate-type = ["cdylib"] - -[dependencies] -wasm-bindgen = "0.2" -js-sys = "0.3.49" -pdf-extract = { git = "https://github.com/scambier/pdf-extract" } - -[profile.release] -lto = true -opt-level = 'z' diff --git a/README.md b/README.md index 258ce4e..78a808b 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,11 @@ ![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/scambier/obsidian-omnisearch) ![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/scambier/obsidian-omnisearch?include_prereleases&label=BRAT%20beta) -> **Omnisearch** is a search engine that "_just works_". It always instantly shows you the most relevant results, thanks to its smart weighting algorithm. +> **Omnisearch** is a search engine that "_just works_". It always instantly shows you the most relevant results, thanks +> to its smart weighting algorithm. -Under the hood, it uses the excellent [MiniSearch](https://github.com/lucaong/minisearch) library. +Under the hood, it uses the excellent [MiniSearch](https://github.com/lucaong/minisearch) library, +and [obsidian-text-extract](https://github.com/scambier/obsidian-text-extract) for PDFs and images. ![](https://raw.githubusercontent.com/scambier/obsidian-omnisearch/master/images/omnisearch.gif) @@ -17,9 +19,11 @@ Under the hood, it uses the excellent [MiniSearch](https://github.com/lucaong/mi > Omnisearch's first goal is to _locate_ files instantly. You can see it as a _Quick Switcher_ on steroids. - Find your **📝notes, 📄PDFs, and 🖼images** faster than ever - - _Images OCR and PDF indexing are only available on desktop_ -- Automatic document scoring using the [BM25 algorithm](https://github.com/lucaong/minisearch/issues/129#issuecomment-1046257399) - - The relevance of a document against a query depends on the number of times the query terms appear in the document, its filename, and its headings + - _Images OCR and PDF indexing are only available on desktop_ +- Automatic document scoring using + the [BM25 algorithm](https://github.com/lucaong/minisearch/issues/129#issuecomment-1046257399) + - The relevance of a document against a query depends on the number of times the query terms appear in the document, + its filename, and its headings - Keyboard first: you never have to use your mouse - Workflow similar to the "Quick Switcher" core plugin - Resistance to typos @@ -28,12 +32,15 @@ Under the hood, it uses the excellent [MiniSearch](https://github.com/lucaong/mi - Directly Insert a `[[link]]` from the search results - Supports Vim navigation keys -**Note:** support of Chinese, Japanese, Korean, etc. depends on [this additional plugin](https://github.com/aidenlx/cm-chs-patch). Please read its documentation for more information. +**Note:** support of Chinese, Japanese, Korean, etc. depends +on [this additional plugin](https://github.com/aidenlx/cm-chs-patch). Please read its documentation for more +information. ## 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 and break things.** +- Beta releases can be installed through [BRAT](https://github.com/TfTHacker/obsidian42-brat). **Be advised that those + versions can be buggy and break things.** Only install beta versions if you're willing to You can check the [CHANGELOG](./CHANGELOG.md) for more information on the different versions. @@ -43,14 +50,15 @@ Omnisearch can be used within 2 different contexts: ### Vault Search -Omnisearch's core feature, accessible with the Command Palette "**_Omnisearch: Vault search_**". This modal searches through your vault and returns the most relevant notes. That's all you need to _find_ a note. +Omnisearch's core feature, accessible with the Command Palette "**_Omnisearch: Vault search_**". This modal searches +through your vault and returns the most relevant notes. That's all you need to _find_ a note. If you want to list all the search matches of a single note, you can do so by using `tab` to open the In-File Search. -### In-File Search - -Also accessible through the Command Palette "**_Omnisearch: In-file search_**". This modal searches through the active note's content and lists the matching results. Just press enter to automatically scroll to the right place. +### In-File Search +Also accessible through the Command Palette "**_Omnisearch: In-file search_**". This modal searches through the active +note's content and lists the matching results. Just press enter to automatically scroll to the right place. ## URL Scheme & Public API @@ -58,9 +66,11 @@ You can open Omnisearch with the following scheme: `obsidian://omnisearch?query= ---- -For plugin developers and Dataview users, Omnisearch is also accessible through the global object `omnisearch` (`window.omnisearch`) +For plugin developers and Dataview users, Omnisearch is also accessible through the global +object `omnisearch` (`window.omnisearch`) -> This API is an experimental feature, the `ResultNote` interface may change in the future. The `search()` function returns at most 50 results. +> This API is an experimental feature, the `ResultNote` interface may change in the future. The `search()` function +> returns at most 50 results. ```ts // API: @@ -110,12 +120,13 @@ There are several CSS classes you can use to customize the appearance of Omnisea .omnisearch-input-field ``` -For example, if you'd like the usual yellow highlight on search matches, you can add this code inside a CSS snippet file: +For example, if you'd like the usual yellow highlight on search matches, you can add this code inside a CSS snippet +file: ```css .omnisearch-highlight { - color: var(--text-normal); - background-color: var(--text-highlight-bg); + color: var(--text-normal); + background-color: var(--text-highlight-bg); } ``` @@ -123,14 +134,27 @@ See [styles.css](./assets/styles.css) for more information. ## Issues & Solutions -**Omnisearch makes Obsidian sluggish at startup.** +**Omnisearch makes Obsidian sluggish/freeze at startup.** -- While Omnisearch does its best to work smoothly in the background, bigger vaults can cause some hiccups at startup because of the search index size. +- While Omnisearch does its best to work smoothly in the background, bigger vaults and files can make Obsidian stutter + during indexing. +- If you have several thousands of files, Obsidian may freeze a few seconds at startup while the Omnisearch cache is + loaded in memory. + +**Omnisearch is slow to index my PDFs and images** + +- The first time Omnisearch indexes those files, it needs to extract their text. This can take a long time, but + will only happen once. This process is also resumable, so you can temporarily disable PDFs/images indexing, or close + Obsidian without losing data. + +**Can I index PDFs/images on mobile?** + +- Not at the moment. On mobile devices, text extraction either doesn't work or consumes too much resources. **Omnisearch gives inconsistent/invalid results, there are errors in the developer console** - Restart Obsidian to force a reindex of Omnisearch. -- The cache can be corrupted; you can clear it at the bottom of the settings page, then restart Obsidian. +- The cache could be corrupted; you can clear it at the bottom of the settings page, then restart Obsidian. **A query should return a result that does not appear.** @@ -144,8 +168,8 @@ See [here](https://github.com/scambier/obsidian-omnisearch#css-customization). **I'm still having an issue** -You can write your issue [here](https://github.com/scambier/obsidian-omnisearch/issues) with as much details as possible. - +You can write your issue [here](https://github.com/scambier/obsidian-omnisearch/issues) with as much details as +possible. ## LICENSE @@ -153,6 +177,7 @@ Omnisearch is licensed under [GPL-3](https://tldrlegal.com/license/gnu-general-p ## Thanks -To all people who donate through [Ko-Fi](https://ko-fi.com/scambier) or [Github Sponsors](https://github.com/sponsors/scambier) ❤ +To all people who donate through [Ko-Fi](https://ko-fi.com/scambier) +or [Github Sponsors](https://github.com/sponsors/scambier) ❤ ![JetBrains Logo (Main) logo](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg) diff --git a/assets/styles.css b/assets/styles.css index a426b95..b9c3ac7 100644 --- a/assets/styles.css +++ b/assets/styles.css @@ -30,6 +30,11 @@ .omnisearch-highlight { } +.omnisearch-default-highlight { + color: var(--text-normal); + background-color: var(--text-highlight-bg); +} + .omnisearch-input-container { display: flex; flex-direction: row; diff --git a/package.json b/package.json index ef24e29..7d303fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scambier.obsidian-search", - "version": "1.8.1", + "version": "1.9.0-beta.8", "description": "A search engine for Obsidian", "main": "dist/main.js", "scripts": { @@ -14,13 +14,13 @@ "author": "Simon Cambier", "license": "GPL-3", "devDependencies": { - "@babel/preset-env": "^7.19.4", + "@babel/preset-env": "^7.20.2", "@babel/preset-typescript": "^7.18.6", "@testing-library/jest-dom": "^5.16.5", "@tsconfig/svelte": "^3.0.0", "@types/jest": "^27.5.2", "@types/lodash-es": "^4.17.6", - "@types/node": "^16.11.64", + "@types/node": "^16.18.4", "@types/pako": "^2.0.0", "babel-jest": "^27.5.1", "builtin-modules": "^3.3.0", @@ -29,21 +29,21 @@ "esbuild-svelte": "0.7.1", "jest": "^27.5.1", "obsidian": "latest", - "prettier": "^2.7.1", - "prettier-plugin-svelte": "^2.8.0", - "svelte": "^3.51.0", - "svelte-check": "^2.9.2", + "prettier": "^2.8.0", + "prettier-plugin-svelte": "^2.8.1", + "svelte": "^3.53.1", + "svelte-check": "^2.10.0", "svelte-jester": "^2.3.2", "svelte-preprocess": "^4.10.7", "tslib": "2.3.1", - "typescript": "^4.8.4", - "vite": "^3.2.1" + "typescript": "^4.9.3", + "vite": "^3.2.4" }, "dependencies": { "dexie": "^3.2.2", "lodash-es": "4.17.21", - "minisearch": "github:scambier/minisearch#callback_desync", - "obsidian-text-extract": "1.0.3", + "minisearch": "6.0.0-beta.1", + "obsidian-text-extract": "1.0.4", "pure-md5": "^0.1.14" }, "pnpm": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 91209f8..18914f3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,13 +4,13 @@ overrides: moment@>=2.18.0 <2.29.4: '>=2.29.4' specifiers: - '@babel/preset-env': ^7.19.4 + '@babel/preset-env': ^7.20.2 '@babel/preset-typescript': ^7.18.6 '@testing-library/jest-dom': ^5.16.5 '@tsconfig/svelte': ^3.0.0 '@types/jest': ^27.5.2 '@types/lodash-es': ^4.17.6 - '@types/node': ^16.11.64 + '@types/node': ^16.18.4 '@types/pako': ^2.0.0 babel-jest: ^27.5.1 builtin-modules: ^3.3.0 @@ -20,25 +20,25 @@ specifiers: esbuild-svelte: 0.7.1 jest: ^27.5.1 lodash-es: 4.17.21 - minisearch: github:scambier/minisearch#callback_desync + minisearch: 6.0.0-beta.1 obsidian: latest - obsidian-text-extract: 1.0.3 - prettier: ^2.7.1 - prettier-plugin-svelte: ^2.8.0 + obsidian-text-extract: 1.0.4 + prettier: ^2.8.0 + prettier-plugin-svelte: ^2.8.1 pure-md5: ^0.1.14 - svelte: ^3.51.0 - svelte-check: ^2.9.2 + svelte: ^3.53.1 + svelte-check: ^2.10.0 svelte-jester: ^2.3.2 svelte-preprocess: ^4.10.7 tslib: 2.3.1 - typescript: ^4.8.4 - vite: ^3.2.1 + typescript: ^4.9.3 + vite: ^3.2.4 dependencies: dexie: 3.2.2 lodash-es: 4.17.21 - minisearch: github.com/scambier/minisearch/adf11cab46d851220a41c9ad95ed986b630f0f3c - obsidian-text-extract: 1.0.3 + minisearch: 6.0.0-beta.1 + obsidian-text-extract: 1.0.4 pure-md5: 0.1.14 devDependencies: @@ -48,24 +48,24 @@ devDependencies: '@tsconfig/svelte': 3.0.0 '@types/jest': 27.5.2 '@types/lodash-es': 4.17.6 - '@types/node': 16.18.3 + '@types/node': 16.18.4 '@types/pako': 2.0.0 babel-jest: 27.5.1 builtin-modules: 3.3.0 esbuild: 0.14.0 esbuild-plugin-copy: 1.3.0_esbuild@0.14.0 - esbuild-svelte: 0.7.1_bvt7ajmht5nri6yjdkgzgnstui + esbuild-svelte: 0.7.1_ihq6zb4jn6rs2ewpbixx47bd3m jest: 27.5.1 obsidian: 0.16.3 - prettier: 2.7.1 - prettier-plugin-svelte: 2.8.0_lrllcp5xtrkmmdzifit4hd52ze - svelte: 3.52.0 - svelte-check: 2.9.2_svelte@3.52.0 - svelte-jester: 2.3.2_jest@27.5.1+svelte@3.52.0 - svelte-preprocess: 4.10.7_besnmoibwkhwtentvwuriss7pa + prettier: 2.8.0 + prettier-plugin-svelte: 2.8.1_3ndnxlh52lolrqe4kgjgbxb3xa + svelte: 3.53.1 + svelte-check: 2.10.0_svelte@3.53.1 + svelte-jester: 2.3.2_jest@27.5.1+svelte@3.53.1 + svelte-preprocess: 4.10.7_7dvewpees4iyn2tkw2qzal77a4 tslib: 2.3.1 - typescript: 4.8.4 - vite: 3.2.2 + typescript: 4.9.3 + vite: 3.2.4_@types+node@16.18.4 packages: @@ -87,25 +87,25 @@ packages: dependencies: '@babel/highlight': 7.18.6 - /@babel/compat-data/7.20.1: - resolution: {integrity: sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==} + /@babel/compat-data/7.20.5: + resolution: {integrity: sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==} engines: {node: '>=6.9.0'} dev: true - /@babel/core/7.20.2: - resolution: {integrity: sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==} + /@babel/core/7.20.5: + resolution: {integrity: sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.0 '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.2 - '@babel/helper-compilation-targets': 7.20.0_@babel+core@7.20.2 + '@babel/generator': 7.20.5 + '@babel/helper-compilation-targets': 7.20.0_@babel+core@7.20.5 '@babel/helper-module-transforms': 7.20.2 - '@babel/helpers': 7.20.1 - '@babel/parser': 7.20.2 + '@babel/helpers': 7.20.6 + '@babel/parser': 7.20.5 '@babel/template': 7.18.10 - '@babel/traverse': 7.20.1 - '@babel/types': 7.20.2 + '@babel/traverse': 7.20.5 + '@babel/types': 7.20.5 convert-source-map: 1.9.0 debug: 4.3.4 gensync: 1.0.0-beta.2 @@ -115,11 +115,11 @@ packages: - supports-color dev: true - /@babel/generator/7.20.2: - resolution: {integrity: sha512-SD75PMIK6i9H8G/tfGvB4KKl4Nw6Ssos9nGgYwxbgyTP0iX/Z55DveoH86rmUB/YHTQQ+ZC0F7xxaY8l2OF44Q==} + /@babel/generator/7.20.5: + resolution: {integrity: sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 '@jridgewell/gen-mapping': 0.3.2 jsesc: 2.5.2 @@ -127,7 +127,7 @@ packages: resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 dev: true /@babel/helper-builder-binary-assignment-operator-visitor/7.18.9: @@ -135,7 +135,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/helper-explode-assignable-expression': 7.18.6 - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 dev: true /@babel/helper-compilation-targets/7.20.0: @@ -144,27 +144,27 @@ packages: peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.20.1 + '@babel/compat-data': 7.20.5 '@babel/helper-validator-option': 7.18.6 browserslist: 4.21.4 semver: 6.3.0 dev: true - /@babel/helper-compilation-targets/7.20.0_@babel+core@7.20.2: + /@babel/helper-compilation-targets/7.20.0_@babel+core@7.20.5: resolution: {integrity: sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.20.1 - '@babel/core': 7.20.2 + '@babel/compat-data': 7.20.5 + '@babel/core': 7.20.5 '@babel/helper-validator-option': 7.18.6 browserslist: 4.21.4 semver: 6.3.0 dev: true - /@babel/helper-create-class-features-plugin/7.20.2: - resolution: {integrity: sha512-k22GoYRAHPYr9I+Gvy2ZQlAe5mGy8BqWst2wRt8cwIufWTxrsVshhIBvYNqC80N0GSFWTsqRVexOtfzlgOEDvA==} + /@babel/helper-create-class-features-plugin/7.20.5: + resolution: {integrity: sha512-3RCdA/EmEaikrhayahwToF0fpweU/8o2p8vhc1c/1kftHOdTKuC65kik/TLc+qfbS8JKw4qqJbne4ovICDhmww==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -180,14 +180,14 @@ packages: - supports-color dev: true - /@babel/helper-create-regexp-features-plugin/7.19.0: - resolution: {integrity: sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==} + /@babel/helper-create-regexp-features-plugin/7.20.5: + resolution: {integrity: sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: '@babel/helper-annotate-as-pure': 7.18.6 - regexpu-core: 5.2.1 + regexpu-core: 5.2.2 dev: true /@babel/helper-define-polyfill-provider/0.3.3: @@ -213,7 +213,7 @@ packages: resolution: {integrity: sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 dev: true /@babel/helper-function-name/7.19.0: @@ -221,26 +221,26 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.18.10 - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 /@babel/helper-hoist-variables/7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 /@babel/helper-member-expression-to-functions/7.18.9: resolution: {integrity: sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 dev: true /@babel/helper-module-imports/7.18.6: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 dev: true /@babel/helper-module-transforms/7.20.2: @@ -253,8 +253,8 @@ packages: '@babel/helper-split-export-declaration': 7.18.6 '@babel/helper-validator-identifier': 7.19.1 '@babel/template': 7.18.10 - '@babel/traverse': 7.20.1 - '@babel/types': 7.20.2 + '@babel/traverse': 7.20.5 + '@babel/types': 7.20.5 transitivePeerDependencies: - supports-color dev: true @@ -263,7 +263,7 @@ packages: resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 dev: true /@babel/helper-plugin-utils/7.20.2: @@ -279,8 +279,8 @@ packages: dependencies: '@babel/helper-annotate-as-pure': 7.18.6 '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-wrap-function': 7.19.0 - '@babel/types': 7.20.2 + '@babel/helper-wrap-function': 7.20.5 + '@babel/types': 7.20.5 transitivePeerDependencies: - supports-color dev: true @@ -292,8 +292,8 @@ packages: '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-member-expression-to-functions': 7.18.9 '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/traverse': 7.20.1 - '@babel/types': 7.20.2 + '@babel/traverse': 7.20.5 + '@babel/types': 7.20.5 transitivePeerDependencies: - supports-color dev: true @@ -302,21 +302,21 @@ packages: resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 dev: true /@babel/helper-skip-transparent-expression-wrappers/7.20.0: resolution: {integrity: sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 dev: true /@babel/helper-split-export-declaration/7.18.6: resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 /@babel/helper-string-parser/7.19.4: resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} @@ -331,25 +331,25 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/helper-wrap-function/7.19.0: - resolution: {integrity: sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==} + /@babel/helper-wrap-function/7.20.5: + resolution: {integrity: sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-function-name': 7.19.0 '@babel/template': 7.18.10 - '@babel/traverse': 7.20.1 - '@babel/types': 7.20.2 + '@babel/traverse': 7.20.5 + '@babel/types': 7.20.5 transitivePeerDependencies: - supports-color dev: true - /@babel/helpers/7.20.1: - resolution: {integrity: sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==} + /@babel/helpers/7.20.6: + resolution: {integrity: sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==} engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.18.10 - '@babel/traverse': 7.20.1 - '@babel/types': 7.20.2 + '@babel/traverse': 7.20.5 + '@babel/types': 7.20.5 transitivePeerDependencies: - supports-color dev: true @@ -362,12 +362,12 @@ packages: chalk: 2.4.2 js-tokens: 4.0.0 - /@babel/parser/7.20.2: - resolution: {integrity: sha512-afk318kh2uKbo7BEj2QtEi8HVCGrwHUffrYDy7dgVcSa2j9lY3LDjPzcyGdpX7xgm35aWqvciZJ4WKmdF/SxYg==} + /@babel/parser/7.20.5: + resolution: {integrity: sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/7.18.6: resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} @@ -409,7 +409,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-create-class-features-plugin': 7.20.2 + '@babel/helper-create-class-features-plugin': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 transitivePeerDependencies: - supports-color @@ -421,7 +421,7 @@ packages: peerDependencies: '@babel/core': ^7.12.0 dependencies: - '@babel/helper-create-class-features-plugin': 7.20.2 + '@babel/helper-create-class-features-plugin': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 '@babel/plugin-syntax-class-static-block': 7.14.5 transitivePeerDependencies: @@ -494,11 +494,11 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.20.1 + '@babel/compat-data': 7.20.5 '@babel/helper-compilation-targets': 7.20.0 '@babel/helper-plugin-utils': 7.20.2 '@babel/plugin-syntax-object-rest-spread': 7.8.3 - '@babel/plugin-transform-parameters': 7.20.1 + '@babel/plugin-transform-parameters': 7.20.5 dev: true /@babel/plugin-proposal-optional-catch-binding/7.18.6: @@ -528,20 +528,20 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-create-class-features-plugin': 7.20.2 + '@babel/helper-create-class-features-plugin': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-proposal-private-property-in-object/7.18.6: - resolution: {integrity: sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==} + /@babel/plugin-proposal-private-property-in-object/7.20.5: + resolution: {integrity: sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-create-class-features-plugin': 7.20.2 + '@babel/helper-create-class-features-plugin': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 '@babel/plugin-syntax-private-property-in-object': 7.14.5 transitivePeerDependencies: @@ -554,7 +554,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-create-regexp-features-plugin': 7.19.0 + '@babel/helper-create-regexp-features-plugin': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -566,12 +566,12 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.20.2: + /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.20.5: resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.2 + '@babel/core': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -583,12 +583,12 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.20.2: + /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.20.5: resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.2 + '@babel/core': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -600,12 +600,12 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.20.2: + /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.20.5: resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.2 + '@babel/core': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -651,12 +651,12 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.20.2: + /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.20.5: resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.2 + '@babel/core': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -668,12 +668,12 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.20.2: + /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.20.5: resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.2 + '@babel/core': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -685,12 +685,12 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.20.2: + /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.20.5: resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.2 + '@babel/core': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -702,12 +702,12 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.20.2: + /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.20.5: resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.2 + '@babel/core': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -719,12 +719,12 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.20.2: + /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.20.5: resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.2 + '@babel/core': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -736,12 +736,12 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.20.2: + /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.20.5: resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.2 + '@babel/core': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -753,12 +753,12 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.20.2: + /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.20.5: resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.2 + '@babel/core': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -770,12 +770,12 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.20.2: + /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.20.5: resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.2 + '@babel/core': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -797,13 +797,13 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.20.2: + /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.20.5: resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.2 + '@babel/core': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -816,13 +816,13 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-typescript/7.20.0_@babel+core@7.20.2: + /@babel/plugin-syntax-typescript/7.20.0_@babel+core@7.20.5: resolution: {integrity: sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.20.2 + '@babel/core': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -857,8 +857,8 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-block-scoping/7.20.2: - resolution: {integrity: sha512-y5V15+04ry69OV2wULmwhEA6jwSWXO1TwAtIwiPXcvHcoOQUqpyMVd2bDsQJMW8AurjulIyUV8kDqtjSwHy1uQ==} + /@babel/plugin-transform-block-scoping/7.20.5: + resolution: {integrity: sha512-WvpEIW9Cbj9ApF3yJCjIEEf1EiNJLtXagOrL5LNWEZOo3jv8pmPoYTSNJQvqej8OavVlgOoOPw6/htGZro6IkA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -909,7 +909,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-create-regexp-features-plugin': 7.19.0 + '@babel/helper-create-regexp-features-plugin': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -1021,13 +1021,13 @@ packages: - supports-color dev: true - /@babel/plugin-transform-named-capturing-groups-regex/7.19.1: - resolution: {integrity: sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==} + /@babel/plugin-transform-named-capturing-groups-regex/7.20.5: + resolution: {integrity: sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/helper-create-regexp-features-plugin': 7.19.0 + '@babel/helper-create-regexp-features-plugin': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -1052,8 +1052,8 @@ packages: - supports-color dev: true - /@babel/plugin-transform-parameters/7.20.1: - resolution: {integrity: sha512-nDvKLrAvl+kf6BOy1UJ3MGwzzfTMgppxwiD2Jb4LO3xjYyZq30oQzDNJbCQpMdG9+j2IXHoiMrw5Cm/L6ZoxXQ==} + /@babel/plugin-transform-parameters/7.20.5: + resolution: {integrity: sha512-h7plkOmcndIUWXZFLgpbrh2+fXAi47zcUX7IrOQuZdLD0I0KvjJ6cvo3BEcAOsDOcZhVKGJqv07mkSqK0y2isQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1070,14 +1070,14 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-regenerator/7.18.6: - resolution: {integrity: sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==} + /@babel/plugin-transform-regenerator/7.20.5: + resolution: {integrity: sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/helper-plugin-utils': 7.20.2 - regenerator-transform: 0.15.0 + regenerator-transform: 0.15.1 dev: true /@babel/plugin-transform-reserved-words/7.18.6: @@ -1141,7 +1141,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-create-class-features-plugin': 7.20.2 + '@babel/helper-create-class-features-plugin': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 '@babel/plugin-syntax-typescript': 7.20.0 transitivePeerDependencies: @@ -1163,7 +1163,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-create-regexp-features-plugin': 7.19.0 + '@babel/helper-create-regexp-features-plugin': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -1173,7 +1173,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.20.1 + '@babel/compat-data': 7.20.5 '@babel/helper-compilation-targets': 7.20.0 '@babel/helper-plugin-utils': 7.20.2 '@babel/helper-validator-option': 7.18.6 @@ -1192,7 +1192,7 @@ packages: '@babel/plugin-proposal-optional-catch-binding': 7.18.6 '@babel/plugin-proposal-optional-chaining': 7.18.9 '@babel/plugin-proposal-private-methods': 7.18.6 - '@babel/plugin-proposal-private-property-in-object': 7.18.6 + '@babel/plugin-proposal-private-property-in-object': 7.20.5 '@babel/plugin-proposal-unicode-property-regex': 7.18.6 '@babel/plugin-syntax-async-generators': 7.8.4 '@babel/plugin-syntax-class-properties': 7.12.13 @@ -1212,7 +1212,7 @@ packages: '@babel/plugin-transform-arrow-functions': 7.18.6 '@babel/plugin-transform-async-to-generator': 7.18.6 '@babel/plugin-transform-block-scoped-functions': 7.18.6 - '@babel/plugin-transform-block-scoping': 7.20.2 + '@babel/plugin-transform-block-scoping': 7.20.5 '@babel/plugin-transform-classes': 7.20.2 '@babel/plugin-transform-computed-properties': 7.18.9 '@babel/plugin-transform-destructuring': 7.20.2 @@ -1227,12 +1227,12 @@ packages: '@babel/plugin-transform-modules-commonjs': 7.19.6 '@babel/plugin-transform-modules-systemjs': 7.19.6 '@babel/plugin-transform-modules-umd': 7.18.6 - '@babel/plugin-transform-named-capturing-groups-regex': 7.19.1 + '@babel/plugin-transform-named-capturing-groups-regex': 7.20.5 '@babel/plugin-transform-new-target': 7.18.6 '@babel/plugin-transform-object-super': 7.18.6 - '@babel/plugin-transform-parameters': 7.20.1 + '@babel/plugin-transform-parameters': 7.20.5 '@babel/plugin-transform-property-literals': 7.18.6 - '@babel/plugin-transform-regenerator': 7.18.6 + '@babel/plugin-transform-regenerator': 7.20.5 '@babel/plugin-transform-reserved-words': 7.18.6 '@babel/plugin-transform-shorthand-properties': 7.18.6 '@babel/plugin-transform-spread': 7.19.0 @@ -1242,11 +1242,11 @@ packages: '@babel/plugin-transform-unicode-escapes': 7.18.10 '@babel/plugin-transform-unicode-regex': 7.18.6 '@babel/preset-modules': 0.1.5 - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 babel-plugin-polyfill-corejs2: 0.3.3 babel-plugin-polyfill-corejs3: 0.6.0 babel-plugin-polyfill-regenerator: 0.4.1 - core-js-compat: 3.26.0 + core-js-compat: 3.26.1 semver: 6.3.0 transitivePeerDependencies: - supports-color @@ -1260,7 +1260,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 '@babel/plugin-proposal-unicode-property-regex': 7.18.6 '@babel/plugin-transform-dotall-regex': 7.18.6 - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 esutils: 2.0.3 dev: true @@ -1277,11 +1277,11 @@ packages: - supports-color dev: true - /@babel/runtime/7.20.1: - resolution: {integrity: sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==} + /@babel/runtime/7.20.6: + resolution: {integrity: sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA==} engines: {node: '>=6.9.0'} dependencies: - regenerator-runtime: 0.13.10 + regenerator-runtime: 0.13.11 dev: true /@babel/template/7.18.10: @@ -1289,28 +1289,28 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/parser': 7.20.2 - '@babel/types': 7.20.2 + '@babel/parser': 7.20.5 + '@babel/types': 7.20.5 - /@babel/traverse/7.20.1: - resolution: {integrity: sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==} + /@babel/traverse/7.20.5: + resolution: {integrity: sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.2 + '@babel/generator': 7.20.5 '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-function-name': 7.19.0 '@babel/helper-hoist-variables': 7.18.6 '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.20.2 - '@babel/types': 7.20.2 + '@babel/parser': 7.20.5 + '@babel/types': 7.20.5 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color - /@babel/types/7.20.2: - resolution: {integrity: sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==} + /@babel/types/7.20.5: + resolution: {integrity: sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-string-parser': 7.19.4 @@ -1321,8 +1321,8 @@ packages: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true - /@esbuild/android-arm/0.15.13: - resolution: {integrity: sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw==} + /@esbuild/android-arm/0.15.16: + resolution: {integrity: sha512-nyB6CH++2mSgx3GbnrJsZSxzne5K0HMyNIWafDHqYy7IwxFc4fd/CgHVZXr8Eh+Q3KbIAcAe3vGyqIPhGblvMQ==} engines: {node: '>=12'} cpu: [arm] os: [android] @@ -1330,8 +1330,8 @@ packages: dev: true optional: true - /@esbuild/linux-loong64/0.15.13: - resolution: {integrity: sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag==} + /@esbuild/linux-loong64/0.15.16: + resolution: {integrity: sha512-SDLfP1uoB0HZ14CdVYgagllgrG7Mdxhkt4jDJOKl/MldKrkQ6vDJMZKl2+5XsEY/Lzz37fjgLQoJBGuAw/x8kQ==} engines: {node: '>=12'} cpu: [loong64] os: [linux] @@ -1360,7 +1360,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.18.3 + '@types/node': 16.18.4 chalk: 4.1.2 jest-message-util: 27.5.1 jest-util: 27.5.1 @@ -1381,7 +1381,7 @@ packages: '@jest/test-result': 27.5.1 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.3 + '@types/node': 16.18.4 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.8.1 @@ -1418,7 +1418,7 @@ packages: dependencies: '@jest/fake-timers': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.3 + '@types/node': 16.18.4 jest-mock: 27.5.1 dev: true @@ -1428,7 +1428,7 @@ packages: dependencies: '@jest/types': 27.5.1 '@sinonjs/fake-timers': 8.1.0 - '@types/node': 16.18.3 + '@types/node': 16.18.4 jest-message-util: 27.5.1 jest-mock: 27.5.1 jest-util: 27.5.1 @@ -1457,7 +1457,7 @@ packages: '@jest/test-result': 27.5.1 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.3 + '@types/node': 16.18.4 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -1516,7 +1516,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.20.2 + '@babel/core': 7.20.5 '@jest/types': 27.5.1 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 @@ -1541,7 +1541,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 16.18.3 + '@types/node': 16.18.4 '@types/yargs': 16.0.4 chalk: 4.1.2 dev: true @@ -1600,8 +1600,8 @@ packages: fastq: 1.13.0 dev: true - /@sinonjs/commons/1.8.4: - resolution: {integrity: sha512-RpmQdHVo8hCEHDVpO39zToS9jOhR6nw+/lQAzRNq9ErrGV9IeHM71XCn68svVl/euFeVW6BWX4p35gkhbOcSIQ==} + /@sinonjs/commons/1.8.6: + resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} dependencies: type-detect: 4.0.8 dev: true @@ -1609,7 +1609,7 @@ packages: /@sinonjs/fake-timers/8.1.0: resolution: {integrity: sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==} dependencies: - '@sinonjs/commons': 1.8.4 + '@sinonjs/commons': 1.8.6 dev: true /@testing-library/jest-dom/5.16.5: @@ -1617,7 +1617,7 @@ packages: engines: {node: '>=8', npm: '>=6', yarn: '>=1'} dependencies: '@adobe/css-tools': 4.0.1 - '@babel/runtime': 7.20.1 + '@babel/runtime': 7.20.6 '@types/testing-library__jest-dom': 5.14.5 aria-query: 5.1.3 chalk: 3.0.0 @@ -1636,33 +1636,33 @@ packages: resolution: {integrity: sha512-pYrtLtOwku/7r1i9AMONsJMVYAtk3hzOfiGNekhtq5tYBGA7unMve8RvUclKLMT3PrihvJqUmzsRGh0RP84hKg==} dev: true - /@types/babel__core/7.1.19: - resolution: {integrity: sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==} + /@types/babel__core/7.1.20: + resolution: {integrity: sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==} dependencies: - '@babel/parser': 7.20.2 - '@babel/types': 7.20.2 + '@babel/parser': 7.20.5 + '@babel/types': 7.20.5 '@types/babel__generator': 7.6.4 '@types/babel__template': 7.4.1 - '@types/babel__traverse': 7.18.2 + '@types/babel__traverse': 7.18.3 dev: true /@types/babel__generator/7.6.4: resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} dependencies: - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 dev: true /@types/babel__template/7.4.1: resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} dependencies: - '@babel/parser': 7.20.2 - '@babel/types': 7.20.2 + '@babel/parser': 7.20.5 + '@babel/types': 7.20.5 dev: true - /@types/babel__traverse/7.18.2: - resolution: {integrity: sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==} + /@types/babel__traverse/7.18.3: + resolution: {integrity: sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==} dependencies: - '@babel/types': 7.20.2 + '@babel/types': 7.20.5 dev: true /@types/codemirror/0.0.108: @@ -1678,7 +1678,7 @@ packages: /@types/graceful-fs/4.1.5: resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} dependencies: - '@types/node': 16.18.3 + '@types/node': 16.18.4 dev: true /@types/istanbul-lib-coverage/2.0.4: @@ -1707,15 +1707,15 @@ packages: /@types/lodash-es/4.17.6: resolution: {integrity: sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==} dependencies: - '@types/lodash': 4.14.188 + '@types/lodash': 4.14.191 dev: true - /@types/lodash/4.14.188: - resolution: {integrity: sha512-zmEmF5OIM3rb7SbLCFYoQhO4dGt2FRM9AMkxvA3LaADOF1n8in/zGJlWji9fmafLoNyz+FoL6FE0SLtGIArD7w==} + /@types/lodash/4.14.191: + resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==} dev: true - /@types/node/16.18.3: - resolution: {integrity: sha512-jh6m0QUhIRcZpNv7Z/rpN+ZWXOicUUQbSoWks7Htkbb9IjFQj4kzcX/xFCkjstCj5flMsN8FiSvt+q+Tcs4Llg==} + /@types/node/16.18.4: + resolution: {integrity: sha512-9qGjJ5GyShZjUfx2ArBIGM+xExdfLvvaCyQR0t6yRXKPcWCVYF/WemtX/uIU3r7FYECXRXkIiw2Vnhn6y8d+pw==} dev: true /@types/pako/2.0.0: @@ -1733,7 +1733,7 @@ packages: /@types/sass/1.43.1: resolution: {integrity: sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==} dependencies: - '@types/node': 16.18.3 + '@types/node': 16.18.4 dev: true /@types/stack-utils/2.0.1: @@ -1829,8 +1829,8 @@ packages: engines: {node: '>=10'} dev: true - /anymatch/3.1.2: - resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} + /anymatch/3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} dependencies: normalize-path: 3.0.0 @@ -1871,9 +1871,9 @@ packages: eslint: '>= 4.12.1' dependencies: '@babel/code-frame': 7.18.6 - '@babel/parser': 7.20.2 - '@babel/traverse': 7.20.1 - '@babel/types': 7.20.2 + '@babel/parser': 7.20.5 + '@babel/traverse': 7.20.5 + '@babel/types': 7.20.5 eslint-visitor-keys: 1.3.0 resolve: 1.22.1 transitivePeerDependencies: @@ -1888,7 +1888,7 @@ packages: dependencies: '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/babel__core': 7.1.19 + '@types/babel__core': 7.1.20 babel-plugin-istanbul: 6.1.1 babel-preset-jest: 27.5.1 chalk: 4.1.2 @@ -1898,18 +1898,18 @@ packages: - supports-color dev: true - /babel-jest/27.5.1_@babel+core@7.20.2: + /babel-jest/27.5.1_@babel+core@7.20.5: 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.20.2 + '@babel/core': 7.20.5 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/babel__core': 7.1.19 + '@types/babel__core': 7.1.20 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 27.5.1_@babel+core@7.20.2 + babel-preset-jest: 27.5.1_@babel+core@7.20.5 chalk: 4.1.2 graceful-fs: 4.2.10 slash: 3.0.0 @@ -1935,9 +1935,9 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@babel/template': 7.18.10 - '@babel/types': 7.20.2 - '@types/babel__core': 7.1.19 - '@types/babel__traverse': 7.18.2 + '@babel/types': 7.20.5 + '@types/babel__core': 7.1.20 + '@types/babel__traverse': 7.18.3 dev: true /babel-plugin-polyfill-corejs2/0.3.3: @@ -1945,7 +1945,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.20.1 + '@babel/compat-data': 7.20.5 '@babel/helper-define-polyfill-provider': 0.3.3 semver: 6.3.0 transitivePeerDependencies: @@ -1958,7 +1958,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/helper-define-polyfill-provider': 0.3.3 - core-js-compat: 3.26.0 + core-js-compat: 3.26.1 transitivePeerDependencies: - supports-color dev: true @@ -1992,24 +1992,24 @@ packages: '@babel/plugin-syntax-top-level-await': 7.14.5 dev: true - /babel-preset-current-node-syntax/1.0.1_@babel+core@7.20.2: + /babel-preset-current-node-syntax/1.0.1_@babel+core@7.20.5: resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.20.2 - '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.20.2 - '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.20.2 - '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.20.2 - '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.20.2 - '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.20.2 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.20.2 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.20.2 - '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.20.2 - '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.20.2 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.20.2 - '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.20.2 - '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.20.2 + '@babel/core': 7.20.5 + '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.20.5 + '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.20.5 + '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.20.5 + '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.20.5 + '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.20.5 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.20.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.20.5 + '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.20.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.20.5 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.20.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.20.5 + '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.20.5 dev: true /babel-preset-jest/27.5.1: @@ -2022,15 +2022,15 @@ packages: babel-preset-current-node-syntax: 1.0.1 dev: true - /babel-preset-jest/27.5.1_@babel+core@7.20.2: + /babel-preset-jest/27.5.1_@babel+core@7.20.5: 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.20.2 + '@babel/core': 7.20.5 babel-plugin-jest-hoist: 27.5.1 - babel-preset-current-node-syntax: 1.0.1_@babel+core@7.20.2 + babel-preset-current-node-syntax: 1.0.1_@babel+core@7.20.5 dev: true /balanced-match/1.0.2: @@ -2069,7 +2069,7 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001430 + caniuse-lite: 1.0.30001435 electron-to-chromium: 1.4.284 node-releases: 2.0.6 update-browserslist-db: 1.0.10_browserslist@4.21.4 @@ -2116,8 +2116,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite/1.0.30001430: - resolution: {integrity: sha512-IB1BXTZKPDVPM7cnV4iaKaHxckvdr/3xtctB3f7Hmenx3qYBhGtTZ//7EllK66aKXW98Lx0+7Yr0kxBtIt3tzg==} + /caniuse-lite/1.0.30001435: + resolution: {integrity: sha512-kdCkUTjR+v4YAJelyiDTqiu82BDr4W4CP5sgTA0ZBmqn30XfS2ZghPLMowik9TPhS+psWJiUNxsqLyurDbmutA==} dev: true /chalk/2.4.2: @@ -2153,7 +2153,7 @@ packages: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} dependencies: - anymatch: 3.1.2 + anymatch: 3.1.3 braces: 3.0.2 glob-parent: 5.1.2 is-binary-path: 2.1.0 @@ -2164,8 +2164,9 @@ packages: fsevents: 2.3.2 dev: true - /ci-info/3.5.0: - resolution: {integrity: sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==} + /ci-info/3.7.0: + resolution: {integrity: sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==} + engines: {node: '>=8'} dev: true /cjs-module-lexer/1.2.2: @@ -2223,8 +2224,8 @@ packages: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} dev: true - /core-js-compat/3.26.0: - resolution: {integrity: sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A==} + /core-js-compat/3.26.1: + resolution: {integrity: sha512-622/KzTudvXCDLRw70iHW4KKs1aGpcRcowGWyYJr2DEBfRrd6hNJybxSWJFuZYD4ma86xhrwDDHxmDaIq4EA8A==} dependencies: browserslist: 4.21.4 dev: true @@ -2401,8 +2402,8 @@ packages: resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} dev: true - /esbuild-android-64/0.15.13: - resolution: {integrity: sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g==} + /esbuild-android-64/0.15.16: + resolution: {integrity: sha512-Vwkv/sT0zMSgPSVO3Jlt1pUbnZuOgtOQJkJkyyJFAlLe7BiT8e9ESzo0zQSx4c3wW4T6kGChmKDPMbWTgtliQA==} engines: {node: '>=12'} cpu: [x64] os: [android] @@ -2418,8 +2419,8 @@ packages: dev: true optional: true - /esbuild-android-arm64/0.15.13: - resolution: {integrity: sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w==} + /esbuild-android-arm64/0.15.16: + resolution: {integrity: sha512-lqfKuofMExL5niNV3gnhMUYacSXfsvzTa/58sDlBET/hCOG99Zmeh+lz6kvdgvGOsImeo6J9SW21rFCogNPLxg==} engines: {node: '>=12'} cpu: [arm64] os: [android] @@ -2435,8 +2436,8 @@ packages: dev: true optional: true - /esbuild-darwin-64/0.15.13: - resolution: {integrity: sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg==} + /esbuild-darwin-64/0.15.16: + resolution: {integrity: sha512-wo2VWk/n/9V2TmqUZ/KpzRjCEcr00n7yahEdmtzlrfQ3lfMCf3Wa+0sqHAbjk3C6CKkR3WKK/whkMq5Gj4Da9g==} engines: {node: '>=12'} cpu: [x64] os: [darwin] @@ -2452,8 +2453,8 @@ packages: dev: true optional: true - /esbuild-darwin-arm64/0.15.13: - resolution: {integrity: sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A==} + /esbuild-darwin-arm64/0.15.16: + resolution: {integrity: sha512-fMXaUr5ou0M4WnewBKsspMtX++C1yIa3nJ5R2LSbLCfJT3uFdcRoU/NZjoM4kOMKyOD9Sa/2vlgN8G07K3SJnw==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] @@ -2469,8 +2470,8 @@ packages: dev: true optional: true - /esbuild-freebsd-64/0.15.13: - resolution: {integrity: sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA==} + /esbuild-freebsd-64/0.15.16: + resolution: {integrity: sha512-UzIc0xlRx5x9kRuMr+E3+hlSOxa/aRqfuMfiYBXu2jJ8Mzej4lGL7+o6F5hzhLqWfWm1GWHNakIdlqg1ayaTNQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] @@ -2486,8 +2487,8 @@ packages: dev: true optional: true - /esbuild-freebsd-arm64/0.15.13: - resolution: {integrity: sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q==} + /esbuild-freebsd-arm64/0.15.16: + resolution: {integrity: sha512-8xyiYuGc0DLZphFQIiYaLHlfoP+hAN9RHbE+Ibh8EUcDNHAqbQgUrQg7pE7Bo00rXmQ5Ap6KFgcR0b4ALZls1g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] @@ -2503,8 +2504,8 @@ packages: dev: true optional: true - /esbuild-linux-32/0.15.13: - resolution: {integrity: sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w==} + /esbuild-linux-32/0.15.16: + resolution: {integrity: sha512-iGijUTV+0kIMyUVoynK0v+32Oi8yyp0xwMzX69GX+5+AniNy/C/AL1MjFTsozRp/3xQPl7jVux/PLe2ds10/2w==} engines: {node: '>=12'} cpu: [ia32] os: [linux] @@ -2520,8 +2521,8 @@ packages: dev: true optional: true - /esbuild-linux-64/0.15.13: - resolution: {integrity: sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A==} + /esbuild-linux-64/0.15.16: + resolution: {integrity: sha512-tuSOjXdLw7VzaUj89fIdAaQT7zFGbKBcz4YxbWrOiXkwscYgE7HtTxUavreBbnRkGxKwr9iT/gmeJWNm4djy/g==} engines: {node: '>=12'} cpu: [x64] os: [linux] @@ -2537,8 +2538,8 @@ packages: dev: true optional: true - /esbuild-linux-arm/0.15.13: - resolution: {integrity: sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ==} + /esbuild-linux-arm/0.15.16: + resolution: {integrity: sha512-XKcrxCEXDTOuoRj5l12tJnkvuxXBMKwEC5j0JISw3ziLf0j4zIwXbKbTmUrKFWbo6ZgvNpa7Y5dnbsjVvH39bQ==} engines: {node: '>=12'} cpu: [arm] os: [linux] @@ -2554,8 +2555,8 @@ packages: dev: true optional: true - /esbuild-linux-arm64/0.15.13: - resolution: {integrity: sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ==} + /esbuild-linux-arm64/0.15.16: + resolution: {integrity: sha512-mPYksnfHnemNrvjrDhZyixL/AfbJN0Xn9S34ZOHYdh6/jJcNd8iTsv3JwJoEvTJqjMggjMhGUPJAdjnFBHoH8A==} engines: {node: '>=12'} cpu: [arm64] os: [linux] @@ -2571,8 +2572,8 @@ packages: dev: true optional: true - /esbuild-linux-mips64le/0.15.13: - resolution: {integrity: sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A==} + /esbuild-linux-mips64le/0.15.16: + resolution: {integrity: sha512-kSJO2PXaxfm0pWY39+YX+QtpFqyyrcp0ZeI8QPTrcFVQoWEPiPVtOfTZeS3ZKedfH+Ga38c4DSzmKMQJocQv6A==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] @@ -2588,8 +2589,8 @@ packages: dev: true optional: true - /esbuild-linux-ppc64le/0.15.13: - resolution: {integrity: sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA==} + /esbuild-linux-ppc64le/0.15.16: + resolution: {integrity: sha512-NimPikwkBY0yGABw6SlhKrtT35sU4O23xkhlrTT/O6lSxv3Pm5iSc6OYaqVAHWkLdVf31bF4UDVFO+D990WpAA==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] @@ -2597,8 +2598,8 @@ packages: dev: true optional: true - /esbuild-linux-riscv64/0.15.13: - resolution: {integrity: sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow==} + /esbuild-linux-riscv64/0.15.16: + resolution: {integrity: sha512-ty2YUHZlwFOwp7pR+J87M4CVrXJIf5ZZtU/umpxgVJBXvWjhziSLEQxvl30SYfUPq0nzeWKBGw5i/DieiHeKfw==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] @@ -2606,8 +2607,8 @@ packages: dev: true optional: true - /esbuild-linux-s390x/0.15.13: - resolution: {integrity: sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag==} + /esbuild-linux-s390x/0.15.16: + resolution: {integrity: sha512-VkZaGssvPDQtx4fvVdZ9czezmyWyzpQhEbSNsHZZN0BHvxRLOYAQ7sjay8nMQwYswP6O2KlZluRMNPYefFRs+w==} engines: {node: '>=12'} cpu: [s390x] os: [linux] @@ -2623,8 +2624,8 @@ packages: dev: true optional: true - /esbuild-netbsd-64/0.15.13: - resolution: {integrity: sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ==} + /esbuild-netbsd-64/0.15.16: + resolution: {integrity: sha512-ElQ9rhdY51et6MJTWrCPbqOd/YuPowD7Cxx3ee8wlmXQQVW7UvQI6nSprJ9uVFQISqSF5e5EWpwWqXZsECLvXg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] @@ -2640,8 +2641,8 @@ packages: dev: true optional: true - /esbuild-openbsd-64/0.15.13: - resolution: {integrity: sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w==} + /esbuild-openbsd-64/0.15.16: + resolution: {integrity: sha512-KgxMHyxMCT+NdLQE1zVJEsLSt2QQBAvJfmUGDmgEq8Fvjrf6vSKB00dVHUEDKcJwMID6CdgCpvYNt999tIYhqA==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] @@ -2668,8 +2669,8 @@ packages: dev: true optional: true - /esbuild-sunos-64/0.15.13: - resolution: {integrity: sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw==} + /esbuild-sunos-64/0.15.16: + resolution: {integrity: sha512-exSAx8Phj7QylXHlMfIyEfNrmqnLxFqLxdQF6MBHPdHAjT7fsKaX6XIJn+aQEFiOcE4X8e7VvdMCJ+WDZxjSRQ==} engines: {node: '>=12'} cpu: [x64] os: [sunos] @@ -2677,7 +2678,7 @@ packages: dev: true optional: true - /esbuild-svelte/0.7.1_bvt7ajmht5nri6yjdkgzgnstui: + /esbuild-svelte/0.7.1_ihq6zb4jn6rs2ewpbixx47bd3m: resolution: {integrity: sha512-83vRAJ2OmoKxmK+rLFZVmyv5bJ8ahsYQwJ2RGmNAlHBIHq4ENUwA/hiwA2+AohrWD1BgZnGPMj8DL3l0I0xkug==} engines: {node: '>=14'} peerDependencies: @@ -2685,7 +2686,7 @@ packages: svelte: '>=3.43.0' dependencies: esbuild: 0.14.0 - svelte: 3.52.0 + svelte: 3.53.1 dev: true /esbuild-windows-32/0.14.0: @@ -2696,8 +2697,8 @@ packages: dev: true optional: true - /esbuild-windows-32/0.15.13: - resolution: {integrity: sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA==} + /esbuild-windows-32/0.15.16: + resolution: {integrity: sha512-zQgWpY5pUCSTOwqKQ6/vOCJfRssTvxFuEkpB4f2VUGPBpdddZfdj8hbZuFRdZRPIVHvN7juGcpgCA/XCF37mAQ==} engines: {node: '>=12'} cpu: [ia32] os: [win32] @@ -2713,8 +2714,8 @@ packages: dev: true optional: true - /esbuild-windows-64/0.15.13: - resolution: {integrity: sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ==} + /esbuild-windows-64/0.15.16: + resolution: {integrity: sha512-HjW1hHRLSncnM3MBCP7iquatHVJq9l0S2xxsHHj4yzf4nm9TU4Z7k4NkeMlD/dHQ4jPlQQhwcMvwbJiOefSuZw==} engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -2730,8 +2731,8 @@ packages: dev: true optional: true - /esbuild-windows-arm64/0.15.13: - resolution: {integrity: sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg==} + /esbuild-windows-arm64/0.15.16: + resolution: {integrity: sha512-oCcUKrJaMn04Vxy9Ekd8x23O8LoU01+4NOkQ2iBToKgnGj5eo1vU9i27NQZ9qC8NFZgnQQZg5oZWAejmbsppNA==} engines: {node: '>=12'} cpu: [arm64] os: [win32] @@ -2763,34 +2764,34 @@ packages: esbuild-windows-arm64: 0.14.0 dev: true - /esbuild/0.15.13: - resolution: {integrity: sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ==} + /esbuild/0.15.16: + resolution: {integrity: sha512-o6iS9zxdHrrojjlj6pNGC2NAg86ECZqIETswTM5KmJitq+R1YmahhWtMumeQp9lHqJaROGnsBi2RLawGnfo5ZQ==} engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - '@esbuild/android-arm': 0.15.13 - '@esbuild/linux-loong64': 0.15.13 - esbuild-android-64: 0.15.13 - esbuild-android-arm64: 0.15.13 - esbuild-darwin-64: 0.15.13 - esbuild-darwin-arm64: 0.15.13 - esbuild-freebsd-64: 0.15.13 - esbuild-freebsd-arm64: 0.15.13 - esbuild-linux-32: 0.15.13 - esbuild-linux-64: 0.15.13 - esbuild-linux-arm: 0.15.13 - esbuild-linux-arm64: 0.15.13 - esbuild-linux-mips64le: 0.15.13 - esbuild-linux-ppc64le: 0.15.13 - esbuild-linux-riscv64: 0.15.13 - esbuild-linux-s390x: 0.15.13 - esbuild-netbsd-64: 0.15.13 - esbuild-openbsd-64: 0.15.13 - esbuild-sunos-64: 0.15.13 - esbuild-windows-32: 0.15.13 - esbuild-windows-64: 0.15.13 - esbuild-windows-arm64: 0.15.13 + '@esbuild/android-arm': 0.15.16 + '@esbuild/linux-loong64': 0.15.16 + esbuild-android-64: 0.15.16 + esbuild-android-arm64: 0.15.16 + esbuild-darwin-64: 0.15.16 + esbuild-darwin-arm64: 0.15.16 + esbuild-freebsd-64: 0.15.16 + esbuild-freebsd-arm64: 0.15.16 + esbuild-linux-32: 0.15.16 + esbuild-linux-64: 0.15.16 + esbuild-linux-arm: 0.15.16 + esbuild-linux-arm64: 0.15.16 + esbuild-linux-mips64le: 0.15.16 + esbuild-linux-ppc64le: 0.15.16 + esbuild-linux-riscv64: 0.15.16 + esbuild-linux-s390x: 0.15.16 + esbuild-netbsd-64: 0.15.16 + esbuild-openbsd-64: 0.15.16 + esbuild-sunos-64: 0.15.16 + esbuild-windows-32: 0.15.16 + esbuild-windows-64: 0.15.16 + esbuild-windows-arm64: 0.15.16 dev: true /escalade/3.1.1: @@ -3022,7 +3023,7 @@ packages: array-union: 2.1.0 dir-glob: 3.0.1 fast-glob: 3.2.12 - ignore: 5.2.0 + ignore: 5.2.1 merge2: 1.4.1 slash: 3.0.0 dev: true @@ -3122,8 +3123,8 @@ packages: resolution: {integrity: sha512-slx8Q6oywCCSfKgPgL0sEsXtPVnSbTLWpyiDcu6msHOyKOLari1TD1qocXVCft80umnkk3/Qqh3lwoFt8T/BPQ==} dev: false - /ignore/5.2.0: - resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} + /ignore/5.2.1: + resolution: {integrity: sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==} engines: {node: '>= 4'} dev: true @@ -3339,8 +3340,8 @@ packages: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.20.2 - '@babel/parser': 7.20.2 + '@babel/core': 7.20.5 + '@babel/parser': 7.20.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 semver: 6.3.0 @@ -3392,7 +3393,7 @@ packages: '@jest/environment': 27.5.1 '@jest/test-result': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.3 + '@types/node': 16.18.4 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 @@ -3406,7 +3407,7 @@ packages: jest-util: 27.5.1 pretty-format: 27.5.1 slash: 3.0.0 - stack-utils: 2.0.5 + stack-utils: 2.0.6 throat: 6.0.1 transitivePeerDependencies: - supports-color @@ -3451,12 +3452,12 @@ packages: ts-node: optional: true dependencies: - '@babel/core': 7.20.2 + '@babel/core': 7.20.5 '@jest/test-sequencer': 27.5.1 '@jest/types': 27.5.1 - babel-jest: 27.5.1_@babel+core@7.20.2 + babel-jest: 27.5.1_@babel+core@7.20.5 chalk: 4.1.2 - ci-info: 3.5.0 + ci-info: 3.7.0 deepmerge: 4.2.2 glob: 7.2.3 graceful-fs: 4.2.10 @@ -3517,7 +3518,7 @@ packages: '@jest/environment': 27.5.1 '@jest/fake-timers': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.3 + '@types/node': 16.18.4 jest-mock: 27.5.1 jest-util: 27.5.1 jsdom: 16.7.0 @@ -3535,7 +3536,7 @@ packages: '@jest/environment': 27.5.1 '@jest/fake-timers': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.3 + '@types/node': 16.18.4 jest-mock: 27.5.1 jest-util: 27.5.1 dev: true @@ -3551,8 +3552,8 @@ packages: dependencies: '@jest/types': 27.5.1 '@types/graceful-fs': 4.1.5 - '@types/node': 16.18.3 - anymatch: 3.1.2 + '@types/node': 16.18.4 + anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.10 jest-regex-util: 27.5.1 @@ -3573,7 +3574,7 @@ packages: '@jest/source-map': 27.5.1 '@jest/test-result': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.3 + '@types/node': 16.18.4 chalk: 4.1.2 co: 4.6.0 expect: 27.5.1 @@ -3620,7 +3621,7 @@ packages: micromatch: 4.0.5 pretty-format: 27.5.1 slash: 3.0.0 - stack-utils: 2.0.5 + stack-utils: 2.0.6 dev: true /jest-mock/27.5.1: @@ -3628,11 +3629,11 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 16.18.3 + '@types/node': 16.18.4 dev: true - /jest-pnp-resolver/1.2.2_jest-resolve@27.5.1: - resolution: {integrity: sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==} + /jest-pnp-resolver/1.2.3_jest-resolve@27.5.1: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} engines: {node: '>=6'} peerDependencies: jest-resolve: '*' @@ -3667,7 +3668,7 @@ packages: chalk: 4.1.2 graceful-fs: 4.2.10 jest-haste-map: 27.5.1 - jest-pnp-resolver: 1.2.2_jest-resolve@27.5.1 + jest-pnp-resolver: 1.2.3_jest-resolve@27.5.1 jest-util: 27.5.1 jest-validate: 27.5.1 resolve: 1.22.1 @@ -3684,7 +3685,7 @@ packages: '@jest/test-result': 27.5.1 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.3 + '@types/node': 16.18.4 chalk: 4.1.2 emittery: 0.8.1 graceful-fs: 4.2.10 @@ -3741,7 +3742,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.18.3 + '@types/node': 16.18.4 graceful-fs: 4.2.10 dev: true @@ -3749,16 +3750,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.20.2 - '@babel/generator': 7.20.2 - '@babel/plugin-syntax-typescript': 7.20.0_@babel+core@7.20.2 - '@babel/traverse': 7.20.1 - '@babel/types': 7.20.2 + '@babel/core': 7.20.5 + '@babel/generator': 7.20.5 + '@babel/plugin-syntax-typescript': 7.20.0_@babel+core@7.20.5 + '@babel/traverse': 7.20.5 + '@babel/types': 7.20.5 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/babel__traverse': 7.18.2 + '@types/babel__traverse': 7.18.3 '@types/prettier': 2.7.1 - babel-preset-current-node-syntax: 1.0.1_@babel+core@7.20.2 + babel-preset-current-node-syntax: 1.0.1_@babel+core@7.20.5 chalk: 4.1.2 expect: 27.5.1 graceful-fs: 4.2.10 @@ -3780,9 +3781,9 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 16.18.3 + '@types/node': 16.18.4 chalk: 4.1.2 - ci-info: 3.5.0 + ci-info: 3.7.0 graceful-fs: 4.2.10 picomatch: 2.3.1 dev: true @@ -3805,7 +3806,7 @@ packages: dependencies: '@jest/test-result': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.3 + '@types/node': 16.18.4 ansi-escapes: 4.3.2 chalk: 4.1.2 jest-util: 27.5.1 @@ -3816,7 +3817,7 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 16.18.3 + '@types/node': 16.18.4 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true @@ -4039,6 +4040,10 @@ packages: resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==} dev: true + /minisearch/6.0.0-beta.1: + resolution: {integrity: sha512-/qHyE4qBbBtli/zgR8H/Dus3cOxQdTciglY/QEyU6FDGCd4lRtYWwkhJ/yDXZvblFXoWwYILu3qCFqsTtF53+g==} + dev: false + /mkdirp/0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -4131,8 +4136,8 @@ packages: object-keys: 1.1.1 dev: true - /obsidian-text-extract/1.0.3: - resolution: {integrity: sha512-nqIfKfAV3vCn5jFl77iJQOqM9fTik3cESroeMENbr3q/1R6hj0ancJISw6/fIMRwWb50zVra51cWqL+rPZCDMQ==} + /obsidian-text-extract/1.0.4: + resolution: {integrity: sha512-lJ7HaEPGUoGVYr6iCSEU8oPrnA8xRBQgSU9KryWteq3wO+Yiw2Zue70G0rZf9Yj+DkgR92PtuR8aQZQxTy/uLA==} dependencies: dexie: 3.2.2 p-limit: 4.0.0 @@ -4275,8 +4280,8 @@ packages: find-up: 4.1.0 dev: true - /postcss/8.4.18: - resolution: {integrity: sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==} + /postcss/8.4.19: + resolution: {integrity: sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==} engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.4 @@ -4289,18 +4294,18 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /prettier-plugin-svelte/2.8.0_lrllcp5xtrkmmdzifit4hd52ze: - resolution: {integrity: sha512-QlXv/U3bUszks3XYDPsk1fsaQC+fo2lshwKbcbO+lrSVdJ+40mB1BfL8OCAk1W9y4pJxpqO/4gqm6NtF3zNGCw==} + /prettier-plugin-svelte/2.8.1_3ndnxlh52lolrqe4kgjgbxb3xa: + resolution: {integrity: sha512-KA3K1J3/wKDnCxW7ZDRA/QL2Q67N7Xs3gOERqJ5X1qFjq1DdnN3K1R29scSKwh+kA8FF67pXbYytUpvN/i3iQw==} peerDependencies: prettier: ^1.16.4 || ^2.0.0 svelte: ^3.2.0 dependencies: - prettier: 2.7.1 - svelte: 3.52.0 + prettier: 2.8.0 + svelte: 3.53.1 dev: true - /prettier/2.7.1: - resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==} + /prettier/2.8.0: + resolution: {integrity: sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==} engines: {node: '>=10.13.0'} hasBin: true dev: true @@ -4373,13 +4378,13 @@ packages: resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} dev: true - /regenerator-runtime/0.13.10: - resolution: {integrity: sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==} + /regenerator-runtime/0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - /regenerator-transform/0.15.0: - resolution: {integrity: sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==} + /regenerator-transform/0.15.1: + resolution: {integrity: sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==} dependencies: - '@babel/runtime': 7.20.1 + '@babel/runtime': 7.20.6 dev: true /regexp.prototype.flags/1.4.3: @@ -4391,8 +4396,8 @@ packages: functions-have-names: 1.2.3 dev: true - /regexpu-core/5.2.1: - resolution: {integrity: sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==} + /regexpu-core/5.2.2: + resolution: {integrity: sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==} engines: {node: '>=4'} dependencies: regenerate: 1.4.2 @@ -4400,7 +4405,7 @@ packages: regjsgen: 0.7.1 regjsparser: 0.9.1 unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.1.0 dev: true /regjsgen/0.7.1: @@ -4604,8 +4609,8 @@ packages: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true - /stack-utils/2.0.5: - resolution: {integrity: sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==} + /stack-utils/2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} dependencies: escape-string-regexp: 2.0.0 @@ -4689,8 +4694,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - /svelte-check/2.9.2_svelte@3.52.0: - resolution: {integrity: sha512-DRi8HhnCiqiGR2YF9ervPGvtoYrheE09cXieCTEqeTPOTJzfoa54Py8rovIBv4bH4n5HgZYIyTQ3DDLHQLl2uQ==} + /svelte-check/2.10.0_svelte@3.53.1: + resolution: {integrity: sha512-5iLCoja/WsithyRkNtIeDQ0euJlgWj3Zzo2IA6iuHMuuX9D9OrRYZj2WlA5ACnAFQnN5L9mxWcwUW9VxDNEoGg==} hasBin: true peerDependencies: svelte: ^3.24.0 @@ -4701,9 +4706,9 @@ packages: import-fresh: 3.3.0 picocolors: 1.0.0 sade: 1.8.1 - svelte: 3.52.0 - svelte-preprocess: 4.10.7_besnmoibwkhwtentvwuriss7pa - typescript: 4.8.4 + svelte: 3.53.1 + svelte-preprocess: 4.10.7_7dvewpees4iyn2tkw2qzal77a4 + typescript: 4.9.3 transitivePeerDependencies: - '@babel/core' - coffeescript @@ -4717,7 +4722,7 @@ packages: - sugarss dev: true - /svelte-jester/2.3.2_jest@27.5.1+svelte@3.52.0: + /svelte-jester/2.3.2_jest@27.5.1+svelte@3.53.1: resolution: {integrity: sha512-JtxSz4FWAaCRBXbPsh4LcDs4Ua7zdXgLC0TZvT1R56hRV0dymmNP+abw67DTPF7sQPyNxWsOKd0Sl7Q8SnP8kg==} engines: {node: '>=14'} peerDependencies: @@ -4725,10 +4730,10 @@ packages: svelte: '>= 3' dependencies: jest: 27.5.1 - svelte: 3.52.0 + svelte: 3.53.1 dev: true - /svelte-preprocess/4.10.7_besnmoibwkhwtentvwuriss7pa: + /svelte-preprocess/4.10.7_7dvewpees4iyn2tkw2qzal77a4: resolution: {integrity: sha512-sNPBnqYD6FnmdBrUmBCaqS00RyCsCpj2BG58A1JBswNF7b0OKviwxqVrOL/CKyJrLSClrSeqQv5BXNg2RUbPOw==} engines: {node: '>= 9.11.2'} requiresBuild: true @@ -4775,12 +4780,12 @@ packages: magic-string: 0.25.9 sorcery: 0.10.0 strip-indent: 3.0.0 - svelte: 3.52.0 - typescript: 4.8.4 + svelte: 3.53.1 + typescript: 4.9.3 dev: true - /svelte/3.52.0: - resolution: {integrity: sha512-FxcnEUOAVfr10vDU5dVgJN19IvqeHQCS1zfe8vayTfis9A2t5Fhx+JDe5uv/C3j//bB1umpLJ6quhgs9xyUbCQ==} + /svelte/3.53.1: + resolution: {integrity: sha512-Q4/hHkktZogGhN5iqxqSi9sjEVoe/NbIxX4hXEHoasTxj+TxEQVAq66LnDMdAZxjmsodkoI5F3slqsS68U7FNw==} engines: {node: '>= 8'} dev: true @@ -4812,7 +4817,7 @@ packages: is-url: 1.2.4 node-fetch: 2.6.7 opencollective-postinstall: 2.0.3 - regenerator-runtime: 0.13.10 + regenerator-runtime: 0.13.11 resolve-url: 0.2.1 tesseract.js-core: 3.0.2 wasm-feature-detect: 1.3.0 @@ -4899,8 +4904,8 @@ packages: is-typedarray: 1.0.0 dev: true - /typescript/4.8.4: - resolution: {integrity: sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==} + /typescript/4.9.3: + resolution: {integrity: sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==} engines: {node: '>=4.2.0'} hasBin: true dev: true @@ -4918,8 +4923,8 @@ packages: unicode-property-aliases-ecmascript: 2.1.0 dev: true - /unicode-match-property-value-ecmascript/2.0.0: - resolution: {integrity: sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==} + /unicode-match-property-value-ecmascript/2.1.0: + resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} engines: {node: '>=4'} dev: true @@ -4965,17 +4970,20 @@ packages: source-map: 0.7.4 dev: true - /vite/3.2.2: - resolution: {integrity: sha512-pLrhatFFOWO9kS19bQ658CnRYzv0WLbsPih6R+iFeEEhDOuYgYCX2rztUViMz/uy/V8cLCJvLFeiOK7RJEzHcw==} + /vite/3.2.4_@types+node@16.18.4: + resolution: {integrity: sha512-Z2X6SRAffOUYTa+sLy3NQ7nlHFU100xwanq1WDwqaiFiCe+25zdxP1TfCS5ojPV2oDDcXudHIoPnI1Z/66B7Yw==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true peerDependencies: + '@types/node': '>= 14' less: '*' sass: '*' stylus: '*' sugarss: '*' terser: ^5.4.0 peerDependenciesMeta: + '@types/node': + optional: true less: optional: true sass: @@ -4987,8 +4995,9 @@ packages: terser: optional: true dependencies: - esbuild: 0.15.13 - postcss: 8.4.18 + '@types/node': 16.18.4 + esbuild: 0.15.16 + postcss: 8.4.19 resolve: 1.22.1 rollup: 2.79.1 optionalDependencies: @@ -5181,9 +5190,3 @@ packages: /zlibjs/0.3.1: resolution: {integrity: sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==} dev: false - - github.com/scambier/minisearch/adf11cab46d851220a41c9ad95ed986b630f0f3c: - resolution: {tarball: https://codeload.github.com/scambier/minisearch/tar.gz/adf11cab46d851220a41c9ad95ed986b630f0f3c} - name: minisearch - version: 5.0.0 - dev: false diff --git a/src/cache-manager.ts b/src/cache-manager.ts index a71eac1..64e4834 100644 --- a/src/cache-manager.ts +++ b/src/cache-manager.ts @@ -1,17 +1,102 @@ -import { Notice, type TFile } from 'obsidian' -import type { IndexedDocument } from './globals' +import { Notice } from 'obsidian' +import type { DocumentRef, IndexedDocument } from './globals' import { database } from './database' -import MiniSearch from 'minisearch' -import { minisearchOptions } from './search/search-engine' -import { makeMD5 } from './tools/utils' +import type { AsPlainObject } from 'minisearch' +import type MiniSearch from 'minisearch' +import { + extractHeadingsFromCache, + getAliasesFromMetadata, + getTagsFromMetadata, + isFileImage, + isFilePDF, + isFilePlaintext, + makeMD5, + removeDiacritics, +} from './tools/utils' +import { getImageText, getPdfText } from 'obsidian-text-extract' + +async function getIndexedDocument(path: string): Promise { + const file = app.vault.getFiles().find(f => f.path === path) + if (!file) throw new Error(`Invalid file path: "${path}"`) + let content: string + if (isFilePlaintext(path)) { + content = await app.vault.cachedRead(file) + } else if (isFilePDF(path)) { + content = await getPdfText(file) + } else if (isFileImage(file.path)) { + content = await getImageText(file) + } else { + throw new Error('Invalid file format: ' + file.path) + } + content = removeDiacritics(content) + const metadata = app.metadataCache.getFileCache(file) + + // Look for links that lead to non-existing files, + // and add them to the index. + if (metadata) { + // // FIXME: https://github.com/scambier/obsidian-omnisearch/issues/129 + // const nonExisting = getNonExistingNotes(file, metadata) + // for (const name of nonExisting.filter( + // o => !cacheManager.getLiveDocument(o) + // )) { + // NotesIndex.addNonExistingToIndex(name, file.path) + // } + + // EXCALIDRAW + // Remove the json code + if (metadata.frontmatter?.['excalidraw-plugin']) { + const comments = + metadata.sections?.filter(s => s.type === 'comment') ?? [] + for (const { start, end } of comments.map(c => c.position)) { + content = + content.substring(0, start.offset - 1) + content.substring(end.offset) + } + } + } + + return { + basename: removeDiacritics(file.basename), + content, + path: file.path, + mtime: file.stat.mtime, + + tags: getTagsFromMetadata(metadata), + aliases: getAliasesFromMetadata(metadata).join(''), + headings1: metadata ? extractHeadingsFromCache(metadata, 1).join(' ') : '', + headings2: metadata ? extractHeadingsFromCache(metadata, 2).join(' ') : '', + headings3: metadata ? extractHeadingsFromCache(metadata, 3).join(' ') : '', + } +} class CacheManager { - private liveDocuments: Map = new Map() /** * Show an empty input field next time the user opens Omnisearch modal */ private nextQueryIsEmpty = false + /** + * The "live cache", containing all indexed vault files + * in the form of IndexedDocuments + */ + private documents: Map = new Map() + + public async addToLiveCache(path: string): Promise { + const doc = await getIndexedDocument(path) + this.documents.set(path, doc) + } + + public removeFromLiveCache(path: string): void { + this.documents.delete(path) + } + + public async getDocument(path: string): Promise { + if (this.documents.has(path)) { + return this.documents.get(path)! + } + await this.addToLiveCache(path) + return this.documents.get(path)! + } + public async addToSearchHistory(query: string): Promise { if (!query) { this.nextQueryIsEmpty = true @@ -36,32 +121,6 @@ class CacheManager { return data } - /** - * Important: keep this method async for the day it _really_ becomes async. - * This will avoid a refactor. - * @param path - * @param note - */ - public async updateLiveDocument( - path: string, - note: IndexedDocument - ): Promise { - this.liveDocuments.set(path, note) - } - - public deleteLiveDocument(key: string): void { - this.liveDocuments.delete(key) - } - - public getLiveDocument(key: string): IndexedDocument | undefined { - return this.liveDocuments.get(key) - } - - public isDocumentOutdated(file: TFile): boolean { - const indexedNote = this.getLiveDocument(file.path) - return !indexedNote || indexedNote.mtime !== file.stat.mtime - } - //#region Minisearch public getDocumentsChecksum(documents: IndexedDocument[]): string { @@ -79,28 +138,13 @@ class CacheManager { ) } - public async getMinisearchCache(): Promise { - // Retrieve documents and make their checksum - const cachedDocs = await database.documents.toArray() - const checksum = this.getDocumentsChecksum(cachedDocs.map(d => d.document)) - - // Add those documents in the live cache - cachedDocs.forEach(doc => - cacheManager.updateLiveDocument(doc.path, doc.document) - ) - - // Retrieve the search cache, and verify the checksum - const cachedIndex = (await database.minisearch.toArray())[0] - if (cachedIndex?.checksum !== checksum) { - console.warn("Omnisearch - Cache - Checksums don't match, clearing cache") - // Invalid (or null) cache, clear everything - await database.minisearch.clear() - await database.documents.clear() - return null - } - + public async getMinisearchCache(): Promise<{ + paths: DocumentRef[] + data: AsPlainObject + } | null> { try { - return MiniSearch.loadJS(cachedIndex.data, minisearchOptions) + const cachedIndex = (await database.minisearch.toArray())[0] + return cachedIndex } catch (e) { new Notice( 'Omnisearch - Cache missing or invalid. Some freezes may occur while Omnisearch indexes your vault.' @@ -111,75 +155,15 @@ class CacheManager { } } - /** - * Get a dict listing the deleted/added documents since last cache - * @param documents - */ - public async getDiffDocuments(documents: IndexedDocument[]): Promise<{ - toDelete: IndexedDocument[] - toAdd: IndexedDocument[] - toUpdate: { oldDoc: IndexedDocument; newDoc: IndexedDocument }[] - }> { - let cachedDocs = await database.documents.toArray() - // present in `documents` but not in `cachedDocs` - const toAdd = documents.filter( - d => !cachedDocs.find(c => c.path === d.path) - ) - // present in `cachedDocs` but not in `documents` - const toDelete = cachedDocs - .filter(c => !documents.find(d => d.path === c.path)) - .map(d => d.document) - - // toUpdate: same path, but different mtime - const toUpdate = cachedDocs - .filter(({ mtime: cMtime, path: cPath }) => - documents.some( - ({ mtime: dMtime, path: dPath }) => - cPath === dPath && dMtime !== cMtime - ) - ) - .map(c => ({ - oldDoc: c.document, - newDoc: documents.find(d => d.path === c.path)!, - })) - - return { - toAdd, - toDelete, - toUpdate, - } - } - public async writeMinisearchCache( minisearch: MiniSearch, - documents: IndexedDocument[] + indexed: Map ): Promise { - const { toDelete, toAdd, toUpdate } = await this.getDiffDocuments(documents) - - // Delete - // console.log(`Omnisearch - Cache - Will delete ${toDelete.length} documents`) - await database.documents.bulkDelete(toDelete.map(o => o.path)) - - // Add - // console.log(`Omnisearch - Cache - Will add ${toAdd.length} documents`) - await database.documents.bulkAdd( - toAdd.map(o => ({ document: o, mtime: o.mtime, path: o.path })) - ) - - // Update - // console.log(`Omnisearch - Cache - Will update ${toUpdate.length} documents`) - await database.documents.bulkPut( - toUpdate.map(o => ({ - document: o.newDoc, - mtime: o.newDoc.mtime, - path: o.newDoc.path, - })) - ) - + const paths = Array.from(indexed).map(([k, v]) => ({ path: k, mtime: v })) await database.minisearch.clear() await database.minisearch.add({ date: new Date().toISOString(), - checksum: this.getDocumentsChecksum(documents), + paths, data: minisearch.toJSON(), }) console.log('Omnisearch - Search cache written') diff --git a/src/components/InputSearch.svelte b/src/components/InputSearch.svelte index fa839e2..72b23c4 100644 --- a/src/components/InputSearch.svelte +++ b/src/components/InputSearch.svelte @@ -32,7 +32,7 @@ // the next time we open the modal, the search field will be empty cacheManager.addToSearchHistory('') dispatch('input', value) - }, 200) + }, 500)
diff --git a/src/components/ModalInFile.svelte b/src/components/ModalInFile.svelte index 868d301..40bec1b 100644 --- a/src/components/ModalInFile.svelte +++ b/src/components/ModalInFile.svelte @@ -9,7 +9,6 @@ import { loopIndex } from 'src/tools/utils' import { onDestroy, onMount, tick } from 'svelte' import { MarkdownView } from 'obsidian' - import { SearchEngine } from 'src/search/search-engine' import ModalContainer from './ModalContainer.svelte' import { OmnisearchInFileModal, @@ -18,6 +17,7 @@ import ResultItemInFile from './ResultItemInFile.svelte' import { Query } from 'src/search/query' import { openNote } from 'src/tools/notes' + import { searchEngine } from 'src/search/omnisearch' export let modal: OmnisearchInFileModal export let parent: OmnisearchVaultModal | null = null @@ -50,7 +50,7 @@ query = new Query(searchQuery) note = ( - await SearchEngine.getEngine().getSuggestions(query, { + await searchEngine.getSuggestions(query, { singleFilePath, }) )[0] ?? null diff --git a/src/components/ModalVault.svelte b/src/components/ModalVault.svelte index 1805204..c92bd25 100644 --- a/src/components/ModalVault.svelte +++ b/src/components/ModalVault.svelte @@ -3,19 +3,16 @@ import { onDestroy, onMount, tick } from 'svelte' import InputSearch from './InputSearch.svelte' import ModalContainer from './ModalContainer.svelte' - import { eventBus, IndexingStep, type ResultNote } from 'src/globals' + import { eventBus, indexingStep, IndexingStepType, type ResultNote, } from 'src/globals' import { createNote, openNote } from 'src/tools/notes' - import { SearchEngine } from 'src/search/search-engine' - import { getCtrlKeyLabel, getExtension, loopIndex } from 'src/tools/utils' - import { - OmnisearchInFileModal, - type OmnisearchVaultModal, - } from 'src/components/modals' + import { getCtrlKeyLabel, getExtension, isFilePDF, loopIndex, } from 'src/tools/utils' + import { OmnisearchInFileModal, type OmnisearchVaultModal, } from 'src/components/modals' import ResultItemVault from './ResultItemVault.svelte' import { Query } from 'src/search/query' import { settings } from '../settings' import * as NotesIndex from '../notes-index' import { cacheManager } from '../cache-manager' + import { searchEngine } from 'src/search/omnisearch' export let modal: OmnisearchVaultModal export let previousQuery: string | undefined @@ -24,32 +21,34 @@ let searchQuery: string | undefined let resultNotes: ResultNote[] = [] let query: Query - let { indexingStep } = SearchEngine let indexingStepDesc = '' + let searching = true $: selectedNote = resultNotes[selectedIndex] $: searchQuery = searchQuery ?? previousQuery $: if (searchQuery) { - updateResults() + resultNotes = [] + searching = true + updateResults().then(() => { + searching = false + }) } else { + searching = false resultNotes = [] } $: { switch ($indexingStep) { - case IndexingStep.LoadingCache: + case IndexingStepType.LoadingCache: indexingStepDesc = 'Loading cache...' break - case IndexingStep.ReadingNotes: + case IndexingStepType.ReadingFiles: + indexingStepDesc = 'Reading files...' + break + case IndexingStepType.IndexingFiles: + indexingStepDesc = 'Indexing files...' + break + case IndexingStepType.WritingCache: updateResults() - indexingStepDesc = 'Reading notes...' - break - case IndexingStep.ReadingPDFs: - indexingStepDesc = 'Reading PDFs...' - break - case IndexingStep.ReadingImages: - indexingStepDesc = 'Reading images...' - break - case IndexingStep.UpdatingCache: indexingStepDesc = 'Updating cache...' break default: @@ -99,7 +98,7 @@ async function updateResults() { query = new Query(searchQuery) - resultNotes = (await SearchEngine.getEngine().getSuggestions(query)).sort( + resultNotes = (await searchEngine.getSuggestions(query)).sort( (a, b) => b.score - a.score ) selectedIndex = 0 @@ -139,7 +138,7 @@ openNote(note, newPane) } - async function onClickCreateNote(e: MouseEvent) { + async function onClickCreateNote(_e: MouseEvent) { await createNoteAndCloseModal() } @@ -189,7 +188,7 @@ function switchToInFileModal(): void { // Do nothing if the selectedNote is a PDF, // or if there is 0 match (e.g indexing in progress) - if (selectedNote?.path.endsWith('.pdf') || !selectedNote?.matches.length) { + if (selectedNote && (isFilePDF(selectedNote?.path) || !selectedNote?.matches.length)) { return } @@ -250,11 +249,13 @@ on:mousemove="{_ => (selectedIndex = i)}" on:click="{onClick}" /> {/each} - {#if !resultNotes.length && searchQuery} -
+
+ {#if !resultNotes.length && searchQuery && !searching} We found 0 result for your search here. -
- {/if} + {:else if searching} + Searching... + {/if} +
diff --git a/src/components/ResultItemVault.svelte b/src/components/ResultItemVault.svelte index 75bf665..f4c9196 100644 --- a/src/components/ResultItemVault.svelte +++ b/src/components/ResultItemVault.svelte @@ -1,5 +1,4 @@ diff --git a/src/components/modals.ts b/src/components/modals.ts index 4ac5c09..7b16729 100644 --- a/src/components/modals.ts +++ b/src/components/modals.ts @@ -35,7 +35,7 @@ abstract class OmnisearchModal extends Modal { { k: 'K', dir: 'up' }, ] as const) { for (const modifier of ['Ctrl', 'Mod'] as const) { - this.scope.register([modifier], key.k, e => { + this.scope.register([modifier], key.k, _e => { if (this.app.vault.getConfig('vimMode')) { // e.preventDefault() eventBus.emit('arrow-' + key.dir) @@ -50,7 +50,7 @@ abstract class OmnisearchModal extends Modal { { k: 'P', dir: 'up' }, ] as const) { for (const modifier of ['Ctrl', 'Mod'] as const) { - this.scope.register([modifier], key.k, e => { + this.scope.register([modifier], key.k, _e => { if (this.app.vault.getConfig('vimMode')) { // e.preventDefault() eventBus.emit('arrow-' + key.dir) @@ -108,7 +108,7 @@ abstract class OmnisearchModal extends Modal { }) // Context - this.scope.register(['Ctrl'], 'H', e => { + this.scope.register(['Ctrl'], 'H', _e => { eventBus.emit(EventNames.ToggleExcerpts) }) } diff --git a/src/database.ts b/src/database.ts index eb94ea4..e9ce767 100644 --- a/src/database.ts +++ b/src/database.ts @@ -1,13 +1,34 @@ import Dexie from 'dexie' import type { AsPlainObject } from 'minisearch' -import type { IndexedDocument } from './globals' +import type { DocumentRef, IndexedDocument } from './globals' export class OmnisearchCache extends Dexie { - public static readonly dbVersion = 7 + public static readonly dbVersion = 8 public static readonly dbName = 'omnisearch/cache/' + app.appId private static instance: OmnisearchCache + searchHistory!: Dexie.Table<{ id?: number; query: string }, number> + minisearch!: Dexie.Table< + { + date: string + paths: DocumentRef[] + data: AsPlainObject + }, + string + > + + private constructor() { + super(OmnisearchCache.dbName) + // Database structure + this.version(OmnisearchCache.dbVersion).stores({ + searchHistory: '++id', + minisearch: 'date', + }) + } + + //#endregion Table declarations + /** * Deletes Omnisearch databases that have an older version than the current one */ @@ -22,27 +43,12 @@ export class OmnisearchCache extends Dexie { console.log('Omnisearch - Those IndexedDb databases will be deleted:') for (const db of toDelete) { if (db.name) { - console.log(db.name + ' ' + db.version) indexedDB.deleteDatabase(db.name) } } } } - //#region Table declarations - - documents!: Dexie.Table< - { path: string; mtime: number; document: IndexedDocument }, - string - > - searchHistory!: Dexie.Table<{ id?: number; query: string }, number> - minisearch!: Dexie.Table< - { date: string; checksum: string; data: AsPlainObject }, - string - > - - //#endregion Table declarations - public static getInstance() { if (!OmnisearchCache.instance) { OmnisearchCache.instance = new OmnisearchCache() @@ -50,19 +56,8 @@ export class OmnisearchCache extends Dexie { return OmnisearchCache.instance } - private constructor() { - super(OmnisearchCache.dbName) - // Database structure - this.version(OmnisearchCache.dbVersion).stores({ - searchHistory: '++id', - documents: 'path', - minisearch: 'date', - }) - } - public async clearCache() { await this.minisearch.clear() - await this.documents.clear() } } diff --git a/src/file-loader.ts b/src/file-loader.ts index f8cb0f3..503735f 100644 --- a/src/file-loader.ts +++ b/src/file-loader.ts @@ -1,17 +1,7 @@ -import { cacheManager } from './cache-manager' -import { - extractHeadingsFromCache, - getAliasesFromMetadata, - getTagsFromMetadata, - isFileImage, - isFilePlaintext, - removeDiacritics, -} from './tools/utils' -import * as NotesIndex from './notes-index' +import { isFileImage, isFilePDF, isFilePlaintext } from './tools/utils' import type { TFile } from 'obsidian' import type { IndexedDocument } from './globals' -import { getNonExistingNotes } from './tools/notes' -import { getPdfText, getImageText } from 'obsidian-text-extract' +import { cacheManager } from './cache-manager' /** * Return all plaintext files as IndexedDocuments @@ -20,9 +10,9 @@ export async function getPlainTextFiles(): Promise { const allFiles = app.vault.getFiles().filter(f => isFilePlaintext(f.path)) const data: IndexedDocument[] = [] for (const file of allFiles) { - const doc = await fileToIndexedDocument(file) + const doc = await cacheManager.getDocument(file.path) data.push(doc) - await cacheManager.updateLiveDocument(file.path, doc) + // await cacheManager.updateLiveDocument(file.path, doc) } return data } @@ -31,7 +21,7 @@ export async function getPlainTextFiles(): Promise { * Return all PDFs as IndexedDocuments. */ export async function getPDFAsDocuments(): Promise { - const files = app.vault.getFiles().filter(f => f.path.endsWith('.pdf')) + const files = app.vault.getFiles().filter(f => isFilePDF(f.path)) return await getBinaryFiles(files) } @@ -48,9 +38,8 @@ async function getBinaryFiles(files: TFile[]): Promise { const input = [] for (const file of files) { input.push( - new Promise(async (resolve, reject) => { - const doc = await fileToIndexedDocument(file) - await cacheManager.updateLiveDocument(file.path, doc) + new Promise(async (resolve, _reject) => { + const doc = await cacheManager.getDocument(file.path) data.push(doc) return resolve(null) }) @@ -59,61 +48,3 @@ async function getBinaryFiles(files: TFile[]): Promise { await Promise.all(input) return data } - -/** - * Convert a file into an IndexedDocument. - * Will use the cache if possible. - */ -export async function fileToIndexedDocument( - file: TFile -): Promise { - let content: string - if (isFilePlaintext(file.path)) { - content = await app.vault.cachedRead(file) - } else if (file.path.endsWith('.pdf')) { - content = await getPdfText(file) - } else if (isFileImage(file.path)) { - content = await getImageText(file) - } else { - throw new Error('Invalid file: ' + file.path) - } - - content = removeDiacritics(content) - const metadata = app.metadataCache.getFileCache(file) - - // Look for links that lead to non-existing files, - // and add them to the index. - if (metadata) { - // FIXME: https://github.com/scambier/obsidian-omnisearch/issues/129 - const nonExisting = getNonExistingNotes(file, metadata) - for (const name of nonExisting.filter( - o => !cacheManager.getLiveDocument(o) - )) { - NotesIndex.addNonExistingToIndex(name, file.path) - } - - // EXCALIDRAW - // Remove the json code - if (metadata.frontmatter?.['excalidraw-plugin']) { - const comments = - metadata.sections?.filter(s => s.type === 'comment') ?? [] - for (const { start, end } of comments.map(c => c.position)) { - content = - content.substring(0, start.offset - 1) + content.substring(end.offset) - } - } - } - - return { - basename: removeDiacritics(file.basename), - content, - path: file.path, - mtime: file.stat.mtime, - - tags: getTagsFromMetadata(metadata), - aliases: getAliasesFromMetadata(metadata).join(''), - headings1: metadata ? extractHeadingsFromCache(metadata, 1).join(' ') : '', - headings2: metadata ? extractHeadingsFromCache(metadata, 2).join(' ') : '', - headings3: metadata ? extractHeadingsFromCache(metadata, 3).join(' ') : '', - } -} diff --git a/src/globals.ts b/src/globals.ts index 8bee954..756e9ae 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -1,14 +1,19 @@ import { EventBus } from './tools/event-bus' +import { writable } from 'svelte/store' +import { settings } from './settings' export const regexLineSplit = /\r?\n|\r|((\.|\?|!)( |\r?\n|\r))/g export const regexYaml = /^---\s*\n(.*?)\n?^---\s?/ms export const regexStripQuotes = /^"|"$|^'|'$/g export const chsRegex = /[\u4e00-\u9fa5]/ +export const chsSegmenter = (app as any).plugins.plugins['cm-chs-patch'] export const excerptBefore = 100 export const excerptAfter = 300 -export const highlightClass = 'suggestion-highlight omnisearch-highlight' +export const highlightClass = `suggestion-highlight omnisearch-highlight ${ + settings.hightlight ? 'omnisearch-default-highlight' : '' +}` export const eventBus = new EventBus() @@ -16,15 +21,16 @@ export const EventNames = { ToggleExcerpts: 'toggle-excerpts', } as const -export const enum IndexingStep { +export const enum IndexingStepType { Done, LoadingCache, - ReadingNotes, - ReadingPDFs, - ReadingImages, - UpdatingCache, + ReadingFiles, + IndexingFiles, + WritingCache, } +export type DocumentRef = { path: string; mtime: number } + export type IndexedDocument = { path: string basename: string @@ -37,6 +43,7 @@ export type IndexedDocument = { headings2: string headings3: string + // TODO: reimplement this doesNotExist?: boolean parent?: string } @@ -49,6 +56,8 @@ export const isSearchMatch = (o: { offset?: number }): o is SearchMatch => { return o.offset !== undefined } +export const indexingStep = writable(IndexingStepType.Done) + export type ResultNote = { score: number path: string diff --git a/src/main.ts b/src/main.ts index 7e1e405..fe4847a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,25 +1,24 @@ -import { Notice, Platform, Plugin, TFile } from 'obsidian' -import { SearchEngine } from './search/search-engine' +import { Notice, Platform, Plugin } from 'obsidian' import { OmnisearchInFileModal, OmnisearchVaultModal, } from './components/modals' import { loadSettings, settings, SettingsTab, showExcerpt } from './settings' -import { eventBus, EventNames, IndexingStep } from './globals' +import { eventBus, EventNames, indexingStep, IndexingStepType } from './globals' import api from './tools/api' -import { isFilePlaintext, wait } from './tools/utils' +import { isFileIndexable } from './tools/utils' +import { database, OmnisearchCache } from './database' import * as NotesIndex from './notes-index' -import * as FileLoader from './file-loader' -import { OmnisearchCache } from './database' +import { searchEngine } from './search/omnisearch' import { cacheManager } from './cache-manager' export default class OmnisearchPlugin extends Plugin { private ribbonButton?: HTMLElement async onload(): Promise { + await loadSettings(this) await cleanOldCacheFiles() await OmnisearchCache.clearOldDatabases() - await loadSettings(this) registerAPI(this) @@ -54,25 +53,34 @@ export default class OmnisearchPlugin extends Plugin { app.workspace.onLayoutReady(async () => { // Listeners to keep the search index up-to-date this.registerEvent( - this.app.vault.on('create', file => { - NotesIndex.addToIndexAndMemCache(file) + this.app.vault.on('create', async file => { + if (isFileIndexable(file.path)) { + await cacheManager.addToLiveCache(file.path) + searchEngine.addFromPaths([file.path]) + } }) ) this.registerEvent( this.app.vault.on('delete', file => { - NotesIndex.removeFromIndex(file.path) + cacheManager.removeFromLiveCache(file.path) + searchEngine.removeFromPaths([file.path]) }) ) this.registerEvent( this.app.vault.on('modify', async file => { - NotesIndex.markNoteForReindex(file) + if (isFileIndexable(file.path)) { + await cacheManager.addToLiveCache(file.path) + NotesIndex.markNoteForReindex(file) + } }) ) this.registerEvent( this.app.vault.on('rename', async (file, oldPath) => { - if (file instanceof TFile && isFilePlaintext(file.path)) { - NotesIndex.removeFromIndex(oldPath) - await NotesIndex.addToIndexAndMemCache(file) + if (isFileIndexable(file.path)) { + cacheManager.removeFromLiveCache(oldPath) + cacheManager.addToLiveCache(file.path) + searchEngine.removeFromPaths([oldPath]) + await searchEngine.addFromPaths([file.path]) } }) ) @@ -80,12 +88,17 @@ export default class OmnisearchPlugin extends Plugin { await populateIndex() }) - showWelcomeNotice(this) + executeFirstLaunchTasks(this) } - onunload(): void { + async onunload(): Promise { // @ts-ignore delete globalThis['omnisearch'] + + // Clear cache when disabling Omnisearch + if (process.env.NODE_ENV === 'production') { + await database.clearCache() + } } addRibbonButton(): void { @@ -106,115 +119,56 @@ export default class OmnisearchPlugin extends Plugin { */ async function populateIndex(): Promise { console.time('Omnisearch - Indexing total time') + indexingStep.set(IndexingStepType.ReadingFiles) + const files = app.vault.getFiles().filter(f => isFileIndexable(f.path)) + console.log(`Omnisearch - ${files.length} files total`) - // Initialize minisearch - let engine = SearchEngine.getEngine() + // Map documents in the background + // Promise.all(files.map(f => cacheManager.addToLiveCache(f.path))) - // if not iOS, load data from cache if (!Platform.isIosApp) { - engine = await SearchEngine.initFromCache() + console.time('Omnisearch - Loading index from cache') + indexingStep.set(IndexingStepType.LoadingCache) + await searchEngine.loadCache() + console.timeEnd('Omnisearch - Loading index from cache') } - // Load plaintext files - SearchEngine.indexingStep.set(IndexingStep.ReadingNotes) - console.log('Omnisearch - Reading notes') - const plainTextFiles = await FileLoader.getPlainTextFiles() - let allFiles = [...plainTextFiles] - // iOS: since there's no cache, directly index the documents - if (Platform.isIosApp) { - await wait(1000) - await engine.addAllToMinisearch(plainTextFiles) - } + const diff = searchEngine.getDiff( + files.map(f => ({ path: f.path, mtime: f.stat.mtime })) + ) - // Load PDFs - if (settings.PDFIndexing) { - SearchEngine.indexingStep.set(IndexingStep.ReadingPDFs) - console.log('Omnisearch - Reading PDFs') - const pdfDocuments = await FileLoader.getPDFAsDocuments() - // iOS: since there's no cache, just index the documents - if (Platform.isIosApp) { - await wait(1000) - await engine.addAllToMinisearch(pdfDocuments) - } - // Add PDFs to the files list - allFiles = [...allFiles, ...pdfDocuments] - } - - // Load Images - if (settings.imagesIndexing) { - SearchEngine.indexingStep.set(IndexingStep.ReadingImages) - console.log('Omnisearch - Reading Images') - const imagesDocuments = await FileLoader.getImagesAsDocuments() - // iOS: since there's no cache, just index the documents - if (Platform.isIosApp) { - await wait(1000) - await engine.addAllToMinisearch(imagesDocuments) - } - // Add Images to the files list - allFiles = [...allFiles, ...imagesDocuments] - } - - console.log('Omnisearch - Total number of files: ' + allFiles.length) - let needToUpdateCache = false - - // Other platforms: make a diff of what's to add/update/delete - if (!Platform.isIosApp) { - SearchEngine.indexingStep.set(IndexingStep.UpdatingCache) - console.log('Omnisearch - Checking index cache diff...') - // Check which documents need to be removed/added/updated - const diffDocs = await cacheManager.getDiffDocuments(allFiles) + if (diff.toAdd.length) { console.log( - `Omnisearch - Files to add/remove/update: ${diffDocs.toAdd.length}/${diffDocs.toDelete.length}/${diffDocs.toUpdate.length}` + 'Omnisearch - Total number of files to add/update: ' + diff.toAdd.length ) - - if ( - diffDocs.toAdd.length + - diffDocs.toDelete.length + - diffDocs.toUpdate.length > - 100 - ) { - new Notice( - `Omnisearch - A great number of files need to be added/updated/cleaned. This process may make cause slowdowns.` - ) - } - - needToUpdateCache = !!( - diffDocs.toAdd.length || - diffDocs.toDelete.length || - diffDocs.toUpdate.length + } + if (diff.toRemove.length) { + console.log( + 'Omnisearch - Total number of files to remove: ' + diff.toRemove.length ) - - // Add - await engine.addAllToMinisearch(diffDocs.toAdd) - diffDocs.toAdd.forEach(doc => - cacheManager.updateLiveDocument(doc.path, doc) - ) - - // Delete - for (const [i, doc] of diffDocs.toDelete.entries()) { - await wait(0) - engine.removeFromMinisearch(doc) - cacheManager.deleteLiveDocument(doc.path) - } - - // Update (delete + add) - diffDocs.toUpdate.forEach(({ oldDoc, newDoc }) => { - engine.removeFromMinisearch(oldDoc) - cacheManager.updateLiveDocument(oldDoc.path, newDoc) - }) - await engine.addAllToMinisearch(diffDocs.toUpdate.map(d => d.newDoc)) } - // Load PDFs into the main search engine, and write cache - // SearchEngine.loadTmpDataIntoMain() - SearchEngine.indexingStep.set(IndexingStep.Done) + if (diff.toAdd.length >= 500) { + new Notice( + `Omnisearch - ${diff.toAdd.length} files need to be indexed. Obsidian may experience stutters and freezes during the process`, + 10_000 + ) + } - if (!Platform.isIosApp && needToUpdateCache) { - console.log('Omnisearch - Writing cache...') - await SearchEngine.getEngine().writeToCache(allFiles) + indexingStep.set(IndexingStepType.IndexingFiles) + searchEngine.removeFromPaths(diff.toRemove.map(o => o.path)) + await searchEngine.addFromPaths(diff.toAdd.map(o => o.path)) + + if (diff.toRemove.length || diff.toAdd.length) { + indexingStep.set(IndexingStepType.WritingCache) + await searchEngine.writeToCache() } console.timeEnd('Omnisearch - Indexing total time') + if (diff.toAdd.length >= 500) { + new Notice(`Omnisearch - Your files have been indexed.`) + } + indexingStep.set(IndexingStepType.Done) } async function cleanOldCacheFiles() { @@ -235,7 +189,7 @@ async function cleanOldCacheFiles() { } } -function showWelcomeNotice(plugin: Plugin) { +function executeFirstLaunchTasks(plugin: Plugin) { const code = '1.8.0-beta.3' if (settings.welcomeMessage !== code) { const welcome = new DocumentFragment() diff --git a/src/notes-index.ts b/src/notes-index.ts index 4b022f8..1a35f57 100644 --- a/src/notes-index.ts +++ b/src/notes-index.ts @@ -1,43 +1,7 @@ -import { Notice, TAbstractFile, TFile } from 'obsidian' -import { isFileIndexable, wait } from './tools/utils' +import type { TAbstractFile } from 'obsidian' import { removeAnchors } from './tools/notes' -import { SearchEngine } from './search/search-engine' -import { cacheManager } from './cache-manager' import type { IndexedDocument } from './globals' -import { fileToIndexedDocument } from './file-loader' - -/** - * Adds a file to the search index - * @param file - * @returns - */ -export async function addToIndexAndMemCache( - file: TAbstractFile -): Promise { - if (!(file instanceof TFile) || !isFileIndexable(file.path)) { - return - } - - // Check if the file was already indexed as non-existent. - // If so, remove it from the index, and add it again as a real note. - if (cacheManager.getLiveDocument(file.path)?.doesNotExist) { - removeFromIndex(file.path) - } - - try { - if (cacheManager.getLiveDocument(file.path)) { - throw new Error(`${file.basename} is already indexed`) - } - - // Make the document and index it - const note = await fileToIndexedDocument(file) - SearchEngine.getEngine().addSingleToMinisearch(note) - await cacheManager.updateLiveDocument(note.path, note) - } catch (e) { - // console.trace('Error while indexing ' + file.basename) - console.error(e) - } -} +import { searchEngine } from './search/omnisearch' /** * Index a non-existing note. @@ -48,7 +12,6 @@ export async function addToIndexAndMemCache( export function addNonExistingToIndex(name: string, parent: string): void { name = removeAnchors(name) const filename = name + (name.endsWith('.md') ? '' : '.md') - if (cacheManager.getLiveDocument(filename)) return const note: IndexedDocument = { path: filename, @@ -65,33 +28,7 @@ export function addNonExistingToIndex(name: string, parent: string): void { doesNotExist: true, parent, } - SearchEngine.getEngine().addSingleToMinisearch(note) - cacheManager.updateLiveDocument(filename, note) -} - -/** - * Removes a file from the index, by its path. - */ -export function removeFromIndex(path: string): void { - if (!isFileIndexable(path)) { - console.info(`"${path}" is not an indexable file`) - return - } - const note = cacheManager.getLiveDocument(path) - if (note) { - SearchEngine.getEngine().removeFromMinisearch(note) - cacheManager.deleteLiveDocument(path) - - // FIXME: only remove non-existing notes if they don't have another parent - // cacheManager - // .getNonExistingNotesFromMemCache() - // .filter(n => n.parent === path) - // .forEach(n => { - // removeFromIndex(n.path) - // }) - } else { - console.warn(`Omnisearch - Note not found under path ${path}`) - } + // searchEngine.addDocuments([note]) } const notesToReindex = new Set() @@ -105,13 +42,11 @@ export function markNoteForReindex(note: TAbstractFile): void { } export async function refreshIndex(): Promise { - if (notesToReindex.size > 0) { - console.info(`Omnisearch - Reindexing ${notesToReindex.size} notes`) - for (const note of notesToReindex) { - removeFromIndex(note.path) - await addToIndexAndMemCache(note) - await wait(0) - } + const paths = [...notesToReindex].map(n => n.path) + if (paths.length) { + searchEngine.removeFromPaths(paths) + searchEngine.addFromPaths(paths) notesToReindex.clear() + // console.log(`Omnisearch - Reindexed ${paths.length} file(s)`) } } diff --git a/src/search/omnisearch.ts b/src/search/omnisearch.ts new file mode 100644 index 0000000..3fb59a6 --- /dev/null +++ b/src/search/omnisearch.ts @@ -0,0 +1,364 @@ +import MiniSearch, { type Options, type SearchResult } from 'minisearch' +import type { + DocumentRef, + IndexedDocument, + ResultNote, + SearchMatch, +} from '../globals' +import { + chsRegex, + chsSegmenter, + indexingStep, + IndexingStepType, + SPACE_OR_PUNCTUATION, +} from '../globals' +import { settings } from '../settings' +import { + chunkArray, + removeDiacritics, + stringsToRegex, + stripMarkdownCharacters, +} from '../tools/utils' +import { Notice, Platform } from 'obsidian' +import type { Query } from './query' +import { cacheManager } from '../cache-manager' + +const tokenize = (text: string): string[] => { + const tokens = text.split(SPACE_OR_PUNCTUATION) + + if (chsSegmenter) { + return tokens.flatMap(word => + chsRegex.test(word) ? chsSegmenter.cut(word) : [word] + ) + } else return tokens +} + +export class Omnisearch { + public static readonly options: Options = { + tokenize, + processTerm: (term: string) => + (settings.ignoreDiacritics ? removeDiacritics(term) : term).toLowerCase(), + idField: 'path', + fields: [ + 'basename', + 'aliases', + 'content', + 'headings1', + 'headings2', + 'headings3', + ], + storeFields: ['tags'], + logger(_level, _message, code) { + if (code === 'version_conflict') { + new Notice( + 'Omnisearch - Your index cache may be incorrect or corrupted. If this message keeps appearing, go to Settings to clear the cache.', + 5000 + ) + } + }, + } + private minisearch: MiniSearch + private indexedDocuments: Map = new Map() + private previousResults: SearchResult[] = [] + + constructor() { + this.minisearch = new MiniSearch(Omnisearch.options) + } + + async loadCache(): Promise { + const cache = await cacheManager.getMinisearchCache() + if (cache) { + this.minisearch = MiniSearch.loadJS(cache.data, Omnisearch.options) + this.indexedDocuments = new Map(cache.paths.map(o => [o.path, o.mtime])) + } + } + + /** + * Returns the list of documents that need to be reindexed + * @param docs + */ + getDiff(docs: DocumentRef[]): { + toAdd: DocumentRef[] + toRemove: DocumentRef[] + } { + const indexedArr = [...this.indexedDocuments] + const docsMap = new Map(docs.map(d => [d.path, d.mtime])) + + const toAdd = docs.filter( + d => + !this.indexedDocuments.has(d.path) || + this.indexedDocuments.get(d.path) !== d.mtime + ) + const toRemove = [...this.indexedDocuments] + .filter( + ([path, mtime]) => !docsMap.has(path) || docsMap.get(path) !== mtime + ) + .map(o => ({ path: o[0], mtime: o[1] })) + return { toAdd, toRemove } + } + + /** + * Add notes/PDFs/images to the search index + * @param paths + */ + public async addFromPaths(paths: string[]): Promise { + let documents = await Promise.all( + paths.map(async path => await cacheManager.getDocument(path)) + ) + + // If a document is already added, discard it + this.removeFromPaths( + documents.filter(d => this.indexedDocuments.has(d.path)).map(d => d.path) + ) + + // Split the documents in smaller chunks to regularly save the cache. + // If the user shuts off Obsidian mid-indexing, we at least saved some + const chunkedDocs = chunkArray(documents, 500) + for (const docs of chunkedDocs) { + // Update the list of indexed docs + docs.forEach(doc => this.indexedDocuments.set(doc.path, doc.mtime)) + + // Discard files that may have been already added (though it shouldn't happen) + const alreadyAdded = docs.filter(doc => this.minisearch.has(doc.path)) + this.removeFromPaths(alreadyAdded.map(o => o.path)) + + // Add docs to minisearch + await this.minisearch.addAllAsync(docs) + } + } + + /** + * Discard a document from minisearch + * @param paths + */ + public removeFromPaths(paths: string[]): void { + paths.forEach(p => this.indexedDocuments.delete(p)) + // Make sure to not discard a file that we don't have + const existing = paths.filter(p => this.minisearch.has(p)) + this.minisearch.discardAll(existing) + } + + /** + * Searches the index for the given query, + * and returns an array of raw results + */ + public async search( + query: Query, + options: { prefixLength: number; singleFilePath?: string } + ): Promise { + if (query.isEmpty()) { + this.previousResults = [] + return [] + } + + let results = this.minisearch.search(query.segmentsToStr(), { + prefix: term => term.length >= options.prefixLength, + fuzzy: 0.2, + combineWith: 'AND', + boost: { + basename: settings.weightBasename, + aliases: settings.weightBasename, + headings1: settings.weightH1, + headings2: settings.weightH2, + headings3: settings.weightH3, + }, + }) + if (!results.length) return this.previousResults + + if (options.singleFilePath) { + return results.filter(r => r.id === options.singleFilePath) + } + + // Hide or downrank files that are in Obsidian's excluded list + if (settings.hideExcluded) { + // Filter the files out + results = results.filter( + result => + !( + app.metadataCache.isUserIgnored && + app.metadataCache.isUserIgnored(result.id) + ) + ) + } else { + // Just downrank them + results.forEach(result => { + if ( + app.metadataCache.isUserIgnored && + app.metadataCache.isUserIgnored(result.id) + ) { + result.score /= 10 + } + }) + } + + // Extract tags from the query + const tags = query.segments + .filter(s => s.value.startsWith('#')) + .map(s => s.value) + + // Put the results with tags on top + for (const tag of tags) { + for (const result of results) { + if ((result.tags ?? []).includes(tag)) { + result.score *= 100 + } + } + } + + results = results.slice(0, 50) + + const documents = await Promise.all( + results.map(async result => await cacheManager.getDocument(result.id)) + ) + + // If the search query contains quotes, filter out results that don't have the exact match + const exactTerms = query.getExactTerms() + if (exactTerms.length) { + results = results.filter(r => { + const document = documents.find(d => d.path === r.id) + const title = document?.path.toLowerCase() ?? '' + const content = stripMarkdownCharacters( + document?.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 + const exclusions = query.exclusions + if (exclusions.length) { + results = results.filter(r => { + const content = stripMarkdownCharacters( + documents.find(d => d.path === r.id)?.content ?? '' + ).toLowerCase() + return exclusions.every(q => !content.includes(q.value)) + }) + } + // FIXME: + // Dedupe results - clutch for https://github.com/scambier/obsidian-omnisearch/issues/129 + results = results.filter( + (result, index, arr) => arr.findIndex(t => t.id === result.id) === index + ) + + this.previousResults = results + + return results + } + + public getMatches(text: string, reg: RegExp, query: Query): SearchMatch[] { + let match: RegExpExecArray | null = null + const matches: SearchMatch[] = [] + let count = 0 + while ((match = reg.exec(text)) !== null) { + if (++count >= 100) break // Avoid infinite loops, stop looking after 100 matches + const m = match[0] + if (m) matches.push({ match: m, offset: match.index }) + } + + // If the query can be found "as is" in the text, put this match first + const best = text.toLowerCase().indexOf(query.segmentsToStr()) + if (best > -1) { + matches.unshift({ + offset: best, + match: query.segmentsToStr(), + }) + } + + return matches + } + + /** + * Searches the index, and returns an array of ResultNote objects. + * If we have the singleFile option set, + * the array contains a single result from that file + * @param query + * @param options + * @returns + */ + public async getSuggestions( + query: Query, + options?: Partial<{ singleFilePath?: string }> + ): Promise { + // Get the raw results + let results: SearchResult[] + if (settings.simpleSearch) { + results = await this.search(query, { + prefixLength: 1, + singleFilePath: options?.singleFilePath, + }) + } else { + results = await this.search(query, { + prefixLength: 3, + singleFilePath: options?.singleFilePath, + }) + } + + // Extract tags from the query + const tags = query.segments + .filter(s => s.value.startsWith('#')) + .map(s => s.value) + + const documents = await Promise.all( + results.map(async result => await cacheManager.getDocument(result.id)) + ) + + // Map the raw results to get usable suggestions + const resultNotes = results.map(result => { + let note = documents.find(d => d.path === result.id) + if (!note) { + // throw new Error(`Omnisearch - Note "${result.id}" not indexed`) + console.warn(`Omnisearch - Note "${result.id}" not in the live cache`) + note = { + content: '', + basename: result.id, + path: result.id, + } as IndexedDocument + } + + // 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 = [ + // Matching terms from the result, + // do not necessarily match the query + ...Object.keys(result.match), + + // Quoted expressions + ...query.segments.filter(s => s.exact).map(s => s.value), + + // Tags, starting with # + ...tags, + ].filter(w => w.length > 1) + + // console.log(foundWords) + const matches = this.getMatches( + note.content, + stringsToRegex(foundWords), + query + ) + const resultNote: ResultNote = { + score: result.score, + foundWords, + matches, + ...note, + } + return resultNote + }) + return resultNotes + } + + public async writeToCache(): Promise { + if (Platform.isIosApp) { + return + } + await cacheManager.writeMinisearchCache( + this.minisearch, + this.indexedDocuments + ) + } +} + +export const searchEngine = new Omnisearch() diff --git a/src/search/search-engine.ts b/src/search/search-engine.ts deleted file mode 100644 index 04e967a..0000000 --- a/src/search/search-engine.ts +++ /dev/null @@ -1,305 +0,0 @@ -import MiniSearch, { type Options, type SearchResult } from 'minisearch' -import { - chsRegex, - type IndexedDocument, - type ResultNote, - type SearchMatch, - SPACE_OR_PUNCTUATION, - IndexingStep, -} from '../globals' -import { - removeDiacritics, - stringsToRegex, - stripMarkdownCharacters, -} from '../tools/utils' -import type { Query } from './query' -import { settings } from '../settings' -import { cacheManager } from '../cache-manager' -import { writable } from 'svelte/store' -import { Notice } from 'obsidian' - -let previousResults: ResultNote[] = [] - -const tokenize = (text: string): string[] => { - const tokens = text.split(SPACE_OR_PUNCTUATION) - const chsSegmenter = (app as any).plugins.plugins['cm-chs-patch'] - - if (chsSegmenter) { - return tokens.flatMap(word => - chsRegex.test(word) ? chsSegmenter.cut(word) : [word] - ) - } else return tokens -} - -export const minisearchOptions: Options = { - tokenize, - processTerm: (term: string) => - (settings.ignoreDiacritics ? removeDiacritics(term) : term).toLowerCase(), - idField: 'path', - fields: [ - 'basename', - 'aliases', - 'content', - 'headings1', - 'headings2', - 'headings3', - ], - storeFields: ['tags'], - callbackWhenDesync() { - new Notice( - 'Omnisearch - Your index cache may be incorrect or corrupted. If this message keeps appearing, go to Settings to clear the cache.' - ) - }, -} - -export class SearchEngine { - private static engine?: SearchEngine - public static indexingStep = writable(IndexingStep.LoadingCache) - - /** - * The main singleton SearchEngine instance. - * Should be used for all queries - */ - public static getEngine(): SearchEngine { - if (!this.engine) { - this.engine = new SearchEngine() - } - return this.engine - } - - /** - * Instantiates the main instance with cache data (if it exists) - */ - public static async initFromCache(): Promise { - try { - const cache = await cacheManager.getMinisearchCache() - if (cache) { - this.getEngine().minisearch = cache - } - } catch (e) { - new Notice( - 'Omnisearch - Cache missing or invalid. Some freezes may occur while Omnisearch indexes your vault.' - ) - console.error('Omnisearch - Could not init engine from cache') - console.error(e) - } - return this.getEngine() - } - - private minisearch: MiniSearch - - private constructor() { - this.minisearch = new MiniSearch(minisearchOptions) - } - - /** - * Searches the index for the given query, - * and returns an array of raw results - */ - public async search( - query: Query, - options: { prefixLength: number } - ): Promise { - if (!query.segmentsToStr()) return [] - - let results = this.minisearch.search(query.segmentsToStr(), { - prefix: term => term.length >= options.prefixLength, - fuzzy: 0.2, - combineWith: 'AND', - boost: { - basename: settings.weightBasename, - aliases: settings.weightBasename, - headings1: settings.weightH1, - headings2: settings.weightH2, - headings3: settings.weightH3, - }, - }) - - // Downrank files that are in Obsidian's excluded list - if (settings.respectExcluded) { - results.forEach(result => { - if ( - app.metadataCache.isUserIgnored && - app.metadataCache.isUserIgnored(result.id) - ) { - result.score /= 10 // TODO: make this value configurable or toggleable? - } - }) - } - - // If the search query contains quotes, filter out results that don't have the exact match - const exactTerms = query.getExactTerms() - if (exactTerms.length) { - results = results.filter(r => { - const title = - cacheManager.getLiveDocument(r.id)?.path.toLowerCase() ?? '' - const content = stripMarkdownCharacters( - cacheManager.getLiveDocument(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 - const exclusions = query.exclusions - if (exclusions.length) { - results = results.filter(r => { - const content = stripMarkdownCharacters( - cacheManager.getLiveDocument(r.id)?.content ?? '' - ).toLowerCase() - return exclusions.every(q => !content.includes(q.value)) - }) - } - // FIXME: - // Dedupe results - clutch for https://github.com/scambier/obsidian-omnisearch/issues/129 - return results.filter( - (result, index, arr) => arr.findIndex(t => t.id === result.id) === index - ) - } - - /** - * Parses a text against a regex, and returns the { string, offset } matches - */ - public getMatches(text: string, reg: RegExp, query: Query): SearchMatch[] { - let match: RegExpExecArray | null = null - const matches: SearchMatch[] = [] - let count = 0 - while ((match = reg.exec(text)) !== null) { - if (++count >= 100) break // Avoid infinite loops, stop looking after 100 matches - const m = match[0] - if (m) matches.push({ match: m, offset: match.index }) - } - - // If the query can be found "as is" in the text, put this match first - const best = text.toLowerCase().indexOf(query.segmentsToStr()) - if (best > -1) { - matches.unshift({ - offset: best, - match: query.segmentsToStr(), - }) - } - - return matches - } - - /** - * Searches the index, and returns an array of ResultNote objects. - * If we have the singleFile option set, - * the array contains a single result from that file - * @param query - * @param options - * @returns - */ - public async getSuggestions( - query: Query, - options?: Partial<{ singleFilePath: string | null }> - ): Promise { - if (query.isEmpty()) { - previousResults = [] - return [] - } - // Get the raw results - let results: SearchResult[] - if (settings.simpleSearch) { - results = await this.search(query, { prefixLength: 1 }) - } else { - results = await this.search(query, { prefixLength: 3 }) - } - if (!results.length) return previousResults - - // Extract tags from the query - const tags = query.segments - .filter(s => s.value.startsWith('#')) - .map(s => s.value) - - // Either keep the 50 first results, - // or the one corresponding to `singleFile` - if (options?.singleFilePath) { - const result = results.find(r => r.id === options.singleFilePath) - if (result) results = [result] - else results = [] - } else { - results = results.slice(0, 50) - - // Put the results with tags on top - 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 - const resultNotes = results.map(result => { - let note = cacheManager.getLiveDocument(result.id) - if (!note) { - // throw new Error(`Omnisearch - Note "${result.id}" not indexed`) - console.warn(`Omnisearch - Note "${result.id}" not in the live cache`) - note = { - content: '', - basename: result.id, - path: result.id, - } as IndexedDocument - } - - // 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 = [ - // Matching terms from the result, - // do not necessarily match the query - ...Object.keys(result.match), - - // Quoted expressions - ...query.segments.filter(s => s.exact).map(s => s.value), - - // Tags, starting with # - ...tags, - ].filter(w => w.length > 1) - - // console.log(foundWords) - const matches = this.getMatches( - note.content, - stringsToRegex(foundWords), - query - ) - const resultNote: ResultNote = { - score: result.score, - foundWords, - matches, - ...note, - } - return resultNote - }) - previousResults = resultNotes - return resultNotes - } - - // #region Read/write minisearch index - - public async addAllToMinisearch( - documents: IndexedDocument[], - chunkSize = 10 - ): Promise { - await this.minisearch.addAllAsync(documents, { chunkSize }) - } - - public addSingleToMinisearch(document: IndexedDocument): void { - this.minisearch.add(document) - } - - public removeFromMinisearch(document: IndexedDocument): void { - this.minisearch.remove(document) - } - - // #endregion - - public async writeToCache(documents: IndexedDocument[]): Promise { - await cacheManager.writeMinisearchCache(this.minisearch, documents) - } -} diff --git a/src/settings.ts b/src/settings.ts index fdd651d..35ecc5e 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -19,7 +19,7 @@ interface WeightingSettings { export interface OmnisearchSettings extends WeightingSettings { /** Respect the "excluded files" Obsidian setting by downranking results ignored files */ - respectExcluded: boolean + hideExcluded: boolean /** Ignore diacritics when indexing files */ ignoreDiacritics: boolean /** Extensions of plain text files to index, in addition to .md */ @@ -44,6 +44,7 @@ export interface OmnisearchSettings extends WeightingSettings { welcomeMessage: string /** If a query returns 0 result, try again with more relax conditions */ simpleSearch: boolean + hightlight: boolean } /** @@ -149,7 +150,7 @@ export class SettingsTab extends PluginSettingTab { //#endregion Indexing - // #region Behavior + //#region Behavior new Setting(containerEl).setName('Behavior').setHeading() @@ -157,11 +158,12 @@ export class SettingsTab extends PluginSettingTab { new Setting(containerEl) .setName('Respect Obsidian\'s "Excluded Files"') .setDesc( - 'Files that are in Obsidian\'s "Options > Files & Links > Excluded Files" list will be downranked in results.' + `By default, fFiles that are in Obsidian\'s "Options > Files & Links > Excluded Files" list are downranked in results. + Enable this option to completely hide them` ) .addToggle(toggle => - toggle.setValue(settings.respectExcluded).onChange(async v => { - settings.respectExcluded = v + toggle.setValue(settings.hideExcluded).onChange(async v => { + settings.hideExcluded = v await saveSettings(this.plugin) }) ) @@ -188,8 +190,7 @@ export class SettingsTab extends PluginSettingTab { new Setting(containerEl) .setName('Simpler search') .setDesc( - `When enabled, Omnisearch is a bit more restrictive when using your query terms as prefixes. - May return less results, but will be quicker. You should enable this if Omnisearch makes Obsidian freeze while searching.` + `Enable this if Obsidian often freezes while making searches. This will return more strict results.` ) .addToggle(toggle => toggle.setValue(settings.simpleSearch).onChange(async v => { @@ -198,9 +199,9 @@ export class SettingsTab extends PluginSettingTab { }) ) - // #endregion Behavior + //#endregion Behavior - // #region User Interface + //#region User Interface new Setting(containerEl).setName('User Interface').setHeading() @@ -235,7 +236,9 @@ export class SettingsTab extends PluginSettingTab { // Keep line returns in excerpts new Setting(containerEl) .setName('Render line return in excerpts') - .setDesc('Activate this option render line returns in result excerpts.') + .setDesc( + 'Activate this option to render line returns in result excerpts.' + ) .addToggle(toggle => toggle .setValue(settings.renderLineReturnInExcerpts) @@ -285,9 +288,22 @@ export class SettingsTab extends PluginSettingTab { }) ) - // #endregion User Interface + // Highlight results + new Setting(containerEl) + .setName('Highlight matching words in results') + .setDesc( + 'Will highlight matching results when enabled. See README for more customization options.' + ) + .addToggle(toggle => + toggle.setValue(settings.hightlight).onChange(async v => { + settings.hightlight = v + await saveSettings(this.plugin) + }) + ) - // #region Results Weighting + //#endregion User Interface + + //#region Results Weighting new Setting(containerEl).setName('Results weighting').setHeading() @@ -309,29 +325,29 @@ export class SettingsTab extends PluginSettingTab { .setName(`Headings level 3 (default: ${DEFAULT_SETTINGS.weightH3})`) .addSlider(cb => this.weightSlider(cb, 'weightH3')) - // #endregion Results Weighting + //#endregion Results Weighting - // #region Danger Zone + //#region Danger Zone + if (!Platform.isIosApp) { + new Setting(containerEl).setName('Danger Zone').setHeading() - new Setting(containerEl).setName('Danger Zone').setHeading() - - const resetCacheDesc = new DocumentFragment() - resetCacheDesc.createSpan({}, span => { - span.innerHTML = `Erase all Omnisearch cache data. + const resetCacheDesc = new DocumentFragment() + resetCacheDesc.createSpan({}, span => { + span.innerHTML = `Erase all Omnisearch cache data. Use this if Omnisearch results are inconsistent, missing, or appear outdated.
Needs a restart to fully take effect.` - }) - new Setting(containerEl) - .setName('Clear cache data') - .setDesc(resetCacheDesc) - .addButton(cb => { - cb.setButtonText('Clear cache') - cb.onClick(async () => { - await database.clearCache() - new Notice('Omnisearch - Cache cleared. Please restart Obsidian.') - }) }) - + new Setting(containerEl) + .setName('Clear cache data') + .setDesc(resetCacheDesc) + .addButton(cb => { + cb.setButtonText('Clear cache') + cb.onClick(async () => { + await database.clearCache() + new Notice('Omnisearch - Cache cleared. Please restart Obsidian.') + }) + }) + } //#endregion Danger Zone } @@ -347,7 +363,7 @@ export class SettingsTab extends PluginSettingTab { } export const DEFAULT_SETTINGS: OmnisearchSettings = { - respectExcluded: true, + hideExcluded: false, ignoreDiacritics: true, indexedFileTypes: [] as string[], PDFIndexing: false, @@ -358,6 +374,7 @@ export const DEFAULT_SETTINGS: OmnisearchSettings = { showExcerpt: true, renderLineReturnInExcerpts: true, showCreateButton: false, + hightlight: true, showPreviousQueryResults: true, simpleSearch: false, @@ -373,12 +390,6 @@ export let settings = Object.assign({}, DEFAULT_SETTINGS) as OmnisearchSettings export async function loadSettings(plugin: Plugin): Promise { settings = Object.assign({}, DEFAULT_SETTINGS, await plugin.loadData()) - - if (Platform.isMobileApp) { - settings.PDFIndexing = false - settings.imagesIndexing = false - } - showExcerpt.set(settings.showExcerpt) } diff --git a/src/tools/api.ts b/src/tools/api.ts index 3268b1d..7539c93 100644 --- a/src/tools/api.ts +++ b/src/tools/api.ts @@ -1,6 +1,6 @@ import type { ResultNote } from '../globals' import { Query } from '../search/query' -import { SearchEngine } from '../search/search-engine' +import { searchEngine } from '../search/omnisearch' type ResultNoteApi = { score: number @@ -35,8 +35,8 @@ function mapResults(results: ResultNote[]): ResultNoteApi[] { async function search(q: string): Promise { const query = new Query(q) - const raw = await SearchEngine.getEngine().getSuggestions(query) + const raw = await searchEngine.getSuggestions(query) return mapResults(raw) } -export default { search } +export default {search} diff --git a/src/tools/utils.ts b/src/tools/utils.ts index 1339d3e..8f62702 100644 --- a/src/tools/utils.ts +++ b/src/tools/utils.ts @@ -1,12 +1,13 @@ import { type CachedMetadata, - Notice, - Platform, getAllTags, + Notice, parseFrontMatterAliases, + Platform, } from 'obsidian' import type { SearchMatch } from '../globals' import { + chsSegmenter, excerptAfter, excerptBefore, highlightClass, @@ -70,7 +71,10 @@ export function getAllIndices(text: string, regex: RegExp): SearchMatch[] { */ export function stringsToRegex(strings: string[]): RegExp { if (!strings.length) return /^$/g - const joined = strings.map(s => '\\b' + escapeRegex(s)).join('|') + // \\b is "word boundary", and is not applied if the user uses the cm-chs-patch plugin + const joined = strings + .map(s => (chsSegmenter ? '' : '\\b') + escapeRegex(s)) + .join('|') const reg = new RegExp(`(${joined})`, 'gi') // console.log(reg) return reg @@ -170,7 +174,7 @@ export async function filterAsync( callbackfn: (value: T, index: number, array: T[]) => Promise ): Promise { const filterMap = await mapAsync(array, callbackfn) - return array.filter((value, index) => filterMap[index]) + return array.filter((_value, index) => filterMap[index]) } /** @@ -207,9 +211,9 @@ export function getCtrlKeyLabel(): 'ctrl' | '⌘' { export function isFileIndexable(path: string): boolean { return ( - (settings.PDFIndexing && path.endsWith('.pdf')) || isFilePlaintext(path) || - (settings.imagesIndexing && isFileImage(path)) + (!Platform.isMobileApp && settings.PDFIndexing && isFilePDF(path)) || + (!Platform.isMobileApp && settings.imagesIndexing && isFileImage(path)) ) } @@ -219,6 +223,10 @@ export function isFileImage(path: string): boolean { ) } +export function isFilePDF(path: string): boolean { + return path.endsWith('.pdf') +} + export function isFilePlaintext(path: string): boolean { return getPlaintextExtensions().some(t => path.endsWith(`.${t}`)) } @@ -240,3 +248,15 @@ export function makeMD5(data: BinaryLike): string { } return createHash('md5').update(data).digest('hex') } + +export function chunkArray(arr: T[], len: number): T[][] { + var chunks = [], + i = 0, + n = arr.length + + while (i < n) { + chunks.push(arr.slice(i, (i += len))) + } + + return chunks +} diff --git a/src/vendor/parse-query.ts b/src/vendor/parse-query.ts index a7180a9..0679133 100644 --- a/src/vendor/parse-query.ts +++ b/src/vendor/parse-query.ts @@ -86,7 +86,7 @@ export function parseQuery( let val = term.slice(sepIndex + 1) // Strip backslashes respecting escapes - val = (val + '').replace(/\\(.?)/g, function (s, n1) { + val = (val + '').replace(/\\(.?)/g, function (_s, n1) { switch (n1) { case '\\': return '\\' @@ -115,7 +115,7 @@ export function parseQuery( } // Strip backslashes respecting escapes - term = (term + '').replace(/\\(.?)/g, function (s, n1) { + term = (term + '').replace(/\\(.?)/g, function (_s, n1) { switch (n1) { case '\\': return '\\'