From 6566a2e95890cd45de6b8ecd8fb4f13151a27a42 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Sat, 25 May 2024 22:49:50 +0200 Subject: [PATCH] Massive refactor to get rid of the global app. --- package.json | 2 +- pnpm-lock.yaml | 932 +++++++++++++++++-------- src/__tests__/query-tests.ts | 6 +- src/cache-manager.ts | 377 +++++----- src/components/InputSearch.svelte | 11 +- src/components/ModalInFile.svelte | 23 +- src/components/ModalVault.svelte | 58 +- src/components/ResultItemInFile.svelte | 14 +- src/components/ResultItemVault.svelte | 31 +- src/components/modals.ts | 31 +- src/database.ts | 27 +- src/globals.ts | 17 - src/main.ts | 111 +-- src/notes-index.ts | 48 +- src/search/omnisearch.ts | 173 ++--- src/search/query.ts | 5 +- src/search/tokenizer.ts | 159 ++--- src/settings.ts | 85 +-- src/stores/obsidian-app.ts | 17 - src/tools/api-server.ts | 12 +- src/tools/api.ts | 82 ++- src/tools/notes.ts | 15 +- src/tools/text-processing.ts | 401 +++++------ src/tools/utils.ts | 41 +- 24 files changed, 1532 insertions(+), 1146 deletions(-) delete mode 100644 src/stores/obsidian-app.ts diff --git a/package.json b/package.json index 6689d19..fd0223f 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "esbuild-plugin-copy": "1.3.0", "esbuild-svelte": "0.7.1", "jest": "^27.5.1", - "obsidian": "1.3.5", + "obsidian": "1.5.7-1", "prettier": "^2.8.8", "prettier-plugin-svelte": "^2.10.1", "svelte": "^3.59.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e79b63c..a99f8ae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,7 +22,7 @@ dependencies: version: 4.0.2 minisearch: specifier: github:scambier/minisearch#async-load-json - version: github.com/scambier/minisearch/fbe02d564ff2a6332a463932e624ab0516778d71 + version: github.com/scambier/minisearch/699babb6732423565868708e2b024d941de05180 pure-md5: specifier: ^0.1.14 version: 0.1.14 @@ -33,10 +33,10 @@ dependencies: devDependencies: '@babel/preset-env': specifier: ^7.24.3 - version: 7.24.3(@babel/core@7.24.3) + version: 7.24.3(@babel/core@7.24.6) '@babel/preset-typescript': specifier: ^7.24.1 - version: 7.24.1(@babel/core@7.24.3) + version: 7.24.1(@babel/core@7.24.6) '@testing-library/jest-dom': specifier: ^5.17.0 version: 5.17.0 @@ -57,7 +57,7 @@ devDependencies: version: 2.0.3 babel-jest: specifier: ^27.5.1 - version: 27.5.1(@babel/core@7.24.3) + version: 27.5.1(@babel/core@7.24.6) builtin-modules: specifier: ^3.3.0 version: 3.3.0 @@ -74,8 +74,8 @@ devDependencies: specifier: ^27.5.1 version: 27.5.1 obsidian: - specifier: 1.3.5 - version: 1.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.26.0) + specifier: 1.5.7-1 + version: 1.5.7-1(@codemirror/state@6.4.1)(@codemirror/view@6.26.3) prettier: specifier: ^2.8.8 version: 2.8.8 @@ -87,13 +87,13 @@ devDependencies: version: 3.59.2 svelte-check: specifier: ^2.10.3 - version: 2.10.3(@babel/core@7.24.3)(svelte@3.59.2) + version: 2.10.3(@babel/core@7.24.6)(svelte@3.59.2) svelte-jester: specifier: ^2.3.2 version: 2.3.2(jest@27.5.1)(svelte@3.59.2) svelte-preprocess: specifier: ^4.10.7 - version: 4.10.7(@babel/core@7.24.3)(svelte@3.59.2)(typescript@4.9.5) + version: 4.10.7(@babel/core@7.24.6)(svelte@3.59.2)(typescript@4.9.5) tslib: specifier: 2.3.1 version: 2.3.1 @@ -126,11 +126,24 @@ packages: picocolors: 1.0.0 dev: true + /@babel/code-frame@7.24.6: + resolution: {integrity: sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.24.6 + picocolors: 1.0.1 + dev: true + /@babel/compat-data@7.24.1: resolution: {integrity: sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==} engines: {node: '>=6.9.0'} dev: true + /@babel/compat-data@7.24.6: + resolution: {integrity: sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/core@7.24.3: resolution: {integrity: sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==} engines: {node: '>=6.9.0'} @@ -154,6 +167,29 @@ packages: - supports-color dev: true + /@babel/core@7.24.6: + resolution: {integrity: sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/helper-compilation-targets': 7.24.6 + '@babel/helper-module-transforms': 7.24.6(@babel/core@7.24.6) + '@babel/helpers': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/template': 7.24.6 + '@babel/traverse': 7.24.6 + '@babel/types': 7.24.6 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/generator@7.24.1: resolution: {integrity: sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==} engines: {node: '>=6.9.0'} @@ -164,6 +200,16 @@ packages: jsesc: 2.5.2 dev: true + /@babel/generator@7.24.6: + resolution: {integrity: sha512-S7m4eNa6YAPJRHmKsLHIDJhNAGNKoWNiWefz1MBbpnt8g9lvMDl1hir4P9bo/57bQEmuwEhnRU/AMWsD0G/Fbg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.6 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + dev: true + /@babel/helper-annotate-as-pure@7.22.5: resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} engines: {node: '>=6.9.0'} @@ -189,42 +235,53 @@ packages: semver: 6.3.1 dev: true - /@babel/helper-create-class-features-plugin@7.24.1(@babel/core@7.24.3): + /@babel/helper-compilation-targets@7.24.6: + resolution: {integrity: sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.24.6 + '@babel/helper-validator-option': 7.24.6 + browserslist: 4.23.0 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true + + /@babel/helper-create-class-features-plugin@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-1yJa9dX9g//V6fDebXoEfEsxkZHk3Hcbm+zLhyu6qVgYFLvmTALTeV+jNU9e5RnYtioBrGEOdoI2joMSNQ/+aA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 '@babel/helper-member-expression-to-functions': 7.23.0 '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.3) + '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.6) '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 semver: 6.3.1 dev: true - /@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.24.3): + /@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.24.6): resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-annotate-as-pure': 7.22.5 regexpu-core: 5.3.2 semver: 6.3.1 dev: true - /@babel/helper-define-polyfill-provider@0.6.1(@babel/core@7.24.3): + /@babel/helper-define-polyfill-provider@0.6.1(@babel/core@7.24.6): resolution: {integrity: sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-plugin-utils': 7.24.0 debug: 4.3.4 @@ -239,6 +296,11 @@ packages: engines: {node: '>=6.9.0'} dev: true + /@babel/helper-environment-visitor@7.24.6: + resolution: {integrity: sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-function-name@7.23.0: resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} engines: {node: '>=6.9.0'} @@ -247,6 +309,14 @@ packages: '@babel/types': 7.24.0 dev: true + /@babel/helper-function-name@7.24.6: + resolution: {integrity: sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.24.6 + '@babel/types': 7.24.6 + dev: true + /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} @@ -254,6 +324,13 @@ packages: '@babel/types': 7.24.0 dev: true + /@babel/helper-hoist-variables@7.24.6: + resolution: {integrity: sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.6 + dev: true + /@babel/helper-member-expression-to-functions@7.23.0: resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} engines: {node: '>=6.9.0'} @@ -268,6 +345,13 @@ packages: '@babel/types': 7.24.0 dev: true + /@babel/helper-module-imports@7.24.6: + resolution: {integrity: sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.6 + dev: true + /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.3): resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} engines: {node: '>=6.9.0'} @@ -282,6 +366,34 @@ packages: '@babel/helper-validator-identifier': 7.22.20 dev: true + /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.6): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.24.3 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: true + + /@babel/helper-module-transforms@7.24.6(@babel/core@7.24.6): + resolution: {integrity: sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-module-imports': 7.24.6 + '@babel/helper-simple-access': 7.24.6 + '@babel/helper-split-export-declaration': 7.24.6 + '@babel/helper-validator-identifier': 7.24.6 + dev: true + /@babel/helper-optimise-call-expression@7.22.5: resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} engines: {node: '>=6.9.0'} @@ -294,25 +406,25 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.24.3): + /@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.24.6): resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-wrap-function': 7.22.20 dev: true - /@babel/helper-replace-supers@7.24.1(@babel/core@7.24.3): + /@babel/helper-replace-supers@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-member-expression-to-functions': 7.23.0 '@babel/helper-optimise-call-expression': 7.22.5 @@ -325,6 +437,13 @@ packages: '@babel/types': 7.24.0 dev: true + /@babel/helper-simple-access@7.24.6: + resolution: {integrity: sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.6 + dev: true + /@babel/helper-skip-transparent-expression-wrappers@7.22.5: resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} engines: {node: '>=6.9.0'} @@ -339,21 +458,43 @@ packages: '@babel/types': 7.24.0 dev: true + /@babel/helper-split-export-declaration@7.24.6: + resolution: {integrity: sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.6 + dev: true + /@babel/helper-string-parser@7.24.1: resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} engines: {node: '>=6.9.0'} dev: true + /@babel/helper-string-parser@7.24.6: + resolution: {integrity: sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-validator-identifier@7.22.20: resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} dev: true + /@babel/helper-validator-identifier@7.24.6: + resolution: {integrity: sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-validator-option@7.23.5: resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} engines: {node: '>=6.9.0'} dev: true + /@babel/helper-validator-option@7.24.6: + resolution: {integrity: sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-wrap-function@7.22.20: resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==} engines: {node: '>=6.9.0'} @@ -374,6 +515,14 @@ packages: - supports-color dev: true + /@babel/helpers@7.24.6: + resolution: {integrity: sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.24.6 + '@babel/types': 7.24.6 + dev: true + /@babel/highlight@7.24.2: resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==} engines: {node: '>=6.9.0'} @@ -384,6 +533,16 @@ packages: picocolors: 1.0.0 dev: true + /@babel/highlight@7.24.6: + resolution: {integrity: sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.24.6 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.1 + dev: true + /@babel/parser@7.24.1: resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==} engines: {node: '>=6.0.0'} @@ -392,46 +551,54 @@ packages: '@babel/types': 7.24.0 dev: true - /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.1(@babel/core@7.24.3): + /@babel/parser@7.24.6: + resolution: {integrity: sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.24.6 + dev: true + + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.1(@babel/core@7.24.3): + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-optional-chaining': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-transform-optional-chaining': 7.24.1(@babel/core@7.24.6) dev: true - /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.1(@babel/core@7.24.3): + /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.3): + /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.6): resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 dev: true /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.3): @@ -443,6 +610,15 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.6): + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.3): resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: @@ -452,6 +628,15 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.6): + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.3): resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: @@ -461,51 +646,60 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.3): + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.6): + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.6): resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.3): + /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.6): resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.3): + /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.6): resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-import-assertions@7.24.1(@babel/core@7.24.3): + /@babel/plugin-syntax-import-assertions@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-import-attributes@7.24.1(@babel/core@7.24.3): + /@babel/plugin-syntax-import-attributes@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true @@ -518,6 +712,15 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.6): + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.3): resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: @@ -527,13 +730,22 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-jsx@7.24.1(@babel/core@7.24.3): + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.6): + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-jsx@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true @@ -546,6 +758,15 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.6): + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.3): resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: @@ -555,6 +776,15 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.6): + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.3): resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: @@ -564,6 +794,15 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.6): + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.3): resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: @@ -573,6 +812,15 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.6): + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.3): resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: @@ -582,6 +830,15 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.6): + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.3): resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: @@ -591,13 +848,22 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.3): + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.6): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.6): resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true @@ -611,6 +877,16 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.6): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + /@babel/plugin-syntax-typescript@7.24.1(@babel/core@7.24.3): resolution: {integrity: sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==} engines: {node: '>=6.9.0'} @@ -621,675 +897,685 @@ packages: '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.3): + /@babel/plugin-syntax-typescript@7.24.1(@babel/core@7.24.6): + resolution: {integrity: sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.6 + '@babel/helper-plugin-utils': 7.24.0 + dev: true + + /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.6): resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.3 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.3) + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-arrow-functions@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-arrow-functions@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-async-generator-functions@7.24.3(@babel/core@7.24.3): + /@babel/plugin-transform-async-generator-functions@7.24.3(@babel/core@7.24.6): resolution: {integrity: sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.3) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.3) + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.6) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-async-to-generator@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-async-to-generator@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-module-imports': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.3) + '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-block-scoped-functions@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-block-scoped-functions@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-block-scoping@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-block-scoping@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-h71T2QQvDgM2SmT29UYU6ozjMlAt7s7CSs5Hvy8f8cf/GM/Z4a2zMfN+fjVGaieeCrXR3EdQl6C4gQG+OgmbKw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-class-properties@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-class-properties@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 - '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.3) + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-class-static-block@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-class-static-block@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-FUHlKCn6J3ERiu8Dv+4eoz7w8+kFLSyeVG4vDAikwADGjUCoHw/JHokyGtr8OR4UjpwPVivyF+h8Q5iv/JmrtA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 dependencies: - '@babel/core': 7.24.3 - '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.3) + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.3) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-classes@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-classes@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.3) + '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.6) '@babel/helper-split-export-declaration': 7.22.6 globals: 11.12.0 dev: true - /@babel/plugin-transform-computed-properties@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-computed-properties@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 '@babel/template': 7.24.0 dev: true - /@babel/plugin-transform-destructuring@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-destructuring@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-dotall-regex@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-dotall-regex@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.3) + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-duplicate-keys@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-duplicate-keys@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-dynamic-import@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-dynamic-import@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-exponentiation-operator@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-exponentiation-operator@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-export-namespace-from@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-export-namespace-from@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-for-of@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-for-of@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 dev: true - /@babel/plugin-transform-function-name@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-function-name@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-function-name': 7.23.0 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-json-strings@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-json-strings@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-literals@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-literals@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-logical-assignment-operators@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-logical-assignment-operators@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.3) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-member-expression-literals@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-member-expression-literals@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-modules-amd@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-modules-amd@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3) + '@babel/core': 7.24.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-modules-commonjs@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-modules-commonjs@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3) + '@babel/core': 7.24.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.0 '@babel/helper-simple-access': 7.22.5 dev: true - /@babel/plugin-transform-modules-systemjs@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-modules-systemjs@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3) + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.0 '@babel/helper-validator-identifier': 7.22.20 dev: true - /@babel/plugin-transform-modules-umd@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-modules-umd@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3) + '@babel/core': 7.24.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.24.3): + /@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.24.6): resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.3 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.3) + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-new-target@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-new-target@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-nullish-coalescing-operator@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-nullish-coalescing-operator@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-numeric-separator@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-numeric-separator@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.3) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-object-rest-spread@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-object-rest-spread@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.3) - '@babel/plugin-transform-parameters': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-transform-parameters': 7.24.1(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-object-super@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-object-super@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.3) + '@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-optional-catch-binding@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-optional-catch-binding@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-optional-chaining@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-optional-chaining@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-parameters@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-parameters@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-private-methods@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-private-methods@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 - '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.3) + '@babel/core': 7.24.6 + '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-private-property-in-object@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-private-property-in-object@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.3) + '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.3) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-property-literals@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-property-literals@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-regenerator@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-regenerator@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 regenerator-transform: 0.15.2 dev: true - /@babel/plugin-transform-reserved-words@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-reserved-words@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-shorthand-properties@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-shorthand-properties@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-spread@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-spread@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 dev: true - /@babel/plugin-transform-sticky-regex@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-sticky-regex@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-template-literals@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-template-literals@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-typeof-symbol@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-typeof-symbol@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-typescript@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-typescript@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-liYSESjX2fZ7JyBFkYG78nfvHlMKE6IpNdTVnxmlYUR+j5ZLsitFbaAE+eJSK2zPPkNWNw4mXL51rQ8WrvdK0w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.3) + '@babel/helper-create-class-features-plugin': 7.24.1(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-syntax-typescript': 7.24.1(@babel/core@7.24.6) dev: true - /@babel/plugin-transform-unicode-escapes@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-unicode-escapes@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-unicode-property-regex@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-unicode-property-regex@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.3) + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-unicode-regex@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-unicode-regex@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.3) + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-transform-unicode-sets-regex@7.24.1(@babel/core@7.24.3): + /@babel/plugin-transform-unicode-sets-regex@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.3 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.3) + '@babel/core': 7.24.6 + '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.6) '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/preset-env@7.24.3(@babel/core@7.24.3): + /@babel/preset-env@7.24.3(@babel/core@7.24.6): resolution: {integrity: sha512-fSk430k5c2ff8536JcPvPWK4tZDwehWLGlBp0wrsBUjZVdeQV6lePbwKWZaZfK2vnh/1kQX1PzAJWsnBmVgGJA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/compat-data': 7.24.1 - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-plugin-utils': 7.24.0 '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.3) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.3) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.3) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.3) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.3) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.3) - '@babel/plugin-syntax-import-assertions': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-syntax-import-attributes': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.3) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.3) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.3) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.3) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.3) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.3) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.3) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.3) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.3) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.3) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.3) - '@babel/plugin-transform-arrow-functions': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-async-generator-functions': 7.24.3(@babel/core@7.24.3) - '@babel/plugin-transform-async-to-generator': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-block-scoped-functions': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-block-scoping': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-class-properties': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-class-static-block': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-classes': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-computed-properties': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-destructuring': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-dotall-regex': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-duplicate-keys': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-dynamic-import': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-exponentiation-operator': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-export-namespace-from': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-for-of': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-function-name': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-json-strings': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-literals': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-logical-assignment-operators': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-member-expression-literals': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-modules-amd': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-modules-systemjs': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-modules-umd': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.24.3) - '@babel/plugin-transform-new-target': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-nullish-coalescing-operator': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-numeric-separator': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-object-rest-spread': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-object-super': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-optional-catch-binding': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-optional-chaining': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-parameters': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-private-methods': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-private-property-in-object': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-property-literals': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-regenerator': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-reserved-words': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-shorthand-properties': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-spread': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-sticky-regex': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-template-literals': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-typeof-symbol': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-unicode-escapes': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-unicode-property-regex': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-unicode-regex': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-unicode-sets-regex': 7.24.1(@babel/core@7.24.3) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.3) - babel-plugin-polyfill-corejs2: 0.4.10(@babel/core@7.24.3) - babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.3) - babel-plugin-polyfill-regenerator: 0.6.1(@babel/core@7.24.3) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.6) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.6) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.6) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.6) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-import-assertions': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-syntax-import-attributes': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.6) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.6) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.6) + '@babel/plugin-transform-arrow-functions': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-async-generator-functions': 7.24.3(@babel/core@7.24.6) + '@babel/plugin-transform-async-to-generator': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-block-scoped-functions': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-block-scoping': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-class-properties': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-class-static-block': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-classes': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-computed-properties': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-destructuring': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-dotall-regex': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-duplicate-keys': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-dynamic-import': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-exponentiation-operator': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-export-namespace-from': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-for-of': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-function-name': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-json-strings': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-literals': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-logical-assignment-operators': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-member-expression-literals': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-modules-amd': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-modules-systemjs': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-modules-umd': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.24.6) + '@babel/plugin-transform-new-target': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-nullish-coalescing-operator': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-numeric-separator': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-object-rest-spread': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-object-super': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-optional-catch-binding': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-optional-chaining': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-parameters': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-private-methods': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-private-property-in-object': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-property-literals': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-regenerator': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-reserved-words': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-shorthand-properties': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-spread': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-sticky-regex': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-template-literals': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-typeof-symbol': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-escapes': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-property-regex': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-regex': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-unicode-sets-regex': 7.24.1(@babel/core@7.24.6) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.6) + babel-plugin-polyfill-corejs2: 0.4.10(@babel/core@7.24.6) + babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.6) + babel-plugin-polyfill-regenerator: 0.6.1(@babel/core@7.24.6) core-js-compat: 3.36.1 semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.3): + /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.6): resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 '@babel/types': 7.24.0 esutils: 2.0.3 dev: true - /@babel/preset-typescript@7.24.1(@babel/core@7.24.3): + /@babel/preset-typescript@7.24.1(@babel/core@7.24.6): resolution: {integrity: sha512-1DBaMmRDpuYQBPWD8Pf/WEwCrtgRHxsZnP4mIy9G/X+hFfbI47Q2G4t1Paakld84+qsk2fSsUPMKg71jkoOOaQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@babel/helper-plugin-utils': 7.24.0 '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.3) - '@babel/plugin-transform-typescript': 7.24.1(@babel/core@7.24.3) + '@babel/plugin-syntax-jsx': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-modules-commonjs': 7.24.1(@babel/core@7.24.6) + '@babel/plugin-transform-typescript': 7.24.1(@babel/core@7.24.6) dev: true /@babel/regjsgen@0.8.0: @@ -1312,6 +1598,15 @@ packages: '@babel/types': 7.24.0 dev: true + /@babel/template@7.24.6: + resolution: {integrity: sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/types': 7.24.6 + dev: true + /@babel/traverse@7.24.1: resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==} engines: {node: '>=6.9.0'} @@ -1330,6 +1625,24 @@ packages: - supports-color dev: true + /@babel/traverse@7.24.6: + resolution: {integrity: sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.6 + '@babel/generator': 7.24.6 + '@babel/helper-environment-visitor': 7.24.6 + '@babel/helper-function-name': 7.24.6 + '@babel/helper-hoist-variables': 7.24.6 + '@babel/helper-split-export-declaration': 7.24.6 + '@babel/parser': 7.24.6 + '@babel/types': 7.24.6 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/types@7.24.0: resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} engines: {node: '>=6.9.0'} @@ -1339,6 +1652,15 @@ packages: to-fast-properties: 2.0.0 dev: true + /@babel/types@7.24.6: + resolution: {integrity: sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.24.6 + '@babel/helper-validator-identifier': 7.24.6 + to-fast-properties: 2.0.0 + dev: true + /@bcoe/v8-coverage@0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true @@ -1347,8 +1669,8 @@ packages: resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==} dev: true - /@codemirror/view@6.26.0: - resolution: {integrity: sha512-nSSmzONpqsNzshPOxiKhK203R6BvABepugAe34QfQDbNDslyjkqBuKgrK5ZBvqNXpfxz5iLrlGTmEfhbQyH46A==} + /@codemirror/view@6.26.3: + resolution: {integrity: sha512-gmqxkPALZjkgSxIeeweY/wGQXBfwTUaLs8h7OKtSwfbj9Ct3L11lD+u1sS7XHppxFQoMDiMDp07P9f3I2jWOHw==} dependencies: '@codemirror/state': 6.4.1 style-mod: 4.1.2 @@ -1911,6 +2233,25 @@ packages: - supports-color dev: true + /babel-jest@27.5.1(@babel/core@7.24.6): + 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.24.6 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 27.5.1(@babel/core@7.24.6) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + dev: true + /babel-plugin-istanbul@6.1.1: resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} engines: {node: '>=8'} @@ -1934,38 +2275,38 @@ packages: '@types/babel__traverse': 7.20.5 dev: true - /babel-plugin-polyfill-corejs2@0.4.10(@babel/core@7.24.3): + /babel-plugin-polyfill-corejs2@0.4.10(@babel/core@7.24.6): resolution: {integrity: sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: '@babel/compat-data': 7.24.1 - '@babel/core': 7.24.3 - '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.24.3) + '@babel/core': 7.24.6 + '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.24.6) semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.3): + /babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.6): resolution: {integrity: sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.24.3 - '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.24.3) + '@babel/core': 7.24.6 + '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.24.6) core-js-compat: 3.36.1 transitivePeerDependencies: - supports-color dev: true - /babel-plugin-polyfill-regenerator@0.6.1(@babel/core@7.24.3): + /babel-plugin-polyfill-regenerator@0.6.1(@babel/core@7.24.6): resolution: {integrity: sha512-JfTApdE++cgcTWjsiCQlLyFBMbTUft9ja17saCc93lgV33h4tuCVj7tlvu//qpLwaG+3yEz7/KhahGrUMkVq9g==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.24.3 - '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.24.3) + '@babel/core': 7.24.6 + '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.24.6) transitivePeerDependencies: - supports-color dev: true @@ -1990,6 +2331,26 @@ packages: '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.3) dev: true + /babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.6): + resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.6 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.6) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.6) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.6) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.6) + dev: true + /babel-preset-jest@27.5.1(@babel/core@7.24.3): resolution: {integrity: sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -2001,6 +2362,17 @@ packages: babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.3) dev: true + /babel-preset-jest@27.5.1(@babel/core@7.24.6): + 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.24.6 + babel-plugin-jest-hoist: 27.5.1 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.6) + dev: true + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true @@ -3973,14 +4345,14 @@ packages: resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} dev: true - /obsidian@1.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.26.0): - resolution: {integrity: sha512-2Zg9vlaEZw6fd2AohcdrC1kV+lZcb4a1Ju6GcIwdWaGOWj6l//7wbKD6vVhO2GlfoQRGARYu++eLo7FEc+f6Tw==} + /obsidian@1.5.7-1(@codemirror/state@6.4.1)(@codemirror/view@6.26.3): + resolution: {integrity: sha512-T5ZRuQ1FnfXqEoakTTHVDYvzUEEoT8zSPnQCW31PVgYwG4D4tZCQfKHN2hTz1ifnCe8upvwa6mBTAP2WUA5Vng==} peerDependencies: '@codemirror/state': ^6.0.0 '@codemirror/view': ^6.0.0 dependencies: '@codemirror/state': 6.4.1 - '@codemirror/view': 6.26.0 + '@codemirror/view': 6.26.3 '@types/codemirror': 5.60.8 moment: 2.29.4 dev: true @@ -4079,6 +4451,10 @@ packages: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} dev: true + /picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + dev: true + /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} @@ -4502,7 +4878,7 @@ packages: engines: {node: '>= 0.4'} dev: true - /svelte-check@2.10.3(@babel/core@7.24.3)(svelte@3.59.2): + /svelte-check@2.10.3(@babel/core@7.24.6)(svelte@3.59.2): resolution: {integrity: sha512-Nt1aWHTOKFReBpmJ1vPug0aGysqPwJh2seM1OvICfM2oeyaA62mOiy5EvkXhltGfhCcIQcq2LoE0l1CwcWPjlw==} hasBin: true peerDependencies: @@ -4515,7 +4891,7 @@ packages: picocolors: 1.0.0 sade: 1.8.1 svelte: 3.59.2 - svelte-preprocess: 4.10.7(@babel/core@7.24.3)(svelte@3.59.2)(typescript@4.9.5) + svelte-preprocess: 4.10.7(@babel/core@7.24.6)(svelte@3.59.2)(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - '@babel/core' @@ -4541,7 +4917,7 @@ packages: svelte: 3.59.2 dev: true - /svelte-preprocess@4.10.7(@babel/core@7.24.3)(svelte@3.59.2)(typescript@4.9.5): + /svelte-preprocess@4.10.7(@babel/core@7.24.6)(svelte@3.59.2)(typescript@4.9.5): resolution: {integrity: sha512-sNPBnqYD6FnmdBrUmBCaqS00RyCsCpj2BG58A1JBswNF7b0OKviwxqVrOL/CKyJrLSClrSeqQv5BXNg2RUbPOw==} engines: {node: '>= 9.11.2'} requiresBuild: true @@ -4582,7 +4958,7 @@ packages: typescript: optional: true dependencies: - '@babel/core': 7.24.3 + '@babel/core': 7.24.6 '@types/pug': 2.0.10 '@types/sass': 1.45.0 detect-indent: 6.1.0 @@ -4911,8 +5287,8 @@ packages: yargs-parser: 20.2.9 dev: true - github.com/scambier/minisearch/fbe02d564ff2a6332a463932e624ab0516778d71: - resolution: {tarball: https://codeload.github.com/scambier/minisearch/tar.gz/fbe02d564ff2a6332a463932e624ab0516778d71} + github.com/scambier/minisearch/699babb6732423565868708e2b024d941de05180: + resolution: {tarball: https://codeload.github.com/scambier/minisearch/tar.gz/699babb6732423565868708e2b024d941de05180} name: minisearch version: 6.3.0 dev: false diff --git a/src/__tests__/query-tests.ts b/src/__tests__/query-tests.ts index ef9155e..8ef016e 100644 --- a/src/__tests__/query-tests.ts +++ b/src/__tests__/query-tests.ts @@ -6,7 +6,7 @@ describe('The Query class', () => { it('should correctly parse string queries', () => { // Act - const query = new Query(stringQuery) + const query = new Query(stringQuery, { ignoreDiacritics: true }) // Assert const segments = query.query.text @@ -25,7 +25,7 @@ describe('The Query class', () => { it('should not exclude words when there is no space before', () => { // Act - const query = new Query('foo bar-baz') + const query = new Query('foo bar-baz', { ignoreDiacritics: true }) // Assert expect(query.query.exclude.text).toHaveLength(0) @@ -34,7 +34,7 @@ describe('The Query class', () => { describe('.getExactTerms()', () => { it('should an array of strings containg "exact" values', () => { // Act - const query = new Query(stringQuery) + const query = new Query(stringQuery, { ignoreDiacritics: true }) // Assert expect(query.getExactTerms()).toEqual(['lorem ipsum', 'sit amet']) diff --git a/src/cache-manager.ts b/src/cache-manager.ts index a2e155d..5189e81 100644 --- a/src/cache-manager.ts +++ b/src/cache-manager.ts @@ -1,9 +1,5 @@ import { Notice, TFile } from 'obsidian' -import { - type DocumentRef, - getTextExtractor, - type IndexedDocument, -} from './globals' +import type { DocumentRef, IndexedDocument } from './globals' import { extractHeadingsFromCache, getAliasesFromMetadata, @@ -11,168 +7,19 @@ import { isFileCanvas, isFileFromDataloomPlugin, isFileImage, - isFilePDF, isFileOffice, - isFilePlaintext, - isFilenameIndexable, + isFilePDF, logDebug, makeMD5, removeDiacritics, stripMarkdownCharacters, } from './tools/utils' import type { CanvasData } from 'obsidian/canvas' -import type { AsPlainObject } from 'minisearch' import type MiniSearch from 'minisearch' -import { getObsidianApp } from './stores/obsidian-app' -import { OmnisearchCache } from './database' -import { getSettings } from './settings' +import type { AsPlainObject } from 'minisearch' +import type OmnisearchPlugin from './main' -/** - * This function is responsible for extracting the text from a file and - * returning it as an `IndexedDocument` object. - * @param path - */ -async function getAndMapIndexedDocument( - path: string -): Promise { - const app = getObsidianApp() - const settings = getSettings() - const file = app.vault.getAbstractFileByPath(path) - if (!file) throw new Error(`Invalid file path: "${path}"`) - if (!(file instanceof TFile)) throw new Error(`Not a TFile: "${path}"`) - let content: string | null = null - - const extractor = getTextExtractor() - - // ** Plain text ** - // Just read the file content - if (isFilePlaintext(path)) { - content = await app.vault.cachedRead(file) - } - - // ** Canvas ** - // Extract the text fields from the json - else if (isFileCanvas(path)) { - const canvas = JSON.parse(await app.vault.cachedRead(file)) as CanvasData - let texts: string[] = [] - // Concatenate text from the canvas fields - for (const node of canvas.nodes) { - if (node.type === 'text') { - texts.push(node.text) - } else if (node.type === 'file') { - texts.push(node.file) - } - } - for (const edge of canvas.edges.filter(e => !!e.label)) { - texts.push(edge.label!) - } - content = texts.join('\r\n') - } - - // ** Dataloom plugin ** - else if (isFileFromDataloomPlugin(path)) { - try { - const data = JSON.parse(await app.vault.cachedRead(file)) - // data is a json object, we recursively iterate the keys - // and concatenate the values if the key is "markdown" - const texts: string[] = [] - const iterate = (obj: any) => { - for (const key in obj) { - if (typeof obj[key] === 'object') { - iterate(obj[key]) - } else if (key === 'content') { - texts.push(obj[key]) - } - } - } - iterate(data) - content = texts.join('\r\n') - } catch (e) { - console.error('Omnisearch: Error while parsing Dataloom file', path) - console.error(e) - } - } - - // ** Image ** - else if ( - isFileImage(path) && - settings.imagesIndexing && - extractor?.canFileBeExtracted(path) - ) { - content = await extractor.extractText(file) - } - // ** PDF ** - else if ( - isFilePDF(path) && - settings.PDFIndexing && - extractor?.canFileBeExtracted(path) - ) { - content = await extractor.extractText(file) - } - - // ** Office document ** - else if ( - isFileOffice(path) && - settings.officeIndexing && - extractor?.canFileBeExtracted(path) - ) { - content = await extractor.extractText(file) - } - - // ** Unsupported files ** - else if (isFilenameIndexable(path)) { - content = file.path - } - - if (content === null || content === undefined) { - // This shouldn't happen - console.warn(`Omnisearch: ${content} content for file`, file.path) - 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) - } - } - } - - const tags = getTagsFromMetadata(metadata) - return { - basename: file.basename, - content, - /** Content without diacritics and markdown chars */ - cleanedContent: stripMarkdownCharacters(removeDiacritics(content)), - path: file.path, - mtime: file.stat.mtime, - - tags: tags, - unmarkedTags: tags.map(t => t.replace('#', '')), - aliases: getAliasesFromMetadata(metadata).join(''), - headings1: metadata ? extractHeadingsFromCache(metadata, 1).join(' ') : '', - headings2: metadata ? extractHeadingsFromCache(metadata, 2).join(' ') : '', - headings3: metadata ? extractHeadingsFromCache(metadata, 3).join(' ') : '', - } -} - -class CacheManager { +export class CacheManager { /** * Show an empty input field next time the user opens Omnisearch modal */ @@ -184,13 +31,15 @@ class CacheManager { */ private documents: Map = new Map() + constructor(private plugin: OmnisearchPlugin) {} + /** * Set or update the live cache with the content of the given file. * @param path */ public async addToLiveCache(path: string): Promise { try { - const doc = await getAndMapIndexedDocument(path) + const doc = await this.getAndMapIndexedDocument(path) if (!doc.path) { console.error( `Missing .path field in IndexedDocument "${doc.basename}", skipping` @@ -224,7 +73,8 @@ class CacheManager { return } this.nextQueryIsEmpty = false - const database = OmnisearchCache.getInstance() + // TODO: rename + const database = this.plugin.cache let history = await database.searchHistory.toArray() history = history.filter(s => s.query !== query).reverse() history.unshift({ query }) @@ -237,7 +87,7 @@ class CacheManager { * @returns The search history, in reverse chronological order */ public async getSearchHistory(): Promise> { - const data = (await OmnisearchCache.getInstance().searchHistory.toArray()) + const data = (await this.plugin.cache.searchHistory.toArray()) .reverse() .map(o => o.query) if (this.nextQueryIsEmpty) { @@ -246,8 +96,6 @@ class CacheManager { return data } - //#region Minisearch - public getDocumentsChecksum(documents: IndexedDocument[]): string { return makeMD5( JSON.stringify( @@ -263,13 +111,15 @@ class CacheManager { ) } + //#region Minisearch + public async getMinisearchCache(): Promise<{ paths: DocumentRef[] data: AsPlainObject } | null> { try { const cachedIndex = ( - await OmnisearchCache.getInstance().minisearch.toArray() + await this.plugin.cache.minisearch.toArray() )[0] return cachedIndex } catch (e) { @@ -287,7 +137,8 @@ class CacheManager { indexed: Map ): Promise { const paths = Array.from(indexed).map(([k, v]) => ({ path: k, mtime: v })) - const database = OmnisearchCache.getInstance() + // TODO: rename + const database = this.plugin.cache await database.minisearch.clear() await database.minisearch.add({ date: new Date().toISOString(), @@ -297,7 +148,197 @@ class CacheManager { console.log('Omnisearch - Search cache written') } - //#endregion Minisearch -} + public isFileIndexable(path: string): boolean { + return this.isFilenameIndexable(path) || this.isContentIndexable(path) + } -export const cacheManager = new CacheManager() + //#endregion Minisearch + + public isContentIndexable(path: string): boolean { + const settings = this.plugin.settings + const hasTextExtractor = !!this.plugin.getTextExtractor() + const canIndexPDF = hasTextExtractor && settings.PDFIndexing + const canIndexImages = hasTextExtractor && settings.imagesIndexing + return ( + this.isFilePlaintext(path) || + isFileCanvas(path) || + isFileFromDataloomPlugin(path) || + (canIndexPDF && isFilePDF(path)) || + (canIndexImages && isFileImage(path)) + ) + } + + public isFilenameIndexable(path: string): boolean { + return ( + this.canIndexUnsupportedFiles() || + this.isFilePlaintext(path) || + isFileCanvas(path) || + isFileFromDataloomPlugin(path) + ) + } + + public canIndexUnsupportedFiles(): boolean { + return ( + this.plugin.settings.unsupportedFilesIndexing === 'yes' || + (this.plugin.settings.unsupportedFilesIndexing === 'default' && + !!this.plugin.app.vault.getConfig('showUnsupportedFiles')) + ) + } + + private isFilePlaintext(path: string): boolean { + return [...this.plugin.settings.indexedFileTypes, 'md'].some(t => + path.endsWith(`.${t}`) + ) + } + + /** + * This function is responsible for extracting the text from a file and + * returning it as an `IndexedDocument` object. + * @param path + */ + private async getAndMapIndexedDocument( + path: string + ): Promise { + const app = this.plugin.app + const file = app.vault.getAbstractFileByPath(path) + if (!file) throw new Error(`Invalid file path: "${path}"`) + if (!(file instanceof TFile)) throw new Error(`Not a TFile: "${path}"`) + let content: string | null = null + + const extractor = this.plugin.getTextExtractor() + + // ** Plain text ** + // Just read the file content + if (this.isFilePlaintext(path)) { + content = await app.vault.cachedRead(file) + } + + // ** Canvas ** + // Extract the text fields from the json + else if (isFileCanvas(path)) { + const canvas = JSON.parse(await app.vault.cachedRead(file)) as CanvasData + let texts: string[] = [] + // Concatenate text from the canvas fields + for (const node of canvas.nodes) { + if (node.type === 'text') { + texts.push(node.text) + } else if (node.type === 'file') { + texts.push(node.file) + } + } + for (const edge of canvas.edges.filter(e => !!e.label)) { + texts.push(edge.label!) + } + content = texts.join('\r\n') + } + + // ** Dataloom plugin ** + else if (isFileFromDataloomPlugin(path)) { + try { + const data = JSON.parse(await app.vault.cachedRead(file)) + // data is a json object, we recursively iterate the keys + // and concatenate the values if the key is "markdown" + const texts: string[] = [] + const iterate = (obj: any) => { + for (const key in obj) { + if (typeof obj[key] === 'object') { + iterate(obj[key]) + } else if (key === 'content') { + texts.push(obj[key]) + } + } + } + iterate(data) + content = texts.join('\r\n') + } catch (e) { + console.error('Omnisearch: Error while parsing Dataloom file', path) + console.error(e) + } + } + + // ** Image ** + else if ( + isFileImage(path) && + this.plugin.settings.imagesIndexing && + extractor?.canFileBeExtracted(path) + ) { + content = await extractor.extractText(file) + } + // ** PDF ** + else if ( + isFilePDF(path) && + this.plugin.settings.PDFIndexing && + extractor?.canFileBeExtracted(path) + ) { + content = await extractor.extractText(file) + } + + // ** Office document ** + else if ( + isFileOffice(path) && + this.plugin.settings.officeIndexing && + extractor?.canFileBeExtracted(path) + ) { + content = await extractor.extractText(file) + } + + // ** Unsupported files ** + else if (this.isFilenameIndexable(path)) { + content = file.path + } + + if (content === null || content === undefined) { + // This shouldn't happen + console.warn(`Omnisearch: ${content} content for file`, file.path) + 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) + } + } + } + + const tags = getTagsFromMetadata(metadata) + return { + basename: file.basename, + content, + /** Content without diacritics and markdown chars */ + cleanedContent: stripMarkdownCharacters(removeDiacritics(content)), + path: file.path, + mtime: file.stat.mtime, + + tags: tags, + unmarkedTags: tags.map(t => t.replace('#', '')), + 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/components/InputSearch.svelte b/src/components/InputSearch.svelte index b940547..d29044e 100644 --- a/src/components/InputSearch.svelte +++ b/src/components/InputSearch.svelte @@ -2,10 +2,11 @@ import { debounce } from 'obsidian' import { toggleInputComposition } from 'src/globals' import { createEventDispatcher, tick } from 'svelte' - import { cacheManager } from '../cache-manager' + import type OmnisearchPlugin from '../main' export let initialValue = '' export let placeholder = '' + export let plugin: OmnisearchPlugin let initialSet = false let value = '' let elInput: HTMLInputElement @@ -39,7 +40,7 @@ const debouncedOnInput = debounce(() => { // If typing a query and not executing it, // the next time we open the modal, the search field will be empty - cacheManager.addToSearchHistory('') + plugin.cacheManager.addToSearchHistory('') dispatch('input', value) }, 300) @@ -50,13 +51,13 @@ bind:this="{elInput}" bind:value="{value}" class="prompt-input" - use:selectInput on:compositionend="{_ => toggleInputComposition(false)}" on:compositionstart="{_ => toggleInputComposition(true)}" on:input="{debouncedOnInput}" placeholder="{placeholder}" spellcheck="false" - type="text" /> + type="text" + use:selectInput /> - \ No newline at end of file + diff --git a/src/components/ModalInFile.svelte b/src/components/ModalInFile.svelte index 81c33da..6216f49 100644 --- a/src/components/ModalInFile.svelte +++ b/src/components/ModalInFile.svelte @@ -9,7 +9,7 @@ } from 'src/globals' import { getCtrlKeyLabel, loopIndex } from 'src/tools/utils' import { onDestroy, onMount, tick } from 'svelte' - import { MarkdownView, App, Platform } from 'obsidian' + import { MarkdownView, Platform } from 'obsidian' import ModalContainer from './ModalContainer.svelte' import { OmnisearchInFileModal, @@ -18,14 +18,13 @@ import ResultItemInFile from './ResultItemInFile.svelte' import { Query } from 'src/search/query' import { openNote } from 'src/tools/notes' - import { stringsToRegex } from 'src/tools/text-processing' - import { Omnisearch } from 'src/search/omnisearch' + import type OmnisearchPlugin from '../main' + export let plugin: OmnisearchPlugin export let modal: OmnisearchInFileModal export let parent: OmnisearchVaultModal | null = null export let singleFilePath = '' export let previousQuery: string | undefined - export let app: App let searchQuery: string let groupedOffsets: number[] = [] @@ -51,10 +50,12 @@ $: (async () => { if (searchQuery) { - query = new Query(searchQuery) + query = new Query(searchQuery, { + ignoreDiacritics: plugin.settings.ignoreDiacritics, + }) note = ( - await Omnisearch.getInstance().getSuggestions(query, { + await plugin.omnisearch.getSuggestions(query, { singleFilePath, }) )[0] ?? null @@ -131,12 +132,12 @@ if (parent) parent.close() // Open (or switch focus to) the note - const reg = stringsToRegex(note.foundWords) + const reg = plugin.textProcessor.stringsToRegex(note.foundWords) reg.exec(note.content) - await openNote(note, reg.lastIndex, newTab) + await openNote(plugin.app, note, reg.lastIndex, newTab) // Move cursor to the match - const view = app.workspace.getActiveViewOfType(MarkdownView) + const view = plugin.app.workspace.getActiveViewOfType(MarkdownView) if (!view) { // Not an editable document, so no cursor to place return @@ -155,12 +156,13 @@ } function switchToVaultModal(): void { - new OmnisearchVaultModal(app, searchQuery ?? previousQuery).open() + new OmnisearchVaultModal(plugin, searchQuery ?? previousQuery).open() modal.close() } @@ -175,6 +177,7 @@ {#if groupedOffsets.length && note} {#each groupedOffsets as offset, i} - import { App, MarkdownView, Notice, Platform, TFile } from 'obsidian' + import { MarkdownView, Notice, Platform, TFile } from 'obsidian' import { onDestroy, onMount, tick } from 'svelte' import InputSearch from './InputSearch.svelte' import ModalContainer from './ModalContainer.svelte' @@ -24,16 +24,13 @@ } from 'src/components/modals' import ResultItemVault from './ResultItemVault.svelte' import { Query } from 'src/search/query' - import * as NotesIndex from '../notes-index' - import { cacheManager } from '../cache-manager' import { cancelable, CancelablePromise } from 'cancelable-promise' import { debounce } from 'lodash-es' - import { Omnisearch } from 'src/search/omnisearch' - import { getSettings } from 'src/settings' + import type OmnisearchPlugin from '../main' export let modal: OmnisearchVaultModal export let previousQuery: string | undefined - export let app: App + export let plugin: OmnisearchPlugin let selectedIndex = 0 let historySearchIndex = 0 @@ -51,7 +48,7 @@ $: selectedNote = resultNotes[selectedIndex] $: searchQuery = searchQuery ?? previousQuery - $: if (getSettings().openInNewPane) { + $: if (plugin.settings.openInNewPane) { openInNewPaneKey = '↵' openInCurrentPaneKey = getCtrlKeyLabel() + ' ↵' createInNewPaneKey = 'shift ↵' @@ -103,7 +100,7 @@ eventBus.on('vault', Action.PrevSearchHistory, prevSearchHistory) eventBus.on('vault', Action.NextSearchHistory, nextSearchHistory) eventBus.on('vault', Action.OpenInNewLeaf, openNoteInNewLeaf) - await NotesIndex.refreshIndex() + await plugin.notesIndexer.refreshIndex() await updateResultsDebounced() }) @@ -113,7 +110,9 @@ async function prevSearchHistory() { // Filter out the empty string, if it's there - const history = (await cacheManager.getSearchHistory()).filter(s => s) + const history = (await plugin.cacheManager.getSearchHistory()).filter( + s => s + ) if (++historySearchIndex >= history.length) { historySearchIndex = 0 } @@ -122,7 +121,9 @@ } async function nextSearchHistory() { - const history = (await cacheManager.getSearchHistory()).filter(s => s) + const history = (await plugin.cacheManager.getSearchHistory()).filter( + s => s + ) if (--historySearchIndex < 0) { historySearchIndex = history.length ? history.length - 1 : 0 } @@ -138,10 +139,12 @@ cancelableQuery.cancel() cancelableQuery = null } - query = new Query(searchQuery) + query = new Query(searchQuery, { + ignoreDiacritics: plugin.settings.ignoreDiacritics, + }) cancelableQuery = cancelable( new Promise(resolve => { - resolve(Omnisearch.getInstance().getSuggestions(query)) + resolve(plugin.omnisearch.getSuggestions(query)) }) ) resultNotes = await cancelableQuery @@ -188,7 +191,7 @@ function saveCurrentQuery() { if (searchQuery) { - cacheManager.addToSearchHistory(searchQuery) + plugin.cacheManager.addToSearchHistory(searchQuery) } } @@ -199,7 +202,7 @@ ) { saveCurrentQuery() const offset = note.matches?.[0]?.offset ?? 0 - openNote(note, offset, newPane, newLeaf) + openNote(plugin.app, note, offset, newPane, newLeaf) } async function onClickCreateNote(_e: MouseEvent) { @@ -211,7 +214,7 @@ }): Promise { if (searchQuery) { try { - await createNote(searchQuery, opt?.newLeaf) + await createNote(plugin.app, searchQuery, opt?.newLeaf) } catch (e) { new Notice((e as Error).message) return @@ -222,11 +225,11 @@ function insertLink(): void { if (!selectedNote) return - const file = app.vault + const file = plugin.app.vault .getMarkdownFiles() .find(f => f.path === selectedNote.path) - const active = app.workspace.getActiveFile() - const view = app.workspace.getActiveViewOfType(MarkdownView) + const active = plugin.app.workspace.getActiveFile() + const view = plugin.app.workspace.getActiveViewOfType(MarkdownView) if (!view?.editor) { new Notice('Omnisearch - Error - No active editor', 3000) return @@ -235,7 +238,7 @@ // Generate link let link: string if (file && active) { - link = app.fileManager.generateMarkdownLink(file, active.path) + link = plugin.app.fileManager.generateMarkdownLink(file, active.path) } else { link = `[[${selectedNote.basename}.${getExtension(selectedNote.path)}]]` } @@ -249,7 +252,7 @@ modal.close() } - function switchToInFileModal(): void { + function switchToInFileModal(): void { // Do nothing if the selectedNote is a PDF, // or if there is 0 match (e.g indexing in progress) if ( @@ -264,15 +267,15 @@ if (selectedNote) { // Open in-file modal for selected search result - const file = app.vault.getAbstractFileByPath(selectedNote.path) + const file = plugin.app.vault.getAbstractFileByPath(selectedNote.path) if (file && file instanceof TFile) { - new OmnisearchInFileModal(app, file, searchQuery).open() + new OmnisearchInFileModal(plugin, file, searchQuery).open() } } else { // Open in-file modal for active file - const view = app.workspace.getActiveViewOfType(MarkdownView) + const view = plugin.app.workspace.getActiveViewOfType(MarkdownView) if (view?.file) { - new OmnisearchInFileModal(app, view.file, searchQuery).open() + new OmnisearchInFileModal(plugin, view.file, searchQuery).open() } } } @@ -295,11 +298,12 @@
- {#if getSettings().showCreateButton} + {#if plugin.settings.showCreateButton} {/if} {#if Platform.isMobile} @@ -317,7 +321,7 @@ {#each resultNotes as result, i} {#if !resultNotes.length && searchQuery && !searching} We found 0 result for your search here. - {#if getSettings().simpleSearch && searchQuery + {#if plugin.settings.simpleSearch && searchQuery .split(SPACE_OR_PUNCTUATION) .some(w => w.length < 3)}
diff --git a/src/components/ResultItemInFile.svelte b/src/components/ResultItemInFile.svelte index 01ee5ba..ba9f148 100644 --- a/src/components/ResultItemInFile.svelte +++ b/src/components/ResultItemInFile.svelte @@ -1,24 +1,24 @@ + on:mousemove + selected="{selected}">
- {@html highlightText(cleanedContent, note.matches)} + {@html plugin.textProcessor.highlightText(cleanedContent, note.matches)}
diff --git a/src/components/ResultItemVault.svelte b/src/components/ResultItemVault.svelte index b1f9970..d5a6387 100644 --- a/src/components/ResultItemVault.svelte +++ b/src/components/ResultItemVault.svelte @@ -9,18 +9,12 @@ pathWithoutFilename, } from '../tools/utils' import ResultItemContainer from './ResultItemContainer.svelte' - import { TFile, setIcon, App } from 'obsidian' - import { cloneDeep } from 'lodash-es' - import { - stringsToRegex, - getMatches, - makeExcerpt, - highlightText, - } from 'src/tools/text-processing' + import { TFile, setIcon } from 'obsidian' + import type OmnisearchPlugin from '../main' export let selected = false export let note: ResultNote - export let app: App + export let plugin: OmnisearchPlugin let imagePath: string | null = null let title = '' @@ -31,16 +25,15 @@ $: { imagePath = null if (isFileImage(note.path)) { - const file = app.vault.getAbstractFileByPath(note.path) + const file = plugin.app.vault.getAbstractFileByPath(note.path) if (file instanceof TFile) { - imagePath = app.vault.getResourcePath(file) + imagePath = plugin.app.vault.getResourcePath(file) } } } - $: reg = stringsToRegex(note.foundWords) - $: matchesTitle = getMatches(title, reg) - $: matchesNotePath = getMatches(notePath, reg) - $: cleanedContent = makeExcerpt(note.content, note.matches[0]?.offset ?? -1) + $: matchesTitle = plugin.textProcessor.getMatches(title, note.foundWords) + $: matchesNotePath = plugin.textProcessor.getMatches(notePath, note.foundWords) + $: cleanedContent = plugin.textProcessor.makeExcerpt(note.content, note.matches[0]?.offset ?? -1) $: glyph = false //cacheManager.getLiveDocument(note.path)?.doesNotExist $: { title = note.basename @@ -63,15 +56,15 @@
- {@html highlightText(title, matchesTitle)} + {@html plugin.textProcessor.highlightText(title, matchesTitle)} .{getExtension(note.path)} @@ -91,14 +84,14 @@ {#if notePath}
- {@html highlightText(notePath, matchesNotePath)} + {@html plugin.textProcessor.highlightText(notePath, matchesNotePath)}
{/if}
{#if $showExcerpt}
- {@html highlightText(cleanedContent, note.matches)} + {@html plugin.textProcessor.highlightText(cleanedContent, note.matches)}
{/if} diff --git a/src/components/modals.ts b/src/components/modals.ts index 66164f9..e439866 100644 --- a/src/components/modals.ts +++ b/src/components/modals.ts @@ -1,15 +1,14 @@ -import { App, MarkdownView, Modal, TFile } from 'obsidian' +import { MarkdownView, Modal, TFile } from 'obsidian' import type { Modifier } from 'obsidian' import ModalVault from './ModalVault.svelte' import ModalInFile from './ModalInFile.svelte' import { Action, eventBus, EventNames, isInputComposition } from '../globals' -import { cacheManager } from 'src/cache-manager' -import { getSettings } from 'src/settings' +import type OmnisearchPlugin from 'src/main' abstract class OmnisearchModal extends Modal { - protected constructor(app: App) { - super(app) - const settings = getSettings() + protected constructor(plugin: OmnisearchPlugin) { + super(plugin.app) + const settings = plugin.settings // Remove all the default modal's children // so that we can more easily customize it @@ -153,20 +152,20 @@ abstract class OmnisearchModal extends Modal { export class OmnisearchVaultModal extends OmnisearchModal { /** * Instanciate the Omnisearch vault modal - * @param app + * @param plugin * @param query The query to pre-fill the search field with */ - constructor(app: App, query?: string) { - super(app) + constructor(plugin: OmnisearchPlugin, query?: string) { + super(plugin) // Selected text in the editor - const selectedText = app.workspace + const selectedText = plugin.app.workspace .getActiveViewOfType(MarkdownView) ?.editor.getSelection() - cacheManager.getSearchHistory().then(history => { + plugin.cacheManager.getSearchHistory().then(history => { // Previously searched query (if enabled in settings) - const previous = getSettings().showPreviousQueryResults + const previous = plugin.settings.showPreviousQueryResults ? history[0] : null @@ -174,7 +173,7 @@ export class OmnisearchVaultModal extends OmnisearchModal { const cmp = new ModalVault({ target: this.modalEl, props: { - app, + plugin, modal: this, previousQuery: query || selectedText || previous || '', }, @@ -190,17 +189,17 @@ export class OmnisearchVaultModal extends OmnisearchModal { export class OmnisearchInFileModal extends OmnisearchModal { constructor( - app: App, + plugin: OmnisearchPlugin, file: TFile, searchQuery: string = '', parent?: OmnisearchModal ) { - super(app) + super(plugin) const cmp = new ModalInFile({ target: this.modalEl, props: { - app, + plugin, modal: this, singleFilePath: file.path, parent: parent, diff --git a/src/database.ts b/src/database.ts index 649fc7c..7464398 100644 --- a/src/database.ts +++ b/src/database.ts @@ -2,16 +2,10 @@ import Dexie from 'dexie' import type { AsPlainObject } from 'minisearch' import type { DocumentRef } from './globals' import { Notice } from 'obsidian' -import { getObsidianApp } from './stores/obsidian-app' +import type OmnisearchPlugin from './main' export class OmnisearchCache extends Dexie { public static readonly dbVersion = 8 - public static getDbName() { - return 'omnisearch/cache/' + getObsidianApp().appId - } - - private static instance: OmnisearchCache - searchHistory!: Dexie.Table<{ id?: number; query: string }, number> minisearch!: Dexie.Table< { @@ -22,8 +16,8 @@ export class OmnisearchCache extends Dexie { string > - private constructor() { - super(OmnisearchCache.getDbName()) + constructor(private plugin: OmnisearchPlugin) { + super(OmnisearchCache.getDbName(plugin.app.appId)) // Database structure this.version(OmnisearchCache.dbVersion).stores({ searchHistory: '++id', @@ -31,15 +25,19 @@ export class OmnisearchCache extends Dexie { }) } + public static getDbName(appId: string) { + return 'omnisearch/cache/' + appId + } + //#endregion Table declarations /** * Deletes Omnisearch databases that have an older version than the current one */ - public static async clearOldDatabases(): Promise { + public async clearOldDatabases(): Promise { const toDelete = (await indexedDB.databases()).filter( db => - db.name === OmnisearchCache.getDbName() && + db.name === OmnisearchCache.getDbName(this.plugin.app.appId) && // version multiplied by 10 https://github.com/dexie/Dexie.js/issues/59 db.version !== OmnisearchCache.dbVersion * 10 ) @@ -53,13 +51,6 @@ export class OmnisearchCache extends Dexie { } } - public static getInstance() { - if (!OmnisearchCache.instance) { - OmnisearchCache.instance = new OmnisearchCache() - } - return OmnisearchCache.instance - } - public async clearCache() { new Notice('Omnisearch - Cache cleared. Please restart Obsidian.') await this.minisearch.clear() diff --git a/src/globals.ts b/src/globals.ts index a63c64c..716fbe2 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -1,7 +1,6 @@ import { EventBus } from './tools/event-bus' import { writable } from 'svelte/store' import type { TFile } from 'obsidian' -import { getObsidianApp } from './stores/obsidian-app' export const regexLineSplit = /\r?\n|\r|((\.|\?|!)( |\r?\n|\r))/g export const regexYaml = /^---\s*\n(.*?)\n?^---\s?/ms @@ -92,27 +91,11 @@ export function isInputComposition(): boolean { return inComposition } -/** - * Plugin dependency - Chs Patch for Chinese word segmentation - * @returns - */ -export function getChsSegmenter(): any | undefined { - return (getObsidianApp() as any).plugins.plugins['cm-chs-patch'] -} - export type TextExtractorApi = { extractText: (file: TFile) => Promise canFileBeExtracted: (filePath: string) => boolean } -/** - * Plugin dependency - Text Extractor - * @returns - */ -export function getTextExtractor(): TextExtractorApi | undefined { - return (getObsidianApp() as any).plugins?.plugins?.['text-extractor']?.api -} - export const SEPARATORS = /[|\t\n\r\^"= -#%-*,.`\/<>:;?@[-\]_{}\u00A0\u00A1\u00A7\u00AB\u00B6\u00B7\u00BB\u00BF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u09FD\u0A76\u0AF0\u0C77\u0C84\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166E\u1680\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2000-\u200A\u2010-\u2029\u202F-\u2043\u2045-\u2051\u2053-\u205F\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E4F\u3000-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]/ .toString() diff --git a/src/main.ts b/src/main.ts index fd2312b..5bfeb70 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,54 +4,66 @@ import { OmnisearchVaultModal, } from './components/modals' import { - getSettings, + getDefaultSettings, isCacheEnabled, isPluginDisabled, loadSettings, + type OmnisearchSettings, saveSettings, SettingsTab, showExcerpt, } from './settings' -import { eventBus, EventNames, indexingStep, IndexingStepType } from './globals' -import api, { notifyOnIndexed } from './tools/api' -import { isFileIndexable, logDebug } from './tools/utils' +import { eventBus, EventNames, indexingStep, IndexingStepType, type TextExtractorApi } from './globals' +import { notifyOnIndexed, registerAPI } from './tools/api' import { OmnisearchCache } from './database' -import * as NotesIndex from './notes-index' -import { cacheManager } from './cache-manager' -import { setObsidianApp } from './stores/obsidian-app' import { Omnisearch } from './search/omnisearch' +import { CacheManager } from './cache-manager' +import { logDebug } from './tools/utils' +import { NotesIndexer } from './notes-index' +import { TextProcessor } from "./tools/text-processing"; export default class OmnisearchPlugin extends Plugin { // FIXME: fix the type public apiHttpServer: null | any = null + public settings: OmnisearchSettings = getDefaultSettings(this.app) + + // FIXME: merge cache and cacheManager, or find other names + public readonly cacheManager: CacheManager + public readonly cache = new OmnisearchCache(this) + + public readonly notesIndexer = new NotesIndexer(this) + public readonly textProcessor = new TextProcessor(this) + // TODO: rename to searchEngine + public readonly omnisearch = new Omnisearch(this) + private ribbonButton?: HTMLElement constructor(app: App, manifest: PluginManifest) { super(app, manifest) - setObsidianApp(this.app) + this.cacheManager = new CacheManager(this) } async onload(): Promise { - await loadSettings(this) + this.settings = await loadSettings(this) this.addSettingTab(new SettingsTab(this)) if (!Platform.isMobile) { import('./tools/api-server').then( - m => (this.apiHttpServer = m.getServer()) + m => (this.apiHttpServer = m.getServer(this)) ) } - if (isPluginDisabled()) { + if (isPluginDisabled(this.app)) { console.log('Omnisearch - Plugin disabled') return } await cleanOldCacheFiles(this.app) - await OmnisearchCache.clearOldDatabases() + await this.cache.clearOldDatabases() registerAPI(this) - const settings = getSettings() + const settings = this.settings if (settings.ribbonIcon) { this.addRibbonButton() } @@ -67,7 +79,7 @@ export default class OmnisearchPlugin extends Plugin { id: 'show-modal', name: 'Vault search', callback: () => { - new OmnisearchVaultModal(this.app).open() + new OmnisearchVaultModal(this).open() }, }) @@ -76,18 +88,18 @@ export default class OmnisearchPlugin extends Plugin { name: 'In-file search', editorCallback: (_editor, view) => { if (view.file) { - new OmnisearchInFileModal(this.app, view.file).open() + new OmnisearchInFileModal(this, view.file).open() } }, }) - const searchEngine = Omnisearch.getInstance() + const searchEngine = this.omnisearch this.app.workspace.onLayoutReady(async () => { // Listeners to keep the search index up-to-date this.registerEvent( this.app.vault.on('create', file => { - if (isFileIndexable(file.path)) { + if (this.cacheManager.isFileIndexable(file.path)) { logDebug('Indexing new file', file.path) // await cacheManager.addToLiveCache(file.path) searchEngine.addFromPaths([file.path]) @@ -97,25 +109,25 @@ export default class OmnisearchPlugin extends Plugin { this.registerEvent( this.app.vault.on('delete', file => { logDebug('Removing file', file.path) - cacheManager.removeFromLiveCache(file.path) + this.cacheManager.removeFromLiveCache(file.path) searchEngine.removeFromPaths([file.path]) }) ) this.registerEvent( this.app.vault.on('modify', async file => { - if (isFileIndexable(file.path)) { + if (this.cacheManager.isFileIndexable(file.path)) { logDebug('Updating file', file.path) - await cacheManager.addToLiveCache(file.path) - NotesIndex.markNoteForReindex(file) + await this.cacheManager.addToLiveCache(file.path) + this.notesIndexer.markNoteForReindex(file) } }) ) this.registerEvent( this.app.vault.on('rename', async (file, oldPath) => { - if (isFileIndexable(file.path)) { + if (this.cacheManager.isFileIndexable(file.path)) { logDebug('Renaming file', file.path) - cacheManager.removeFromLiveCache(oldPath) - await cacheManager.addToLiveCache(file.path) + this.cacheManager.removeFromLiveCache(oldPath) + await this.cacheManager.addToLiveCache(file.path) searchEngine.removeFromPaths([oldPath]) await searchEngine.addFromPaths([file.path]) } @@ -132,7 +144,6 @@ export default class OmnisearchPlugin extends Plugin { } async executeFirstLaunchTasks(): Promise { - const settings = getSettings() const code = '1.21.0' // if (settings.welcomeMessage !== code && getTextExtractor()) { // const welcome = new DocumentFragment() @@ -141,8 +152,8 @@ export default class OmnisearchPlugin extends Plugin { // }) // new Notice(welcome, 20_000) // } - settings.welcomeMessage = code - await this.saveData(settings) + this.settings.welcomeMessage = code + await this.saveData(this.settings) } async onunload(): Promise { @@ -151,14 +162,14 @@ export default class OmnisearchPlugin extends Plugin { // Clear cache when disabling Omnisearch if (process.env.NODE_ENV === 'production') { - await OmnisearchCache.getInstance().clearCache() + await this.cache.clearCache() } this.apiHttpServer.close() } addRibbonButton(): void { this.ribbonButton = this.addRibbonIcon('search', 'Omnisearch', _evt => { - new OmnisearchVaultModal(this.app).open() + new OmnisearchVaultModal(this).open() }) } @@ -168,10 +179,28 @@ export default class OmnisearchPlugin extends Plugin { } } + /** + * Plugin dependency - Chs Patch for Chinese word segmentation + * @returns + */ + public getChsSegmenter(): any | undefined { + return (this.app as any).plugins.plugins['cm-chs-patch'] + } + + /** + * Plugin dependency - Text Extractor + * @returns + */ + public getTextExtractor(): TextExtractorApi | undefined { + return (this.app as any).plugins?.plugins?.['text-extractor']?.api + } + private async populateIndex(): Promise { console.time('Omnisearch - Indexing total time') indexingStep.set(IndexingStepType.ReadingFiles) - const files = this.app.vault.getFiles().filter(f => isFileIndexable(f.path)) + const files = this.app.vault + .getFiles() + .filter(f => this.cacheManager.isFileIndexable(f.path)) console.log(`Omnisearch - ${files.length} files total`) console.log( `Omnisearch - Cache is ${isCacheEnabled() ? 'enabled' : 'disabled'}` @@ -179,7 +208,7 @@ export default class OmnisearchPlugin extends Plugin { // Map documents in the background // Promise.all(files.map(f => cacheManager.addToLiveCache(f.path))) - const searchEngine = Omnisearch.getInstance() + const searchEngine = this.omnisearch if (isCacheEnabled()) { console.time('Omnisearch - Loading index from cache') indexingStep.set(IndexingStepType.LoadingCache) @@ -221,17 +250,16 @@ export default class OmnisearchPlugin extends Plugin { if ((diff.toRemove.length || diff.toAdd.length) && isCacheEnabled()) { indexingStep.set(IndexingStepType.WritingCache) - const settings = getSettings() - + // Disable settings.useCache while writing the cache, in case it freezes - settings.useCache = false + this.settings.useCache = false await saveSettings(this) // Write the cache await searchEngine.writeToCache() // Re-enable settings.caching - settings.useCache = true + this.settings.useCache = true await saveSettings(this) } @@ -265,16 +293,3 @@ async function cleanOldCacheFiles(app: App) { } } } - -function registerAPI(plugin: OmnisearchPlugin): void { - // Url scheme for obsidian://omnisearch?query=foobar - plugin.registerObsidianProtocolHandler('omnisearch', params => { - new OmnisearchVaultModal(plugin.app, params.query).open() - }) - - // Public api - // @ts-ignore - globalThis['omnisearch'] = api - // Deprecated - ;(plugin.app as any).plugins.plugins.omnisearch.api = api -} diff --git a/src/notes-index.ts b/src/notes-index.ts index 09c99fd..b18730d 100644 --- a/src/notes-index.ts +++ b/src/notes-index.ts @@ -1,5 +1,30 @@ import type { TAbstractFile } from 'obsidian' -import { Omnisearch } from './search/omnisearch' +import type OmnisearchPlugin from './main' + +export class NotesIndexer { + private notesToReindex = new Set() + + constructor(private plugin: OmnisearchPlugin) {} + + /** + * Updated notes are not reindexed immediately for performance reasons. + * They're added to a list, and reindex is done the next time we open Omnisearch. + */ + public markNoteForReindex(note: TAbstractFile): void { + this.notesToReindex.add(note) + } + + public async refreshIndex(): Promise { + const paths = [...this.notesToReindex].map(n => n.path) + if (paths.length) { + const searchEngine = this.plugin.omnisearch + searchEngine.removeFromPaths(paths) + await searchEngine.addFromPaths(paths) + this.notesToReindex.clear() + // console.log(`Omnisearch - Reindexed ${paths.length} file(s)`) + } + } +} // /** // * Index a non-existing note. @@ -28,24 +53,3 @@ import { Omnisearch } from './search/omnisearch' // } // // searchEngine.addDocuments([note]) // } - -const notesToReindex = new Set() - -/** - * Updated notes are not reindexed immediately for performance reasons. - * They're added to a list, and reindex is done the next time we open Omnisearch. - */ -export function markNoteForReindex(note: TAbstractFile): void { - notesToReindex.add(note) -} - -export async function refreshIndex(): Promise { - const paths = [...notesToReindex].map(n => n.path) - if (paths.length) { - const searchEngine = Omnisearch.getInstance() - searchEngine.removeFromPaths(paths) - await 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 index cb2b72a..82256f1 100644 --- a/src/search/omnisearch.ts +++ b/src/search/omnisearch.ts @@ -4,79 +4,34 @@ import type { DocumentRef, IndexedDocument, ResultNote } from '../globals' import { chunkArray, logDebug, removeDiacritics } from '../tools/utils' import { Notice } from 'obsidian' import type { Query } from './query' -import { cacheManager } from '../cache-manager' import { sortBy } from 'lodash-es' -import { getMatches, stringsToRegex } from 'src/tools/text-processing' -import { tokenizeForIndexing, tokenizeForSearch } from './tokenizer' -import { getObsidianApp } from '../stores/obsidian-app' -import { getSettings } from 'src/settings' +import type OmnisearchPlugin from '../main' +import { Tokenizer } from './tokenizer' +// TODO: rename to SearchEngine export class Omnisearch { - - private static instance: Omnisearch - - app = getObsidianApp() - settings = getSettings() - - public static getInstance(): Omnisearch { - if (!Omnisearch.instance) { - Omnisearch.instance = new Omnisearch(); - } - return Omnisearch.instance; - } - - public static readonly options: Options = { - tokenize: tokenizeForIndexing, - extractField: (doc, fieldName) => { - if (fieldName === 'directory') { - // return path without the filename - const parts = doc.path.split('/') - parts.pop() - return parts.join('/') - } - return (doc as any)[fieldName] - }, - processTerm: (term: string) => - (getSettings().ignoreDiacritics ? removeDiacritics(term) : term).toLowerCase(), - idField: 'path', - fields: [ - 'basename', - // Different from `path`, since `path` is the unique index and needs to include the filename - 'directory', - '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 tokenizer: Tokenizer private minisearch: MiniSearch /** Map */ private indexedDocuments: Map = new Map() // private previousResults: SearchResult[] = [] // private previousQuery: Query | null = null - private constructor() { - this.minisearch = new MiniSearch(Omnisearch.options) + constructor(protected plugin: OmnisearchPlugin) { + this.tokenizer = new Tokenizer(plugin) + this.minisearch = new MiniSearch(this.getOptions()) } /** * Return true if the cache is valid */ async loadCache(): Promise { - const cache = await cacheManager.getMinisearchCache() + const cache = await this.plugin.cacheManager.getMinisearchCache() if (cache) { - this.minisearch = await MiniSearch.loadJSAsync(cache.data, Omnisearch.options) + this.minisearch = await MiniSearch.loadJSAsync( + cache.data, + this.getOptions() + ) this.indexedDocuments = new Map(cache.paths.map(o => [o.path, o.mtime])) return true } @@ -117,7 +72,9 @@ export class Omnisearch { logDebug('Adding files', paths) let documents = ( await Promise.all( - paths.map(async path => await cacheManager.getDocument(path)) + paths.map( + async path => await this.plugin.cacheManager.getDocument(path) + ) ) ).filter(d => !!d?.path) logDebug('Sorting documents to first index markdown') @@ -164,6 +121,7 @@ export class Omnisearch { query: Query, options: { prefixLength: number; singleFilePath?: string } ): Promise { + const settings = this.plugin.settings if (query.isEmpty()) { // this.previousResults = [] // this.previousQuery = null @@ -174,7 +132,7 @@ export class Omnisearch { logDebug('Starting search for', query) let fuzziness: number - switch (this.settings.fuzziness) { + switch (settings.fuzziness) { case '0': fuzziness = 0 break @@ -186,7 +144,7 @@ export class Omnisearch { break } - const searchTokens = tokenizeForSearch(query.segmentsToStr()) + const searchTokens = this.tokenizer.tokenizeForSearch(query.segmentsToStr()) logDebug(JSON.stringify(searchTokens, null, 1)) let results = this.minisearch.search(searchTokens, { prefix: term => term.length >= options.prefixLength, @@ -196,14 +154,14 @@ export class Omnisearch { fuzzy: term => term.length <= 3 ? 0 : term.length <= 5 ? fuzziness / 2 : fuzziness, boost: { - basename: this.settings.weightBasename, - directory: this.settings.weightDirectory, - aliases: this.settings.weightBasename, - headings1: this.settings.weightH1, - headings2: this.settings.weightH2, - headings3: this.settings.weightH3, - tags: this.settings.weightUnmarkedTags, - unmarkedTags: this.settings.weightUnmarkedTags, + basename: settings.weightBasename, + directory: settings.weightDirectory, + aliases: settings.weightBasename, + headings1: settings.weightH1, + headings2: settings.weightH2, + headings3: settings.weightH3, + tags: settings.weightUnmarkedTags, + unmarkedTags: settings.weightUnmarkedTags, }, // The query is already tokenized, don't tokenize again tokenize: text => [text], @@ -249,25 +207,25 @@ export class Omnisearch { logDebug( 'searching with downranked folders', - this.settings.downrankedFoldersFilters + settings.downrankedFoldersFilters ) // Hide or downrank files that are in Obsidian's excluded list - if (this.settings.hideExcluded) { + if (settings.hideExcluded) { // Filter the files out results = results.filter( result => !( - this.app.metadataCache.isUserIgnored && - this.app.metadataCache.isUserIgnored(result.id) + this.plugin.app.metadataCache.isUserIgnored && + this.plugin.app.metadataCache.isUserIgnored(result.id) ) ) } else { // Just downrank them results.forEach(result => { if ( - this.app.metadataCache.isUserIgnored && - this.app.metadataCache.isUserIgnored(result.id) + this.plugin.app.metadataCache.isUserIgnored && + this.plugin.app.metadataCache.isUserIgnored(result.id) ) { result.score /= 10 } @@ -279,10 +237,10 @@ export class Omnisearch { for (const result of results) { const path = result.id - if (this.settings.downrankedFoldersFilters.length > 0) { + if (settings.downrankedFoldersFilters.length > 0) { // downrank files that are in folders listed in the downrankedFoldersFilters let downrankingFolder = false - this.settings.downrankedFoldersFilters.forEach(filter => { + settings.downrankedFoldersFilters.forEach(filter => { if (path.startsWith(filter)) { // we don't want the filter to match the folder sources, e.g. // it needs to match a whole folder name @@ -299,7 +257,7 @@ export class Omnisearch { const pathPartsLength = pathParts.length for (let i = 0; i < pathPartsLength; i++) { const pathPart = pathParts[i] - if (this.settings.downrankedFoldersFilters.includes(pathPart)) { + if (settings.downrankedFoldersFilters.includes(pathPart)) { result.score /= 10 break } @@ -307,9 +265,9 @@ export class Omnisearch { } // Boost custom properties - const metadata = this.app.metadataCache.getCache(path) + const metadata = this.plugin.app.metadataCache.getCache(path) if (metadata) { - for (const { name, weight } of this.settings.weightCustomProperties) { + for (const { name, weight } of settings.weightCustomProperties) { const values = metadata?.frontmatter?.[name] if (values && result.terms.some(t => values.includes(t))) { logDebug(`Boosting field "${name}" x${weight} for ${path}`) @@ -333,7 +291,9 @@ export class Omnisearch { if (results.length) logDebug('First result:', results[0]) const documents = await Promise.all( - results.map(async result => await cacheManager.getDocument(result.id)) + results.map( + async result => await this.plugin.cacheManager.getDocument(result.id) + ) ) // If the search query contains quotes, filter out results that don't have the exact match @@ -389,7 +349,7 @@ export class Omnisearch { ): Promise { // Get the raw results let results: SearchResult[] - if (this.settings.simpleSearch) { + if (this.plugin.settings.simpleSearch) { results = await this.search(query, { prefixLength: 3, singleFilePath: options?.singleFilePath, @@ -402,7 +362,9 @@ export class Omnisearch { } const documents = await Promise.all( - results.map(async result => await cacheManager.getDocument(result.id)) + results.map( + async result => await this.plugin.cacheManager.getDocument(result.id) + ) ) // Map the raw results to get usable suggestions @@ -435,9 +397,9 @@ export class Omnisearch { logDebug('Matching tokens:', foundWords) logDebug('Getting matches locations...') - const matches = getMatches( + const matches = this.plugin.textProcessor.getMatches( note.content, - stringsToRegex(foundWords), + foundWords, query ) logDebug(`Matches for ${note.basename}`, matches) @@ -453,10 +415,49 @@ export class Omnisearch { } public async writeToCache(): Promise { - await cacheManager.writeMinisearchCache( + await this.plugin.cacheManager.writeMinisearchCache( this.minisearch, this.indexedDocuments ) } -} + private getOptions(): Options { + return { + tokenize: this.tokenizer.tokenizeForIndexing, + extractField: (doc, fieldName) => { + if (fieldName === 'directory') { + // return path without the filename + const parts = doc.path.split('/') + parts.pop() + return parts.join('/') + } + return (doc as any)[fieldName] + }, + processTerm: (term: string) => + (this.plugin.settings.ignoreDiacritics + ? removeDiacritics(term) + : term + ).toLowerCase(), + idField: 'path', + fields: [ + 'basename', + // Different from `path`, since `path` is the unique index and needs to include the filename + 'directory', + '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 + ) + } + }, + } + } +} diff --git a/src/search/query.ts b/src/search/query.ts index 7a7b283..2264832 100644 --- a/src/search/query.ts +++ b/src/search/query.ts @@ -1,4 +1,3 @@ -import { getSettings } from 'src/settings' import { removeDiacritics } from '../tools/utils' import { parse } from 'search-query-parser' @@ -14,8 +13,8 @@ export class Query { } #inQuotes: string[] - constructor(text = '') { - if (getSettings().ignoreDiacritics) { + constructor(text = '', options: { ignoreDiacritics: boolean }) { + if (options.ignoreDiacritics) { text = removeDiacritics(text) } const parsed = parse(text.toLowerCase(), { diff --git a/src/search/tokenizer.ts b/src/search/tokenizer.ts index 33eb7d4..9ede21a 100644 --- a/src/search/tokenizer.ts +++ b/src/search/tokenizer.ts @@ -1,93 +1,96 @@ import type { QueryCombination } from 'minisearch' -import { - BRACKETS_AND_SPACE, - SPACE_OR_PUNCTUATION, - chsRegex, - getChsSegmenter, -} from 'src/globals' -import { getSettings } from 'src/settings' +import { BRACKETS_AND_SPACE, chsRegex, SPACE_OR_PUNCTUATION } from 'src/globals' import { logDebug, splitCamelCase, splitHyphens } from 'src/tools/utils' +import type OmnisearchPlugin from '../main' + const markdownLinkExtractor = require('markdown-link-extractor') -function tokenizeWords(text: string, { skipChs = false } = {}): string[] { - const tokens = text.split(BRACKETS_AND_SPACE) - if (skipChs) return tokens - return tokenizeChsWord(tokens) -} +export class Tokenizer { + constructor(private plugin: OmnisearchPlugin) {} -function tokenizeTokens(text: string, { skipChs = false } = {}): string[] { - const tokens = text.split(SPACE_OR_PUNCTUATION) - if (skipChs) return tokens - return tokenizeChsWord(tokens) -} + /** + * Tokenization for indexing will possibly return more tokens than the original text. + * This is because we combine different methods of tokenization to get the best results. + * @param text + * @returns + */ + public tokenizeForIndexing(text: string): string[] { + const words = this.tokenizeWords(text) + let urls: string[] = [] + if (this.plugin.settings.tokenizeUrls) { + try { + urls = markdownLinkExtractor(text) + } catch (e) { + logDebug('Error extracting urls', e) + } + } -function tokenizeChsWord(tokens: string[]): string[] { - const segmenter = getChsSegmenter() - if (!segmenter) return tokens - return tokens.flatMap(word => - chsRegex.test(word) ? segmenter.cut(word, { search: true }) : [word] - ) -} + let tokens = this.tokenizeTokens(text, { skipChs: true }) -/** - * Tokenization for indexing will possibly return more tokens than the original text. - * This is because we combine different methods of tokenization to get the best results. - * @param text - * @returns - */ -export function tokenizeForIndexing(text: string): string[] { - const words = tokenizeWords(text) - let urls: string[] = [] - if (getSettings().tokenizeUrls) { - try { - urls = markdownLinkExtractor(text) - } catch (e) { - logDebug('Error extracting urls', e) + // Split hyphenated tokens + tokens = [...tokens, ...tokens.flatMap(splitHyphens)] + + // Split camelCase tokens into "camel" and "case + tokens = [...tokens, ...tokens.flatMap(splitCamelCase)] + + // Add whole words (aka "not tokens") + tokens = [...tokens, ...words] + + // Add urls + if (urls.length) { + tokens = [...tokens, ...urls] + } + + // Remove duplicates + tokens = [...new Set(tokens)] + + return tokens + } + + /** + * Search tokenization will use the same tokenization methods as indexing, + * but will combine each group with "OR" operators + * @param text + * @returns + */ + public tokenizeForSearch(text: string): QueryCombination { + // Extract urls and remove them from the query + const urls: string[] = markdownLinkExtractor(text) + text = urls.reduce((acc, url) => acc.replace(url, ''), text) + + const tokens = [...this.tokenizeTokens(text), ...urls].filter(Boolean) + + return { + combineWith: 'OR', + queries: [ + { combineWith: 'AND', queries: tokens }, + { + combineWith: 'AND', + queries: this.tokenizeWords(text).filter(Boolean), + }, + { combineWith: 'AND', queries: tokens.flatMap(splitHyphens) }, + { combineWith: 'AND', queries: tokens.flatMap(splitCamelCase) }, + ], } } - let tokens = tokenizeTokens(text, { skipChs: true }) - - // Split hyphenated tokens - tokens = [...tokens, ...tokens.flatMap(splitHyphens)] - - // Split camelCase tokens into "camel" and "case - tokens = [...tokens, ...tokens.flatMap(splitCamelCase)] - - // Add whole words (aka "not tokens") - tokens = [...tokens, ...words] - - // Add urls - if (urls.length) { - tokens = [...tokens, ...urls] + private tokenizeWords(text: string, { skipChs = false } = {}): string[] { + const tokens = text.split(BRACKETS_AND_SPACE) + if (skipChs) return tokens + return this.tokenizeChsWord(tokens) } - // Remove duplicates - tokens = [...new Set(tokens)] + private tokenizeTokens(text: string, { skipChs = false } = {}): string[] { + const tokens = text.split(SPACE_OR_PUNCTUATION) + if (skipChs) return tokens + return this.tokenizeChsWord(tokens) + } - return tokens -} - -/** - * Search tokenization will use the same tokenization methods as indexing, - * but will combine each group with "OR" operators - * @param text - * @returns - */ -export function tokenizeForSearch(text: string): QueryCombination { - // Extract urls and remove them from the query - const urls: string[] = markdownLinkExtractor(text) - text = urls.reduce((acc, url) => acc.replace(url, ''), text) - - const tokens = [...tokenizeTokens(text), ...urls].filter(Boolean) - - return { - combineWith: 'OR', - queries: [ - { combineWith: 'AND', queries: tokens }, - { combineWith: 'AND', queries: tokenizeWords(text).filter(Boolean) }, - { combineWith: 'AND', queries: tokens.flatMap(splitHyphens) }, - { combineWith: 'AND', queries: tokens.flatMap(splitCamelCase) }, - ], + private tokenizeChsWord(tokens: string[]): string[] { + const segmenter = this.plugin.getChsSegmenter() + if (!segmenter) return tokens + return tokens.flatMap(word => + chsRegex.test(word) ? segmenter.cut(word, { search: true }) : [word] + ) } } diff --git a/src/settings.ts b/src/settings.ts index 20b41dd..e37df51 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,5 +1,6 @@ // noinspection CssUnresolvedCustomProperty import { + App, Notice, Platform, Plugin, @@ -8,10 +9,9 @@ import { SliderComponent, } from 'obsidian' import { writable } from 'svelte/store' -import { K_DISABLE_OMNISEARCH, getTextExtractor } from './globals' +import { K_DISABLE_OMNISEARCH } from './globals' import type OmnisearchPlugin from './main' -import { getObsidianApp } from './stores/obsidian-app' -import { OmnisearchCache } from './database' +import { enablePrintDebug } from "./tools/utils"; interface WeightingSettings { weightBasename: number @@ -91,7 +91,9 @@ export class SettingsTab extends PluginSettingTab { display(): void { const { containerEl } = this - const database = OmnisearchCache.getInstance() + // TODO: rename + const database = this.plugin.cache + const textExtractor = this.plugin.getTextExtractor() containerEl.empty() if (this.app.loadLocalStorage(K_DISABLE_OMNISEARCH) == '1') { @@ -114,7 +116,7 @@ export class SettingsTab extends PluginSettingTab { const indexingDesc = new DocumentFragment() indexingDesc.createSpan({}, span => { span.innerHTML = `⚠️ Changing indexing settings will clear the cache, and requires a restart of Obsidian.

` - if (getTextExtractor()) { + if (textExtractor) { span.innerHTML += ` 👍 You have installed Text Extractor, Omnisearch can use it to index PDFs and images contents.
Text extraction only works on desktop, but the cache can be synchronized with your mobile device.` @@ -135,7 +137,7 @@ export class SettingsTab extends PluginSettingTab { }) new Setting(containerEl) .setName( - `PDFs content indexing ${getTextExtractor() ? '' : '⚠️ Disabled'}` + `PDFs content indexing ${textExtractor ? '' : '⚠️ Disabled'}` ) .setDesc(indexPDFsDesc) .addToggle(toggle => @@ -145,7 +147,7 @@ export class SettingsTab extends PluginSettingTab { await saveSettings(this.plugin) }) ) - .setDisabled(!getTextExtractor()) + .setDisabled(!textExtractor) // Images Indexing const indexImagesDesc = new DocumentFragment() @@ -153,7 +155,7 @@ export class SettingsTab extends PluginSettingTab { span.innerHTML = `Omnisearch will use Text Extractor to OCR your images and index their content.` }) new Setting(containerEl) - .setName(`Images OCR indexing ${getTextExtractor() ? '' : '⚠️ Disabled'}`) + .setName(`Images OCR indexing ${textExtractor ? '' : '⚠️ Disabled'}`) .setDesc(indexImagesDesc) .addToggle(toggle => toggle.setValue(settings.imagesIndexing).onChange(async v => { @@ -162,7 +164,7 @@ export class SettingsTab extends PluginSettingTab { await saveSettings(this.plugin) }) ) - .setDisabled(!getTextExtractor()) + .setDisabled(!textExtractor) // Office Documents Indexing const indexOfficesDesc = new DocumentFragment() @@ -171,7 +173,7 @@ export class SettingsTab extends PluginSettingTab { }) new Setting(containerEl) .setName( - `Documents content indexing ${getTextExtractor() ? '' : '⚠️ Disabled'}` + `Documents content indexing ${textExtractor ? '' : '⚠️ Disabled'}` ) .setDesc(indexOfficesDesc) .addToggle(toggle => @@ -181,7 +183,7 @@ export class SettingsTab extends PluginSettingTab { await saveSettings(this.plugin) }) ) - .setDisabled(!getTextExtractor()) + .setDisabled(!textExtractor) // Index filenames of unsupported files const indexUnsupportedDesc = new DocumentFragment() @@ -472,32 +474,34 @@ export class SettingsTab extends PluginSettingTab { //#region Results Weighting + const defaultSettings = getDefaultSettings(this.app) + new Setting(containerEl).setName('Results weighting').setHeading() new Setting(containerEl) .setName( - `File name & declared aliases (default: ${getDefaultSettings().weightBasename})` + `File name & declared aliases (default: ${defaultSettings.weightBasename})` ) .addSlider(cb => this.weightSlider(cb, 'weightBasename')) new Setting(containerEl) - .setName(`File directory (default: ${getDefaultSettings().weightDirectory})`) + .setName(`File directory (default: ${defaultSettings.weightDirectory})`) .addSlider(cb => this.weightSlider(cb, 'weightDirectory')) new Setting(containerEl) - .setName(`Headings level 1 (default: ${getDefaultSettings().weightH1})`) + .setName(`Headings level 1 (default: ${defaultSettings.weightH1})`) .addSlider(cb => this.weightSlider(cb, 'weightH1')) new Setting(containerEl) - .setName(`Headings level 2 (default: ${getDefaultSettings().weightH2})`) + .setName(`Headings level 2 (default: ${defaultSettings.weightH2})`) .addSlider(cb => this.weightSlider(cb, 'weightH2')) new Setting(containerEl) - .setName(`Headings level 3 (default: ${getDefaultSettings().weightH3})`) + .setName(`Headings level 3 (default: ${defaultSettings.weightH3})`) .addSlider(cb => this.weightSlider(cb, 'weightH3')) new Setting(containerEl) - .setName(`Tags (default: ${getDefaultSettings().weightUnmarkedTags})`) + .setName(`Tags (default: ${defaultSettings.weightUnmarkedTags})`) .addSlider(cb => this.weightSlider(cb, 'weightUnmarkedTags')) //#region Specific tags @@ -545,7 +549,7 @@ export class SettingsTab extends PluginSettingTab { // Add a new custom tag new Setting(containerEl).addButton(btn => { btn.setButtonText('Add a new property') - btn.onClick(cb => { + btn.onClick(_cb => { settings.weightCustomProperties.push({ name: '', weight: 1 }) this.display() }) @@ -626,6 +630,7 @@ export class SettingsTab extends PluginSettingTab { .addToggle(toggle => toggle.setValue(settings.verboseLogging).onChange(async v => { settings.verboseLogging = v + enablePrintDebug(v) await saveSettings(this.plugin) }) ) @@ -665,7 +670,7 @@ export class SettingsTab extends PluginSettingTab { .setName('Disable on this device') .setDesc(disableDesc) .addToggle(toggle => - toggle.setValue(isPluginDisabled()).onChange(async v => { + toggle.setValue(isPluginDisabled(this.app)).onChange(async v => { if (v) { this.app.saveLocalStorage(K_DISABLE_OMNISEARCH, '1') } else { @@ -707,8 +712,7 @@ export class SettingsTab extends PluginSettingTab { } } -function getDefaultSettings(): OmnisearchSettings { - const app = getObsidianApp() +export function getDefaultSettings(app: App): OmnisearchSettings { return { useCache: true, hideExcluded: false, @@ -752,32 +756,35 @@ function getDefaultSettings(): OmnisearchSettings { let settings: OmnisearchSettings -export function getSettings(): OmnisearchSettings { - if (!settings) { - settings = Object.assign({}, getDefaultSettings()) as OmnisearchSettings - } - return settings -} +// /** +// * @deprecated +// */ +// export function getSettings(): OmnisearchSettings { +// if (!settings) { +// settings = Object.assign({}, getDefaultSettings()) as OmnisearchSettings +// } +// return settings +// } -export async function loadSettings(plugin: Plugin): Promise { - settings = Object.assign({}, getDefaultSettings(), await plugin.loadData()) +export async function loadSettings( + plugin: Plugin +): Promise { + settings = Object.assign( + {}, + getDefaultSettings(plugin.app), + await plugin.loadData() + ) showExcerpt.set(settings.showExcerpt) + enablePrintDebug(settings.verboseLogging) + return settings } export async function saveSettings(plugin: Plugin): Promise { await plugin.saveData(settings) } -export function isPluginDisabled(): boolean { - return getObsidianApp().loadLocalStorage(K_DISABLE_OMNISEARCH) === '1' -} - -export function canIndexUnsupportedFiles(): boolean { - return ( - settings.unsupportedFilesIndexing === 'yes' || - (settings.unsupportedFilesIndexing === 'default' && - !!getObsidianApp().vault.getConfig('showUnsupportedFiles')) - ) +export function isPluginDisabled(app: App): boolean { + return app.loadLocalStorage(K_DISABLE_OMNISEARCH) === '1' } export function isCacheEnabled(): boolean { diff --git a/src/stores/obsidian-app.ts b/src/stores/obsidian-app.ts deleted file mode 100644 index f9984d5..0000000 --- a/src/stores/obsidian-app.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { App } from 'obsidian' - -let obsidianApp: App | null = null - -export function setObsidianApp(app: App) { - obsidianApp = app -} - -/** - * Helper function to get the Obsidian app instance. - */ -export function getObsidianApp() { - if (!obsidianApp) { - throw new Error('Obsidian app not set') - } - return obsidianApp as App -} diff --git a/src/tools/api-server.ts b/src/tools/api-server.ts index 8d0da04..ec007a4 100644 --- a/src/tools/api-server.ts +++ b/src/tools/api-server.ts @@ -1,10 +1,11 @@ import * as http from 'http' import * as url from 'url' -import api from './api' import { Notice } from 'obsidian' -import { getSettings } from 'src/settings' +import type OmnisearchPlugin from '../main' +import { getApi } from './api' -export function getServer() { +export function getServer(plugin: OmnisearchPlugin) { + const api = getApi(plugin) const server = http.createServer(async function (req, res) { res.setHeader('Access-Control-Allow-Origin', '*') res.setHeader( @@ -47,7 +48,7 @@ export function getServer() { }, () => { console.log(`Omnisearch - Started HTTP server on port ${port}`) - if (getSettings().httpApiNotice) { + if (plugin.settings.httpApiNotice) { new Notice(`Omnisearch - Started HTTP server on port ${port}`) } } @@ -62,9 +63,8 @@ export function getServer() { }, close() { server.close() - const settings = getSettings() console.log(`Omnisearch - Terminated HTTP server`) - if (settings.httpApiEnabled && settings.httpApiNotice) { + if (plugin.settings.httpApiEnabled && plugin.settings.httpApiNotice) { new Notice(`Omnisearch - Terminated HTTP server`) } }, diff --git a/src/tools/api.ts b/src/tools/api.ts index d5d8b9c..802ea3b 100644 --- a/src/tools/api.ts +++ b/src/tools/api.ts @@ -1,9 +1,7 @@ import type { ResultNote } from '../globals' import { Query } from '../search/query' -import { makeExcerpt } from './text-processing' -import { refreshIndex } from '../notes-index' -import { getObsidianApp } from '../stores/obsidian-app' -import { Omnisearch } from 'src/search/omnisearch' +import type OmnisearchPlugin from '../main' +import { OmnisearchVaultModal } from '../components/modals' type ResultNoteApi = { score: number @@ -20,7 +18,6 @@ export type SearchMatchApi = { offset: number } - let notified = false /** @@ -28,15 +25,21 @@ let notified = false */ let onIndexedCallbacks: Array<() => void> = [] -function mapResults(results: ResultNote[]): ResultNoteApi[] { +function mapResults( + plugin: OmnisearchPlugin, + results: ResultNote[] +): ResultNoteApi[] { return results.map(result => { const { score, path, basename, foundWords, matches, content } = result - const excerpt = makeExcerpt(content, matches[0]?.offset ?? -1) + const excerpt = plugin.textProcessor.makeExcerpt( + content, + matches[0]?.offset ?? -1 + ) const res: ResultNoteApi = { score, - vault: getObsidianApp().vault.getName(), + vault: plugin.app.vault.getName(), path, basename, foundWords, @@ -53,27 +56,52 @@ function mapResults(results: ResultNote[]): ResultNoteApi[] { }) } -async function search(q: string): Promise { - const query = new Query(q) - const raw = await Omnisearch.getInstance().getSuggestions(query) - return mapResults(raw) -} - -function registerOnIndexed(cb: () => void): void { - onIndexedCallbacks.push(cb) - // Immediately call the callback if the indexing is already ready done - if (notified) { - cb() - } -} - -function unregisterOnIndexed(cb: () => void): void { - onIndexedCallbacks = onIndexedCallbacks.filter(o => o !== cb) -} - export function notifyOnIndexed(): void { notified = true onIndexedCallbacks.forEach(cb => cb()) } -export default { search, registerOnIndexed, unregisterOnIndexed, refreshIndex } +let registed = false + +export function registerAPI(plugin: OmnisearchPlugin): void { + if (registed) { + return + } + registed = true + + // Url scheme for obsidian://omnisearch?query=foobar + plugin.registerObsidianProtocolHandler('omnisearch', params => { + new OmnisearchVaultModal(plugin, params.query).open() + }) + + const api = getApi(plugin) + + // Public api + // @ts-ignore + globalThis['omnisearch'] = api + // Deprecated + ;(plugin.app as any).plugins.plugins.omnisearch.api = api +} + +export function getApi(plugin: OmnisearchPlugin) { + return { + async search(q: string): Promise { + const query = new Query(q, { + ignoreDiacritics: plugin.settings.ignoreDiacritics, + }) + const raw = await plugin.omnisearch.getSuggestions(query) + return mapResults(plugin, raw) + }, + registerOnIndexed(cb: () => void): void { + onIndexedCallbacks.push(cb) + // Immediately call the callback if the indexing is already ready done + if (notified) { + cb() + } + }, + unregisterOnIndexed(cb: () => void): void { + onIndexedCallbacks = onIndexedCallbacks.filter(o => o !== cb) + }, + refreshIndex: plugin.notesIndexer.refreshIndex, + } +} diff --git a/src/tools/notes.ts b/src/tools/notes.ts index 2ab25b9..270b90a 100644 --- a/src/tools/notes.ts +++ b/src/tools/notes.ts @@ -1,8 +1,8 @@ -import { type CachedMetadata, MarkdownView, TFile } from 'obsidian' +import { type App, type CachedMetadata, MarkdownView, TFile } from 'obsidian' import type { ResultNote } from '../globals' -import { getObsidianApp } from '../stores/obsidian-app' export async function openNote( + app: App, item: ResultNote, offset = 0, newPane = false, @@ -10,7 +10,6 @@ export async function openNote( ): Promise { // Check if the note is already open, // to avoid opening it twice if the first one is pinned - const app = getObsidianApp() let alreadyOpenAndPinned = false app.workspace.iterateAllLeaves(leaf => { if (leaf.view instanceof MarkdownView) { @@ -46,8 +45,11 @@ export async function openNote( }) } -export async function createNote(name: string, newLeaf = false): Promise { - const app = getObsidianApp() +export async function createNote( + app: App, + name: string, + newLeaf = false +): Promise { try { let pathPrefix: string switch (app.vault.getConfig('newFileLocation')) { @@ -77,13 +79,14 @@ export async function createNote(name: string, newLeaf = false): Promise { * @returns */ export function getNonExistingNotes( + app: App, file: TFile, metadata: CachedMetadata ): string[] { return (metadata.links ?? []) .map(l => { const path = removeAnchors(l.link) - return getObsidianApp().metadataCache.getFirstLinkpathDest(path, file.path) + return app.metadataCache.getFirstLinkpathDest(path, file.path) ? '' : l.link }) diff --git a/src/tools/text-processing.ts b/src/tools/text-processing.ts index ee1816e..64574f3 100644 --- a/src/tools/text-processing.ts +++ b/src/tools/text-processing.ts @@ -1,86 +1,206 @@ -import { - type SearchMatch, - regexLineSplit, - regexYaml, - regexStripQuotes, - excerptAfter, - excerptBefore, -} from 'src/globals' +import { excerptAfter, excerptBefore, type SearchMatch } from 'src/globals' import { removeDiacritics, warnDebug } from './utils' import type { Query } from 'src/search/query' import { Notice } from 'obsidian' import { escapeRegExp } from 'lodash-es' -import { getSettings } from 'src/settings' +import type OmnisearchPlugin from '../main' -/** - * Wraps the matches in the text with a element and a highlight class - * @param text - * @param matches - * @returns The html string with the matches highlighted - */ -export function highlightText(text: string, matches: SearchMatch[]): string { - const highlightClass = `suggestion-highlight omnisearch-highlight ${ - getSettings().highlight ? 'omnisearch-default-highlight' : '' - }` - - if (!matches.length) { - return text - } - try { - // Text to highlight - const smartMatches = new RegExp( - matches - .map( - // This regex will match the word (with \b word boundary) - // \b doesn't detect non-alphabetical character's word boundary, so we need to escape it - matchItem => { - const escaped = escapeRegExp(matchItem.match) - return `\\b${escaped}\\b${ - !/[a-zA-Z]/.test(matchItem.match) ? `|${escaped}` : '' - }` - } - ) - .join('|'), - 'giu' - ) +export class TextProcessor { + constructor(private plugin: OmnisearchPlugin) {} - // Replacer function that will highlight the matches - const replacer = (match: string) => { - const matchInfo = matches.find(info => - match.match( - new RegExp( - `\\b${escapeRegExp(info.match)}\\b${ - !/[a-zA-Z]/.test(info.match) ? `|${escapeRegExp(info.match)}` : '' - }`, - 'giu' - ) - ) - ) - if (matchInfo) { - return `${match}` - } - return match + /** + * Wraps the matches in the text with a element and a highlight class + * @param text + * @param matches + * @returns The html string with the matches highlighted + */ + public highlightText(text: string, matches: SearchMatch[]): string { + const highlightClass = `suggestion-highlight omnisearch-highlight ${ + this.plugin.settings.highlight ? 'omnisearch-default-highlight' : '' + }` + + if (!matches.length) { + return text } - - // Effectively highlight the text - let newText = text.replace(smartMatches, replacer) - - // If the text didn't change (= nothing to highlight), re-run the regex but just replace the matches without the word boundary - if (newText === text) { - const dumbMatches = new RegExp( - matches.map(matchItem => escapeRegExp(matchItem.match)).join('|'), + try { + // Text to highlight + const smartMatches = new RegExp( + matches + .map( + // This regex will match the word (with \b word boundary) + // \b doesn't detect non-alphabetical character's word boundary, so we need to escape it + matchItem => { + const escaped = escapeRegExp(matchItem.match) + return `\\b${escaped}\\b${ + !/[a-zA-Z]/.test(matchItem.match) ? `|${escaped}` : '' + }` + } + ) + .join('|'), 'giu' ) - newText = text.replace(dumbMatches, replacer) + + // Replacer function that will highlight the matches + const replacer = (match: string) => { + const matchInfo = matches.find(info => + match.match( + new RegExp( + `\\b${escapeRegExp(info.match)}\\b${ + !/[a-zA-Z]/.test(info.match) + ? `|${escapeRegExp(info.match)}` + : '' + }`, + 'giu' + ) + ) + ) + if (matchInfo) { + return `${match}` + } + return match + } + + // Effectively highlight the text + let newText = text.replace(smartMatches, replacer) + + // If the text didn't change (= nothing to highlight), re-run the regex but just replace the matches without the word boundary + if (newText === text) { + const dumbMatches = new RegExp( + matches.map(matchItem => escapeRegExp(matchItem.match)).join('|'), + 'giu' + ) + newText = text.replace(dumbMatches, replacer) + } + return newText + } catch (e) { + console.error('Omnisearch - Error in highlightText()', e) + return text + } + } + + escapeHTML(html: string): string { + return html + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", ''') + } + + /** + * Converts a list of strings to a list of words, using the \b word boundary. + * Used to find excerpts in a note body, or select which words to highlight. + */ + public stringsToRegex(strings: string[]): RegExp { + if (!strings.length) return /^$/g + + // sort strings by decreasing length, so that longer strings are matched first + strings.sort((a, b) => b.length - a.length) + + const joined = `(${strings + .map(s => `\\b${escapeRegExp(s)}\\b|${escapeRegExp(s)}`) + .join('|')})` + + return new RegExp(`${joined}`, 'gui') + } + + /** + * Returns an array of matches in the text, using the provided regex + * @param text + * @param reg + * @param query + */ + public getMatches(text: string, words: string[], query?: Query): SearchMatch[] { + const reg = this.stringsToRegex(words) + const originalText = text + // text = text.toLowerCase().replace(new RegExp(SEPARATORS, 'gu'), ' ') + if (this.plugin.settings.ignoreDiacritics) { + text = removeDiacritics(text) + } + const startTime = new Date().getTime() + let match: RegExpExecArray | null = null + let matches: SearchMatch[] = [] + let count = 0 + while ((match = reg.exec(text)) !== null) { + // Avoid infinite loops, stop looking after 100 matches or if we're taking too much time + if (++count >= 100 || new Date().getTime() - startTime > 50) { + warnDebug('Stopped getMatches at', count, 'results') + break + } + const matchStartIndex = match.index + const matchEndIndex = matchStartIndex + match[0].length + const originalMatch = originalText + .substring(matchStartIndex, matchEndIndex) + .trim() + if (originalMatch && match.index >= 0) { + matches.push({ match: originalMatch, offset: match.index }) + } + } + + // If the query is more than 1 token and can be found "as is" in the text, put this match first + if ( + query && + (query.query.text.length > 1 || query.getExactTerms().length > 0) + ) { + const best = text.indexOf(query.getBestStringForExcerpt()) + if (best > -1 && matches.find(m => m.offset === best)) { + matches.unshift({ + offset: best, + match: query.getBestStringForExcerpt(), + }) + } + } + return matches + } + + public makeExcerpt(content: string, offset: number): string { + const settings = this.plugin.settings + try { + const pos = offset ?? -1 + const from = Math.max(0, pos - excerptBefore) + const to = Math.min(content.length, pos + excerptAfter) + if (pos > -1) { + content = + (from > 0 ? '…' : '') + + content.slice(from, to).trim() + + (to < content.length - 1 ? '…' : '') + } else { + content = content.slice(0, excerptAfter) + } + if (settings.renderLineReturnInExcerpts) { + const lineReturn = new RegExp(/(?:\r\n|\r|\n)/g) + // Remove multiple line returns + content = content + .split(lineReturn) + .filter(l => l) + .join('\n') + + const last = content.lastIndexOf('\n', pos - from) + + if (last > 0) { + content = content.slice(last) + } + } + + content = escapeHTML(content) + + if (settings.renderLineReturnInExcerpts) { + content = content.trim().replaceAll('\n', '
') + } + + return content + } catch (e) { + new Notice( + 'Omnisearch - Error while creating excerpt, see developer console' + ) + console.error(`Omnisearch - Error while creating excerpt`) + console.error(e) + return '' } - return newText - } catch (e) { - console.error('Omnisearch - Error in highlightText()', e) - return text } } -export function escapeHTML(html: string): string { +function escapeHTML(html: string): string { return html .replaceAll('&', '&') .replaceAll('<', '<') @@ -89,144 +209,3 @@ export function escapeHTML(html: string): string { .replaceAll("'", ''') } -export function splitLines(text: string): string[] { - return text.split(regexLineSplit).filter(l => !!l && l.length > 2) -} - -export function removeFrontMatter(text: string): string { - // Regex to recognize YAML Front Matter (at beginning of file, 3 hyphens, than any character, including newlines, then 3 hyphens). - return text.replace(regexYaml, '') -} - -/** - * Converts a list of strings to a list of words, using the \b word boundary. - * Used to find excerpts in a note body, or select which words to highlight. - */ -export function stringsToRegex(strings: string[]): RegExp { - if (!strings.length) return /^$/g - - // sort strings by decreasing length, so that longer strings are matched first - strings.sort((a, b) => b.length - a.length) - - const joined = `(${strings - .map(s => `\\b${escapeRegExp(s)}\\b|${escapeRegExp(s)}`) - .join('|')})` - - return new RegExp(`${joined}`, 'gui') -} - -/** - * Returns an array of matches in the text, using the provided regex - * @param text - * @param reg - * @param query - */ -export function getMatches( - text: string, - reg: RegExp, - query?: Query -): SearchMatch[] { - const originalText = text - // text = text.toLowerCase().replace(new RegExp(SEPARATORS, 'gu'), ' ') - if (getSettings().ignoreDiacritics) { - text = removeDiacritics(text) - } - const startTime = new Date().getTime() - let match: RegExpExecArray | null = null - let matches: SearchMatch[] = [] - let count = 0 - while ((match = reg.exec(text)) !== null) { - // Avoid infinite loops, stop looking after 100 matches or if we're taking too much time - if (++count >= 100 || new Date().getTime() - startTime > 50) { - warnDebug('Stopped getMatches at', count, 'results') - break - } - const matchStartIndex = match.index - const matchEndIndex = matchStartIndex + match[0].length - const originalMatch = originalText - .substring(matchStartIndex, matchEndIndex) - .trim() - if (originalMatch && match.index >= 0) { - matches.push({ match: originalMatch, offset: match.index }) - } - } - - // If the query is more than 1 token and can be found "as is" in the text, put this match first - if ( - query && - (query.query.text.length > 1 || query.getExactTerms().length > 0) - ) { - const best = text.indexOf(query.getBestStringForExcerpt()) - if (best > -1 && matches.find(m => m.offset === best)) { - matches.unshift({ - offset: best, - match: query.getBestStringForExcerpt(), - }) - } - } - return matches -} - -export function makeExcerpt(content: string, offset: number): string { - const settings = getSettings() - try { - const pos = offset ?? -1 - const from = Math.max(0, pos - excerptBefore) - const to = Math.min(content.length, pos + excerptAfter) - if (pos > -1) { - content = - (from > 0 ? '…' : '') + - content.slice(from, to).trim() + - (to < content.length - 1 ? '…' : '') - } else { - content = content.slice(0, excerptAfter) - } - if (settings.renderLineReturnInExcerpts) { - const lineReturn = new RegExp(/(?:\r\n|\r|\n)/g) - // Remove multiple line returns - content = content - .split(lineReturn) - .filter(l => l) - .join('\n') - - const last = content.lastIndexOf('\n', pos - from) - - if (last > 0) { - content = content.slice(last) - } - } - - content = escapeHTML(content) - - if (settings.renderLineReturnInExcerpts) { - content = content.trim().replaceAll('\n', '
') - } - - return content - } catch (e) { - new Notice( - 'Omnisearch - Error while creating excerpt, see developer console' - ) - console.error(`Omnisearch - Error while creating excerpt`) - console.error(e) - return '' - } -} - -/** - * splits a string in words or "expressions in quotes" - * @param str - * @returns - */ -export function splitQuotes(str: string): string[] { - return ( - str - .match(/"(.*?)"/g) - ?.map(s => s.replace(/"/g, '')) - .filter(q => !!q) ?? [] - ) -} - -export function stripSurroundingQuotes(str: string): string { - return str.replace(regexStripQuotes, '') -} diff --git a/src/tools/utils.ts b/src/tools/utils.ts index a3c469f..664d1de 100644 --- a/src/tools/utils.ts +++ b/src/tools/utils.ts @@ -4,8 +4,7 @@ import { parseFrontMatterAliases, Platform, } from 'obsidian' -import { getTextExtractor, isSearchMatch, type SearchMatch } from '../globals' -import { canIndexUnsupportedFiles, getSettings } from '../settings' +import { isSearchMatch, type SearchMatch } from '../globals' import { type BinaryLike, createHash } from 'crypto' import { md5 } from 'pure-md5' @@ -135,33 +134,6 @@ export function getCtrlKeyLabel(): 'ctrl' | '⌘' { return Platform.isMacOS ? '⌘' : 'ctrl' } -export function isContentIndexable(path: string): boolean { - const settings = getSettings() - const hasTextExtractor = !!getTextExtractor() - const canIndexPDF = hasTextExtractor && settings.PDFIndexing - const canIndexImages = hasTextExtractor && settings.imagesIndexing - return ( - isFilePlaintext(path) || - isFileCanvas(path) || - isFileFromDataloomPlugin(path) || - (canIndexPDF && isFilePDF(path)) || - (canIndexImages && isFileImage(path)) - ) -} - -export function isFilenameIndexable(path: string): boolean { - return ( - canIndexUnsupportedFiles() || - isFilePlaintext(path) || - isFileCanvas(path) || - isFileFromDataloomPlugin(path) - ) -} - -export function isFileIndexable(path: string): boolean { - return isFilenameIndexable(path) || isContentIndexable(path) -} - export function isFileImage(path: string): boolean { const ext = getExtension(path) return ext === 'png' || ext === 'jpg' || ext === 'jpeg' || ext === 'webp' @@ -176,10 +148,6 @@ export function isFileOffice(path: string): boolean { return ext === 'docx' || ext === 'xlsx' } -export function isFilePlaintext(path: string): boolean { - return [...getSettings().indexedFileTypes, 'md'].some(t => path.endsWith(`.${t}`)) -} - export function isFileCanvas(path: string): boolean { return path.endsWith('.canvas') } @@ -251,8 +219,13 @@ export function warnDebug(...args: any[]): void { printDebug(console.warn, ...args) } +let printDebugEnabled= false +export function enablePrintDebug(enable: boolean): void { + printDebugEnabled = enable +} + function printDebug(fn: (...args: any[]) => any, ...args: any[]): void { - if (getSettings().verboseLogging) { + if (printDebugEnabled) { const t = new Date() const ts = `${t.getMinutes()}:${t.getSeconds()}:${t.getMilliseconds()}` fn(...['Omnisearch -', ts + ' -', ...args])