diff --git a/.prettierrc.json b/.prettierrc.json index a1559dd..6037d30 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,6 +1,6 @@ { "printWidth": 120, - "tabWidth": 4, + "tabWidth": 2, "useTabs": false, "singleQuote": false, "semi": true, diff --git a/README.md b/README.md index a6c29d9..8ca2f72 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,54 @@ This plugin supports more flexibly setting your attachment location with variabl > Read the [Original Name](#original-name) section before using the `${originalname}` variable. +## Installation + +- Install from Obsidian community plugins. +- Clone this repo + - `npm i` to install dependencies + - `npm run build` to start compilation in watch mode. + - Copy the `main.js`, `manifest.json` and `style.css` files to your vault `VaultFolder.obsidian/plugins/obsidian-attachment-management` +- Download the release file and unarchive the file to your vault `VaultFolder.obsidian/plugins/obsidian-attachment-management` + +## Usage + +Install and enable the plugin, after configuration you can paste or drop attachment file as usually and it will be auto renamed. + +This plugin supports a command `Rearrange linked attachments/Rearrange all linked attachments`. If you run this command, it will rename all attachments (image file default, to rename another type, you need to enable [Handle All Attachements](#handle-all-attachments)) that have been linked in the `markdown` or `canvas` file as you configured. + +![SCR-20230511-rrtk](./images/SCR-20230511-rrtk.png) + +**Notice**: The `Rearrange linked attachments/Rearrange all linked attachments` is currently an experimental feature; if you want to try it out, it's best to back up your files first. + +### Overriding Setting + +You can set the attachment path setting for a file or folder. The priority of these settings are: + +``` +file setting > most close parent folder setting > global setting +``` + +If you want to reset the settings of files or folders to the global setting, use the command `Reset Override Setting` or the `Reset` button on the override setting panel. **The reset will only work on each file or folder that you trigger the command on**. A more appropriate method to handle resetting will be added in the future. + +### Original Name + +The `${originalname}` represents the original filename (without extension) of the attachment you added to the vault. Some people want to keep the original filename and/or combine it with other variables like `${date}`. If you want to keep the original filename of an attachment, set the **Attachment Format** with `${originalname}`. + +If you want to use `${originalname}` with other variables, like `${originalname}-${date}`. This plugin will persist the original name for future use. Suppose you change the **Attachment Format** from `${originalname}-${date}` to `IMG-${originalname}`, it's work fine. + +The original name is stored in **data.json**, the configuration file of the plugin. You can find it at `.obsidian/plugins/attachment-management/data.json`. + +```json + "originalNameStorage": [ + { + "n": "Pasted image 20240113222517", + "md5": "9B1546EBA299E1A2A2FC86C664A15073" + } + ], +``` + +As you can see, the original name was saved with a hash, so if you add the same file multiple times, only the last one will be saved. The **originalNameStorage** will not clear automatically, use command `Clear unused original name storage`. This command will keep the entry if the hash of an attachment is matched. + ## Roadmap of Features This plugin currently supports: @@ -20,15 +68,6 @@ This plugin currently supports: - [x] Exclude folders that you want this plugin to skip - [x] Add Exclude folder by menu -## How to Install - -- Install from Obsidian community plugins. -- Clone this repo - - `npm i` to install dependencies - - `npm run build` to start compilation in watch mode. - - Copy the `main.js`, `manifest.json` and `style.css` files to your vault `VaultFolder.obsidian/plugins/obsidian-attachment-management` -- Download the release file and unarchive the file to your vault `VaultFolder.obsidian/plugins/obsidian-attachment-management` - ## Settings The path of attachment is composed of three parts : @@ -109,45 +148,6 @@ By default, the "Exclude paths" will only work on the folder you added, and that > **The path is case-sensitive and should not have a leading slash '/' at the beginning.** -## Usage - -Install and enable the plugin, after configuration you can paste or drop attachment file as usually and it will be auto renamed. - -This plugin supports a command `Rearrange linked attachments/Rearrange all linked attachments`. If you run this command, it will rename all attachments (image file default, to rename another type, you need to enable [Handle All Attachements](#handle-all-attachments)) that have been linked in the `markdown` or `canvas` file as you configured. - -![SCR-20230511-rrtk](./images/SCR-20230511-rrtk.png) - -**Notice**: The `Rearrange linked attachments/Rearrange all linked attachments` is currently an experimental feature; if you want to try it out, it's best to back up your files first. - -### Overriding Setting - -You can set the attachment path setting for a file or folder. The priority of these settings are: - -``` -file setting > most close parent folder setting > global setting -``` - -If you want to reset the settings of files or folders to the global setting, use the command `Reset Override Setting` or the `Reset` button on the override setting panel. **The reset will only work on each file or folder that you trigger the command on**. A more appropriate method to handle resetting will be added in the future. - -### Original Name - -The `${originalname}` represents the original filename (without extension) of the attachment you added to the vault. Some people want to keep the original filename and/or combine it with other variables like `${date}`. If you want to keep the original filename of an attachment, set the **Attachment Format** with `${originalname}`. - -If you want to use `${originalname}` with other variables, like `${originalname}-${date}`. This plugin will persist the original name for future use. Suppose you change the **Attachment Format** from `${originalname}-${date}` to `IMG-${originalname}`, it's work fine. - -The original name is stored in **data.json**, the configuration file of the plugin. You can find it at `.obsidian/plugins/attachment-management/data.json`. - -```json - "originalNameStorage": [ - { - "n": "Pasted image 20240113222517", - "md5": "9B1546EBA299E1A2A2FC86C664A15073" - } - ], -``` - -As you can see, the original name was saved with a hash, so if you add the same file multiple times, only the last one will be saved. The **originalNameStorage** will not clear automatically, use command `Clear unused original name storage`. This command will keep the entry if the hash of an attachment is matched. - ### Known Issues - ~~No support for processing duplicated file names right now (in development). In backup, you could use the data variable [`x`](https://momentjscom.readthedocs.io/en/latest/moment/04-displaying/01-format/) to use Unix timestamp with millisecond as filename (it will prevent duplicated filename).~~ @@ -165,3 +165,7 @@ As you can see, the original name was saved with a hash, so if you add the same Q: What if I add '/' to Exclude Paths? A: It will exclude the whole vault folder. + +Q: Is this plugin support auto rename pdf file? + +A: By default, this plugin will only rename the image file. For other file types, you can use the extension override setting. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 14eb0fe..3c34bc5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,28 +30,44 @@ "typescript": "^4.9.5" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmmirror.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame": { - "version": "7.22.10", - "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.22.10.tgz", - "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmmirror.com/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.10", - "chalk": "^2.4.2" + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "node_modules/@babel/highlight/node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", @@ -63,7 +79,7 @@ "node": ">=4" } }, - "node_modules/@babel/code-frame/node_modules/chalk": { + "node_modules/@babel/highlight/node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", @@ -77,7 +93,7 @@ "node": ">=4" } }, - "node_modules/@babel/code-frame/node_modules/color-convert": { + "node_modules/@babel/highlight/node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", @@ -86,13 +102,13 @@ "color-name": "1.1.3" } }, - "node_modules/@babel/code-frame/node_modules/color-name": { + "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", @@ -101,7 +117,7 @@ "node": ">=0.8.0" } }, - "node_modules/@babel/code-frame/node_modules/has-flag": { + "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", @@ -110,7 +126,7 @@ "node": ">=4" } }, - "node_modules/@babel/code-frame/node_modules/supports-color": { + "node_modules/@babel/highlight/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", @@ -122,45 +138,22 @@ "node": ">=4" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.22.10", - "resolved": "https://registry.npmmirror.com/@babel/highlight/-/highlight-7.22.10.tgz", - "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@codemirror/state": { - "version": "6.2.1", - "resolved": "https://registry.npmmirror.com/@codemirror/state/-/state-6.2.1.tgz", - "integrity": "sha512-RupHSZ8+OjNT38zU9fKH2sv+Dnlr8Eb8sl4NOnnqz95mCFTZUaiRP8Xv5MeeaG0px2b8Bnfe7YGwCV3nsBhbuw==", + "version": "6.4.1", + "resolved": "https://registry.npmmirror.com/@codemirror/state/-/state-6.4.1.tgz", + "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==", "dev": true, "peer": true }, "node_modules/@codemirror/view": { - "version": "6.16.0", - "resolved": "https://registry.npmmirror.com/@codemirror/view/-/view-6.16.0.tgz", - "integrity": "sha512-1Z2HkvkC3KR/oEZVuW9Ivmp8TWLzGEd8T8TA04TTwPvqogfkHBdYSlflytDOqmkUxM2d1ywTg7X2dU5mC+SXvg==", + "version": "6.28.4", + "resolved": "https://registry.npmmirror.com/@codemirror/view/-/view-6.28.4.tgz", + "integrity": "sha512-QScv95fiviSQ/CaVGflxAvvvDy/9wi0RFyDl4LkHHWiMr/UPebyuTspmYSeN5Nx6eujcPYwsQzA6ZIZucKZVHQ==", "dev": true, "peer": true, "dependencies": { - "@codemirror/state": "^6.1.4", - "style-mod": "^4.0.0", + "@codemirror/state": "^6.4.0", + "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, @@ -531,17 +524,17 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.8.1", - "resolved": "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.8.1.tgz", - "integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==", + "version": "4.11.0", + "resolved": "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.4", + "resolved": "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -555,41 +548,90 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, "node_modules/@eslint/js": { - "version": "8.49.0", - "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-8.49.0.tgz", - "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==", + "version": "8.57.0", + "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.11", - "resolved": "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", - "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "version": "0.11.14", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "engines": { "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead" }, "node_modules/@hutson/parse-repository-url": { "version": "3.0.2", @@ -642,15 +684,15 @@ } }, "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.13", - "resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.13.tgz", - "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", + "version": "7.0.15", + "resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/json5": { @@ -660,49 +702,49 @@ "dev": true }, "node_modules/@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", "dev": true }, "node_modules/@types/node": { - "version": "16.18.41", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-16.18.41.tgz", - "integrity": "sha512-YZJjn+Aaw0xihnpdImxI22jqGbp0DCgTFKRycygjGx/Y27NnWFJa5FJ7P+MRT3u07dogEeMVh70pWpbIQollTA==", + "version": "16.18.101", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-16.18.101.tgz", + "integrity": "sha512-AAsx9Rgz2IzG8KJ6tXd6ndNkVcu+GYB6U/SnFAaokSPNx2N7dcIIfnighYUNumvj6YS2q39Dejz5tT0NCV7CWA==", "dev": true }, "node_modules/@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmmirror.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "version": "2.4.4", + "resolved": "https://registry.npmmirror.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "dev": true }, "node_modules/@types/semver": { - "version": "7.5.2", - "resolved": "https://registry.npmmirror.com/@types/semver/-/semver-7.5.2.tgz", - "integrity": "sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw==", + "version": "7.5.8", + "resolved": "https://registry.npmmirror.com/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/tern": { - "version": "0.23.4", - "resolved": "https://registry.npmmirror.com/@types/tern/-/tern-0.23.4.tgz", - "integrity": "sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==", + "version": "0.23.9", + "resolved": "https://registry.npmmirror.com/@types/tern/-/tern-0.23.9.tgz", + "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==", "dev": true, "dependencies": { "@types/estree": "*" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.7.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.0.tgz", - "integrity": "sha512-gUqtknHm0TDs1LhY12K2NA3Rmlmp88jK9Tx8vGZMfHeNMLE3GH2e9TRub+y+SOjuYgtOmok+wt1AyDPZqxbNag==", + "version": "6.21.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.7.0", - "@typescript-eslint/type-utils": "6.7.0", - "@typescript-eslint/utils": "6.7.0", - "@typescript-eslint/visitor-keys": "6.7.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -713,6 +755,10 @@ "engines": { "node": "^16.0.0 || >=18.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, "peerDependencies": { "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", "eslint": "^7.0.0 || ^8.0.0" @@ -724,20 +770,24 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.7.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-6.7.0.tgz", - "integrity": "sha512-jZKYwqNpNm5kzPVP5z1JXAuxjtl2uG+5NpaMocFPTNC2EdYIgbXIPImObOkhbONxtFTTdoZstLZefbaK+wXZng==", + "version": "6.21.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.7.0", - "@typescript-eslint/types": "6.7.0", - "@typescript-eslint/typescript-estree": "6.7.0", - "@typescript-eslint/visitor-keys": "6.7.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4" }, "engines": { "node": "^16.0.0 || >=18.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0" }, @@ -748,32 +798,40 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.7.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.0.tgz", - "integrity": "sha512-lAT1Uau20lQyjoLUQ5FUMSX/dS07qux9rYd5FGzKz/Kf8W8ccuvMyldb8hadHdK/qOI7aikvQWqulnEq2nCEYA==", + "version": "6.21.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.0", - "@typescript-eslint/visitor-keys": "6.7.0" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.7.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-6.7.0.tgz", - "integrity": "sha512-f/QabJgDAlpSz3qduCyQT0Fw7hHpmhOzY/Rv6zO3yO+HVIdPfIWhrQoAyG+uZVtWAIS85zAyzgAFfyEr+MgBpg==", + "version": "6.21.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.7.0", - "@typescript-eslint/utils": "6.7.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0" }, @@ -784,31 +842,40 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.7.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-6.7.0.tgz", - "integrity": "sha512-ihPfvOp7pOcN/ysoj0RpBPOx3HQTJTrIN8UZK+WFd3/iDeFHHqeyYxa4hQk4rMhsz9H9mXpR61IzwlBVGXtl9Q==", + "version": "6.21.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.7.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.0.tgz", - "integrity": "sha512-dPvkXj3n6e9yd/0LfojNU8VMUGHWiLuBZvbM6V6QYD+2qxqInE7J+J/ieY2iGwR9ivf/R/haWGkIj04WVUeiSQ==", + "version": "6.21.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.0", - "@typescript-eslint/visitor-keys": "6.7.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", + "minimatch": "9.0.3", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -816,43 +883,56 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.7.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-6.7.0.tgz", - "integrity": "sha512-MfCq3cM0vh2slSikQYqK2Gq52gvOhe57vD2RM3V4gQRZYX4rDPnKLu5p6cm89+LJiGlwEXU8hkYxhqqEC/V3qA==", + "version": "6.21.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.7.0", - "@typescript-eslint/types": "6.7.0", - "@typescript-eslint/typescript-estree": "6.7.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", "semver": "^7.5.4" }, "engines": { "node": "^16.0.0 || >=18.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.7.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.0.tgz", - "integrity": "sha512-/C1RVgKFDmGMcVGeD8HjKv2bd72oI1KxQDeY8uc66gw9R0OK0eMq48cA+jv9/2Ag6cdrsUGySm1yzYmfz0hxwQ==", + "version": "6.21.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.0", + "@typescript-eslint/types": "6.21.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.12.1", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "bin": { "acorn": "bin/acorn" }, @@ -883,6 +963,10 @@ "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, "node_modules/ansi-regex": { @@ -902,6 +986,9 @@ }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/argparse": { @@ -910,13 +997,19 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/array-ify": { @@ -926,19 +1019,23 @@ "dev": true }, "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmmirror.com/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "version": "3.1.8", + "resolved": "https://registry.npmmirror.com/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/array-union": { @@ -951,19 +1048,23 @@ } }, "node_modules/array.prototype.findlastindex": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", - "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/array.prototype.flat": { @@ -979,6 +1080,9 @@ }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/array.prototype.flatmap": { @@ -994,24 +1098,31 @@ }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", "dev": true, "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", "is-shared-array-buffer": "^1.0.2" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/arrify": { @@ -1024,12 +1135,18 @@ } }, "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/balanced-match": { @@ -1038,21 +1155,21 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1071,16 +1188,28 @@ "dev": true, "engines": { "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/callsites": { @@ -1112,49 +1241,26 @@ }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" + "node": ">=10" }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmmirror.com/cliui/-/cliui-7.0.4.tgz", @@ -1518,6 +1624,57 @@ "node": ">=8" } }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/dateformat": { "version": "3.0.3", "resolved": "https://registry.npmmirror.com/dateformat/-/dateformat-3.0.3.tgz", @@ -1528,9 +1685,9 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { "ms": "2.1.2" }, @@ -1563,6 +1720,9 @@ }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/decamelize-keys/node_modules/map-obj": { @@ -1580,17 +1740,20 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" }, "node_modules/define-data-property": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.0.tgz", - "integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==", + "version": "1.1.4", + "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-properties": { @@ -1605,6 +1768,9 @@ }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/detect-indent": { @@ -1673,6 +1839,16 @@ "node": ">=6" } }, + "node_modules/dotgitignore/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/dotgitignore/node_modules/find-up": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/find-up/-/find-up-3.0.0.tgz", @@ -1698,6 +1874,18 @@ "node": ">=6" } }, + "node_modules/dotgitignore/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/dotgitignore/node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz", @@ -1708,6 +1896,9 @@ }, "engines": { "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/dotgitignore/node_modules/p-locate": { @@ -1747,76 +1938,119 @@ } }, "node_modules/es-abstract": { - "version": "1.22.2", - "resolved": "https://registry.npmmirror.com/es-abstract/-/es-abstract-1.22.2.tgz", - "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", + "version": "1.23.3", + "resolved": "https://registry.npmmirror.com/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.1", - "get-symbol-description": "^1.0.0", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", "globalthis": "^1.0.3", "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", + "is-shared-array-buffer": "^1.0.3", "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", + "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", + "object-inspect": "^1.13.1", "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.11" + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" } }, "node_modules/es-to-primitive": { @@ -1831,6 +2065,9 @@ }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/esbuild": { @@ -1871,35 +2108,38 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "engines": { - "node": ">=0.8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint": { - "version": "8.49.0", - "resolved": "https://registry.npmmirror.com/eslint/-/eslint-8.49.0.tgz", - "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==", + "version": "8.57.0", + "resolved": "https://registry.npmmirror.com/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.49.0", - "@humanwhocodes/config-array": "^0.11.11", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -1936,6 +2176,9 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-config-prettier": { @@ -1970,9 +2213,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmmirror.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", "dev": true, "dependencies": { "debug": "^3.2.7" @@ -1996,28 +2239,28 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.28.1", - "resolved": "https://registry.npmmirror.com/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz", - "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==", + "version": "2.29.1", + "resolved": "https://registry.npmmirror.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", "dev": true, "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.findlastindex": "^1.2.2", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", + "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.8.0", - "has": "^1.0.3", - "is-core-module": "^2.13.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.6", - "object.groupby": "^1.0.0", - "object.values": "^1.1.6", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", "semver": "^6.3.1", - "tsconfig-paths": "^3.14.2" + "tsconfig-paths": "^3.15.0" }, "engines": { "node": ">=4" @@ -2026,6 +2269,16 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz", @@ -2047,6 +2300,18 @@ "node": ">=0.10.0" } }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint-plugin-import/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", @@ -2077,9 +2342,9 @@ } }, "node_modules/eslint-plugin-unused-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.0.0.tgz", - "integrity": "sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==", + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.2.0.tgz", + "integrity": "sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ==", "dev": true, "dependencies": { "eslint-rule-composer": "^0.3.0" @@ -2088,8 +2353,8 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^6.0.0", - "eslint": "^8.0.0" + "@typescript-eslint/eslint-plugin": "6 - 7", + "eslint": "8" }, "peerDependenciesMeta": { "@typescript-eslint/eslint-plugin": { @@ -2116,6 +2381,9 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { @@ -2124,45 +2392,29 @@ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": { - "has-flag": "^4.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=8" + "node": "*" } }, "node_modules/espree": { @@ -2176,6 +2428,9 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { @@ -2227,9 +2482,9 @@ "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==" }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -2265,9 +2520,9 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.17.1", + "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dependencies": { "reusify": "^1.0.4" } @@ -2282,6 +2537,18 @@ }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" } }, "node_modules/file-entry-cache": { @@ -2296,9 +2563,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -2317,25 +2584,28 @@ }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/flat-cache": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/flat-cache/-/flat-cache-3.1.0.tgz", - "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dependencies": { - "flatted": "^3.2.7", + "flatted": "^3.2.9", "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { - "node": ">=12.0.0" + "node": "^10.12.0 || >=12.0.0" } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmmirror.com/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==" + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==" }, "node_modules/for-each": { "version": "0.3.3", @@ -2352,10 +2622,13 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { "version": "1.1.6", @@ -2370,13 +2643,19 @@ }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-caller-file": { "version": "2.0.5", @@ -2388,15 +2667,22 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/get-pkg-repo": { @@ -2417,6 +2703,12 @@ "node": ">=6.9.0" } }, + "node_modules/get-pkg-repo/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, "node_modules/get-pkg-repo/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", @@ -2458,16 +2750,20 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/git-raw-commits": { @@ -2540,6 +2836,7 @@ "version": "7.2.3", "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2550,6 +2847,9 @@ }, "engines": { "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/glob-parent": { @@ -2563,27 +2863,54 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/globals": { - "version": "13.21.0", - "resolved": "https://registry.npmmirror.com/globals/-/globals-13.21.0.tgz", - "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "version": "13.24.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dependencies": { "type-fest": "^0.20.2" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, "dependencies": { - "define-properties": "^1.1.3" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/globby": { @@ -2601,6 +2928,9 @@ }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/gopd": { @@ -2610,6 +2940,9 @@ "dev": true, "dependencies": { "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/graceful-fs": { @@ -2653,49 +2986,45 @@ "node": ">=6" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/has-bigints/-/has-bigints-1.0.2.tgz", "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.1" + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-symbols": { @@ -2705,15 +3034,33 @@ "dev": true, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" @@ -2732,9 +3079,9 @@ } }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.1", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "engines": { "node": ">= 4" } @@ -2749,6 +3096,9 @@ }, "engines": { "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/imurmurhash": { @@ -2772,6 +3122,7 @@ "version": "1.0.6", "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -2789,13 +3140,13 @@ "dev": true }, "node_modules/internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "version": "1.0.7", + "resolved": "https://registry.npmmirror.com/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "hasown": "^2.0.0", "side-channel": "^1.0.4" }, "engines": { @@ -2803,14 +3154,19 @@ } }, "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-arrayish": { @@ -2826,6 +3182,9 @@ "dev": true, "dependencies": { "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-boolean-object": { @@ -2839,6 +3198,9 @@ }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-callable": { @@ -2848,15 +3210,39 @@ "dev": true, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-core-module": { - "version": "2.13.0", - "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.13.0.tgz", - "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "version": "2.14.0", + "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.14.0.tgz", + "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", "dev": true, "dependencies": { - "has": "^1.0.3" + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-date-object": { @@ -2869,6 +3255,9 @@ }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-extglob": { @@ -2900,12 +3289,15 @@ } }, "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-number": { @@ -2927,6 +3319,9 @@ }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-obj": { @@ -2966,15 +3361,24 @@ }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2" + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-string": { @@ -2987,6 +3391,9 @@ }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-symbol": { @@ -2999,6 +3406,9 @@ }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-text-path": { @@ -3014,15 +3424,18 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmmirror.com/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "version": "1.1.13", + "resolved": "https://registry.npmmirror.com/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dev": true, "dependencies": { - "which-typed-array": "^1.1.11" + "which-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-weakref": { @@ -3032,12 +3445,15 @@ "dev": true, "dependencies": { "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true }, "node_modules/isexe": { @@ -3133,9 +3549,9 @@ } }, "node_modules/keyv": { - "version": "4.5.3", - "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.3.tgz", - "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "version": "4.5.4", + "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dependencies": { "json-buffer": "3.0.1" } @@ -3200,6 +3616,9 @@ }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lodash": { @@ -3238,6 +3657,9 @@ "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/meow": { @@ -3260,6 +3682,9 @@ }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/meow/node_modules/find-up": { @@ -3303,6 +3728,9 @@ }, "engines": { "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/meow/node_modules/p-locate": { @@ -3330,6 +3758,9 @@ }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/meow/node_modules/read-pkg": { @@ -3359,6 +3790,9 @@ }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/meow/node_modules/read-pkg-up/node_modules/type-fest": { @@ -3407,6 +3841,9 @@ "dev": true, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/merge2": { @@ -3419,12 +3856,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.7", + "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -3441,21 +3878,28 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.3", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/minimist-options": { "version": "4.1.0", @@ -3521,10 +3965,16 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "dev": true + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/object-keys": { "version": "1.1.1", @@ -3536,64 +3986,76 @@ } }, "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "version": "4.1.5", + "resolved": "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmmirror.com/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "version": "2.0.8", + "resolved": "https://registry.npmmirror.com/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object.groupby": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/object.groupby/-/object.groupby-1.0.1.tgz", - "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmmirror.com/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/obsidian": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/obsidian/-/obsidian-1.4.0.tgz", - "integrity": "sha512-fsZMPlxgflGSBSP6P4BjQi5+0MqZl3h6FEDEZ3CNnweNdDw0doyqN3FMO/PGWfuxPT77WicVwUxekuI3e6eCGg==", + "version": "1.5.7-1", + "resolved": "https://registry.npmmirror.com/obsidian/-/obsidian-1.5.7-1.tgz", + "integrity": "sha512-T5ZRuQ1FnfXqEoakTTHVDYvzUEEoT8zSPnQCW31PVgYwG4D4tZCQfKHN2hTz1ifnCe8upvwa6mBTAP2WUA5Vng==", "dev": true, "dependencies": { "@types/codemirror": "5.60.8", @@ -3613,16 +4075,16 @@ } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -3637,6 +4099,9 @@ }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { @@ -3648,6 +4113,9 @@ }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-try": { @@ -3722,6 +4190,12 @@ "node": ">=8" } }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", @@ -3729,6 +4203,9 @@ "dev": true, "engines": { "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/pify": { @@ -3740,6 +4217,15 @@ "node": ">=0.10.0" } }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -3757,6 +4243,9 @@ }, "engines": { "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/prettier-linter-helpers": { @@ -3777,9 +4266,9 @@ "dev": true }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "engines": { "node": ">=6" } @@ -3788,6 +4277,7 @@ "version": "1.5.1", "resolved": "https://registry.npmmirror.com/q/-/q-1.5.1.tgz", "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, "engines": { "node": ">=0.6.0", @@ -3797,7 +4287,21 @@ "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/quick-lru": { "version": "4.0.1", @@ -3978,17 +4482,21 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "version": "1.5.2", + "resolved": "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/require-directory": { @@ -4001,9 +4509,9 @@ } }, "node_modules/resolve": { - "version": "1.22.6", - "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.6.tgz", - "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "version": "1.22.8", + "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { "is-core-module": "^2.13.0", @@ -4012,6 +4520,9 @@ }, "bin": { "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/resolve-from": { @@ -4035,67 +4546,99 @@ "version": "3.0.2", "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/safe-array-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz", - "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, "engines": { "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safe-array-concat/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.2", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -4103,15 +4646,33 @@ "node": ">=10" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, "dependencies": { - "define-data-property": "^1.0.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -4137,14 +4698,21 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/slash": { @@ -4176,9 +4744,9 @@ } }, "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true }, "node_modules/spdx-expression-parse": { @@ -4192,9 +4760,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.13", - "resolved": "https://registry.npmmirror.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", - "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "version": "3.0.18", + "resolved": "https://registry.npmmirror.com/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", + "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", "dev": true }, "node_modules/split": { @@ -4246,6 +4814,77 @@ "node": ">=10" } }, + "node_modules/standard-version/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/standard-version/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/standard-version/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/standard-version/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/standard-version/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/standard-version/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/standard-version/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz", @@ -4270,39 +4909,52 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmmirror.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "version": "1.2.9", + "resolved": "https://registry.npmmirror.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmmirror.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmmirror.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/stringify-package": { @@ -4350,25 +5002,27 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/style-mod": { - "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/style-mod/-/style-mod-4.0.3.tgz", - "integrity": "sha512-78Jv8kYJdjbvRwwijtCevYADfsI0lGzYJe4mMFdceO8l75DFFDoqBhR1jVDicDRRaX4//g1u9wKeo+ztc2h1Rw==", + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==", "dev": true, "peer": true }, "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, + "version": "7.2.0", + "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -4378,6 +5032,9 @@ "dev": true, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/text-extensions": { @@ -4431,12 +5088,12 @@ } }, "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, "engines": { - "node": ">=16.13.0" + "node": ">=16" }, "peerDependencies": { "typescript": ">=4.2.0" @@ -4451,9 +5108,9 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmmirror.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "version": "3.15.0", + "resolved": "https://registry.npmmirror.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "dependencies": { "@types/json5": "^0.0.29", @@ -4485,62 +5142,82 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" } }, "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/typedarray": { @@ -4563,9 +5240,9 @@ } }, "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmmirror.com/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "version": "3.18.0", + "resolved": "https://registry.npmmirror.com/uglify-js/-/uglify-js-3.18.0.tgz", + "integrity": "sha512-SyVVbcNBCk0dzr9XL/R/ySrmYf0s372K6/hFklzgcp2lBFyXtw4I7BOdDjlLhE1aVqaI/SHWXWmYdlZxuyF38A==", "dev": true, "optional": true, "bin": { @@ -4585,6 +5262,9 @@ "has-bigints": "^1.0.2", "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/uri-js": { @@ -4643,22 +5323,36 @@ "is-number-object": "^1.0.4", "is-string": "^1.0.5", "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/which-typed-array": { - "version": "1.1.11", - "resolved": "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.11.tgz", - "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "version": "1.1.15", + "resolved": "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "engines": { + "node": ">=0.10.0" } }, "node_modules/wordwrap": { @@ -4679,6 +5373,9 @@ }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/wrappy": { @@ -4743,6 +5440,9 @@ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } } } diff --git a/src/arrange.ts b/src/arrange.ts index 9261803..314b30b 100644 --- a/src/arrange.ts +++ b/src/arrange.ts @@ -2,7 +2,7 @@ import { App, Notice, TFile, TFolder, Plugin } from "obsidian"; import { path } from "./lib/path"; import { debugLog } from "./lib/log"; import { getOverrideSetting } from "./override"; -import { ATTACHMENT_RENAME_TYPE, MD5, attachRenameType, isAttachment, isCanvasFile, isMarkdownFile } from "./utils"; +import { MD5, isAttachment, isCanvasFile, isMarkdownFile } from "./utils"; import { LinkMatch, getAllLinkMatchesInFile } from "./lib/linkDetector"; import { AttachmentManagementPluginSettings, AttachmentPathSettings } from "./settings/settings"; import { SETTINGS_VARIABLES_DATES, SETTINGS_VARIABLES_NOTENAME } from "./lib/constant"; @@ -15,332 +15,335 @@ import { containOriginalNameVariable, loadOriginalName } from "./lib/originalSto const bannerRegex = /!\[\[(.*?)\]\]/i; export class ArrangeHandler { - settings: AttachmentManagementPluginSettings; - app: App; - plugin: Plugin; + settings: AttachmentManagementPluginSettings; + app: App; + plugin: Plugin; - constructor(settings: AttachmentManagementPluginSettings, app: App, plugin: Plugin) { - this.settings = settings; - this.app = app; - this.plugin = plugin; + constructor(settings: AttachmentManagementPluginSettings, app: App, plugin: Plugin) { + this.settings = settings; + this.app = app; + this.plugin = plugin; + } + + /** + * Rearranges attachments that are linked by markdown or canvas. + * Only rearranges attachments if autoRenameAttachment is enabled in settings. + * + * @param {"active" | "links" | "file"} type - The type of attachments to rearrange. + * @param {TFile} file - The file to which the attachments are linked (optional), if the type was "file", thi should be provided. + * @param {string} oldPath - The old path of the file (optional), used for rename event. + */ + async rearrangeAttachment(type: "active" | "links" | "file", file?: TFile, oldPath?: string) { + if (!this.settings.autoRenameAttachment) { + debugLog("rearrangeAttachment - autoRenameAttachment not enable"); + return; } - /** - * Rearranges attachments that are linked by markdown or canvas. - * Only rearranges attachments if autoRenameAttachment is enabled in settings. - * - * @param {"active" | "links" | "file"} type - The type of attachments to rearrange. - * @param {TFile} file - The file to which the attachments are linked (optional), if the type was "file", thi should be provided. - * @param {string} oldPath - The old path of the file (optional), used for rename event. - */ - async rearrangeAttachment(type: "active" | "links" | "file", file?: TFile, oldPath?: string) { - if (!this.settings.autoRenameAttachment) { - debugLog("rearrangeAttachment - autoRenameAttachment not enable"); - return; + // only rearrange attachment that linked by markdown or canvas + const attachments = await this.getAttachmentsInVault(this.settings, type, file, oldPath); + debugLog("rearrangeAttachment - attachments:", Object.keys(attachments).length, Object.entries(attachments)); + for (const obNote of Object.keys(attachments)) { + const innerFile = this.app.vault.getAbstractFileByPath(obNote); + if (!(innerFile instanceof TFile) || isAttachment(this.settings, innerFile)) { + debugLog(`rearrangeAttachment - ${obNote} not exists or is attachment, skipped`); + continue; + } + const { setting } = getOverrideSetting(this.settings, innerFile); + + // create attachment path if it's not exists + const md = getMetadata(obNote); + const attachPath = md.getAttachmentPath(setting, this.settings.dateFormat); + if (!(await this.app.vault.adapter.exists(attachPath, true))) { + // process the case where rename the filename to uppercase or lowercase + if (oldPath != undefined && (await this.app.vault.adapter.exists(attachPath, false))) { + const mdOld = getMetadata(oldPath); + const attachPathOld = mdOld.getAttachmentPath(setting, this.settings.dateFormat); + // this will trigger the rename event and cause the path of attachment change + this.app.vault.adapter.rename(attachPathOld, attachPath); + } else { + await this.app.vault.adapter.mkdir(attachPath); } + } - // only rearrange attachment that linked by markdown or canvas - const attachments = await this.getAttachmentsInVault(this.settings, type, file, oldPath); - debugLog("rearrangeAttachment - attachments:", Object.keys(attachments).length, Object.entries(attachments)); - for (const obNote of Object.keys(attachments)) { - const innerFile = this.app.vault.getAbstractFileByPath(obNote); - if (!(innerFile instanceof TFile) || isAttachment(this.settings, innerFile)) { - debugLog(`rearrangeAttachment - ${obNote} not exists or is attachment, skipped`); - continue; - } - const { setting } = getOverrideSetting(this.settings, innerFile); + for (let link of attachments[obNote]) { + try { + link = decodeURI(link); + } catch (err) { + console.log(`Invalid link: ${link}, err: ${err}`); + continue; + } + debugLog(`rearrangeAttachment - article: ${obNote} links: ${link}`); + const linkFile = this.app.vault.getAbstractFileByPath(link); + if (linkFile === null || !(linkFile instanceof TFile)) { + debugLog(`${link} not exists, skipped`); + continue; + } - const type = attachRenameType(setting); - if (type === ATTACHMENT_RENAME_TYPE.NULL) { - debugLog("rearrangeAttachment - no variable use, skipped"); - return; - } + const metadata = getMetadata(obNote, linkFile); + const md5 = await MD5(this.app.vault.adapter, linkFile); + const originalName = loadOriginalName(this.settings, setting, linkFile.extension, md5); + debugLog("rearrangeAttachment - original name:", originalName); - for (let link of attachments[obNote]) { - try { - link = decodeURI(link); - } catch (err) { - console.log(`Invalid link: ${link}, err: ${err}`); - continue; - } - debugLog(`rearrangeAttachment - article: ${obNote} links: ${link}`); - const linkFile = this.app.vault.getAbstractFileByPath(link); - if (linkFile === null || !(linkFile instanceof TFile)) { - debugLog(`${link} not exists, skipped`); - continue; - } + let attachName = ""; + if (containOriginalNameVariable(setting, linkFile.extension)) { + attachName = await metadata.getAttachFileName( + setting, + this.settings.dateFormat, + originalName?.n ?? "", + this.app.vault.adapter, + path.basename(link, path.extname(link)) + ); + } else { + attachName = await metadata.getAttachFileName( + setting, + this.settings.dateFormat, + path.basename(link, path.extname(link)), + this.app.vault.adapter + ); + } - const metadata = getMetadata(obNote, linkFile); - const attachPath = metadata.getAttachmentPath(setting, this.settings.dateFormat); + // ignore if the path was equal to the link + if (attachPath == path.dirname(link) && attachName === path.basename(link, path.extname(link))) { + continue; + } - const md5 = await MD5(this.app.vault.adapter, linkFile); - const originalName = loadOriginalName(this.settings, setting, linkFile.extension, md5); - debugLog("rearrangeAttachment - original name:", originalName); + const attachPathFile = this.app.vault.getAbstractFileByPath(attachPath); + if (attachPathFile === null || !(attachPathFile instanceof TFolder)) { + debugLog(`${attachPath} not exists, skipped`); + continue; + } + const { name } = await deduplicateNewName(attachName + "." + path.extname(link), attachPathFile); + debugLog("rearrangeAttachment - deduplicated name:", name); - let attachName = ""; - if (containOriginalNameVariable(setting, linkFile.extension)) { - attachName = await metadata.getAttachFileName( - setting, - this.settings.dateFormat, - originalName?.n ?? "", - this.app.vault.adapter, - path.basename(link, path.extname(link)) - ); - } else { - attachName = await metadata.getAttachFileName( - setting, - this.settings.dateFormat, - path.basename(link, path.extname(link)), - this.app.vault.adapter - ); - } + await this.app.fileManager.renameFile(linkFile, path.join(attachPath, name)); + } + } + } - // ignore if the path was equal to the link - if (attachPath == path.dirname(link) && attachName === path.basename(link, path.extname(link))) { - continue; - } + /** + * Retrieves the attachments in the vault based on the specified settings and type. + * If a file is provided, only attachments related to that file will be returned. + * + * @param {AttachmentManagementPluginSettings} settings - The settings for the attachment management plugin. + * @param {"active" | "links" | "file"} type - The type of attachments to retrieve. + * @param {TFile} [file] - The file to filter attachments by. Optional. + * @return {Promise>>} - A promise that resolves to a record of attachments, where each key is a file name and each value is a set of associated attachment names. + */ + async getAttachmentsInVault( + settings: AttachmentManagementPluginSettings, + type: "active" | "links" | "file", + file?: TFile, + oldPath?: string + ): Promise>> { + let attachmentsRecord: Record> = {}; - if (!(await this.app.vault.adapter.exists(attachPath))) { - await this.app.vault.adapter.mkdir(attachPath); - } + attachmentsRecord = await this.getAttachmentsInVaultByLinks(settings, type, file, oldPath); - const attachPathFile = this.app.vault.getAbstractFileByPath(attachPath); - if (attachPathFile === null || !(attachPathFile instanceof TFolder)) { - debugLog(`${attachPath} not exists, skipped`); - continue; - } - const { name } = await deduplicateNewName(attachName + "." + path.extname(link), attachPathFile); - debugLog("rearrangeAttachment - deduplicated name:", name); + return attachmentsRecord; + } - await this.app.fileManager.renameFile(linkFile, path.join(attachPath, name)); - } + /** + * Modified from https://github.com/ozntel/oz-clear-unused-images-obsidian/blob/master/src/util.ts#LL48C21-L48C21 + * Retrieves a record of attachments in the vault based on the given settings and type. + * + * @param {AttachmentManagementPluginSettings} settings - The settings for the attachment management plugin. + * @param {"active" | "links" | "file"} type - The type of attachments to retrieve. + * @param {TFile} file - The file to retrieve attachments for (optional). + * @return {Promise>>} - A promise that resolves to a record of attachments. + */ + async getAttachmentsInVaultByLinks( + settings: AttachmentManagementPluginSettings, + type: "active" | "links" | "file", + file?: TFile, + oldPath?: string + ): Promise>> { + const attachmentsRecord: Record> = {}; + let resolvedLinks: Record> = {}; + let allFiles: TFile[] = []; + if (type === "links") { + // resolvedLinks was not working for canvas file + resolvedLinks = this.app.metadataCache.resolvedLinks; + allFiles = this.app.vault.getFiles(); + } else if (type === "active") { + const file = getActiveFile(this.app); + if (file) { + if ((file.parent && isExcluded(file.parent.path, this.settings)) || isAttachment(this.settings, file)) { + allFiles = []; + new Notice(`${file.path} was excluded, skipped`); + } else { + debugLog("getAttachmentsInVaultByLinks - active:", file.path); + allFiles = [file]; + if (this.app.metadataCache.resolvedLinks[file.path]) { + resolvedLinks[file.path] = this.app.metadataCache.resolvedLinks[file.path]; + } + debugLog("getAttachmentsInVaultByLinks - resolvedLinks:", resolvedLinks); + } + } + } else if (type === "file" && file != undefined) { + if ((file.parent && isExcluded(file.parent.path, this.settings)) || isAttachment(this.settings, file)) { + allFiles = []; + new Notice(`${file.path} was excluded, skipped`); + } else { + debugLog("getAttachmentsInVaultByLinks - file:", file.path); + allFiles = [file]; + const rlinks = this.app.metadataCache.resolvedLinks[file.path]; + if (rlinks) { + debugLog("getAttachmentsInVaultByLinks - rlinks:", rlinks); + resolvedLinks[file.path] = rlinks; + } else if (oldPath) { + debugLog("getAttachmentsInVaultByLinks - oldPath:", oldPath); + // in some cases, this.app.metadataCache.resolvedLinks[file.path] will be empty since the cache is not updated + resolvedLinks[file.path] = this.app.metadataCache.resolvedLinks[oldPath]; } + debugLog("getAttachmentsInVaultByLinks - resolvedLinks:", resolvedLinks); + } } - /** - * Retrieves the attachments in the vault based on the specified settings and type. - * If a file is provided, only attachments related to that file will be returned. - * - * @param {AttachmentManagementPluginSettings} settings - The settings for the attachment management plugin. - * @param {"active" | "links" | "file"} type - The type of attachments to retrieve. - * @param {TFile} [file] - The file to filter attachments by. Optional. - * @return {Promise>>} - A promise that resolves to a record of attachments, where each key is a file name and each value is a set of attachment names. - */ - async getAttachmentsInVault( - settings: AttachmentManagementPluginSettings, - type: "active" | "links" | "file", - file?: TFile, - oldPath?: string - ): Promise>> { - let attachmentsRecord: Record> = {}; + debugLog("getAttachmentsInVaultByLinks - allFiles:", allFiles.length, allFiles); - attachmentsRecord = await this.getAttachmentsInVaultByLinks(settings, type, file, oldPath); - - return attachmentsRecord; - } - - /** - * Modified from https://github.com/ozntel/oz-clear-unused-images-obsidian/blob/master/src/util.ts#LL48C21-L48C21 - * Retrieves a record of attachments in the vault based on the given settings and type. - * - * @param {AttachmentManagementPluginSettings} settings - The settings for the attachment management plugin. - * @param {"active" | "links" | "file"} type - The type of attachments to retrieve. - * @param {TFile} file - The file to retrieve attachments for (optional). - * @return {Promise>>} - A promise that resolves to a record of attachments. - */ - async getAttachmentsInVaultByLinks( - settings: AttachmentManagementPluginSettings, - type: "active" | "links" | "file", - file?: TFile, - oldPath?: string - ): Promise>> { - const attachmentsRecord: Record> = {}; - let resolvedLinks: Record> = {}; - let allFiles: TFile[] = []; - if (type === "links") { - // resolvedLinks was not working for canvas file - resolvedLinks = this.app.metadataCache.resolvedLinks; - allFiles = this.app.vault.getFiles(); - } else if (type === "active") { - const file = getActiveFile(this.app); - if (file) { - if ((file.parent && isExcluded(file.parent.path, this.settings)) || isAttachment(this.settings, file)) { - allFiles = []; - new Notice(`${file.path} was excluded, skipped`); - } else { - debugLog("getAttachmentsInVaultByLinks - active:", file.path); - allFiles = [file]; - if (this.app.metadataCache.resolvedLinks[file.path]) { - resolvedLinks[file.path] = this.app.metadataCache.resolvedLinks[file.path]; - } - debugLog("getAttachmentsInVaultByLinks - resolvedLinks:", resolvedLinks); - } - } - } else if (type === "file" && file != undefined) { - if ((file.parent && isExcluded(file.parent.path, this.settings)) || isAttachment(this.settings, file)) { - allFiles = []; - new Notice(`${file.path} was excluded, skipped`); - } else { - debugLog("getAttachmentsInVaultByLinks - file:", file.path); - allFiles = [file]; - const rlinks = this.app.metadataCache.resolvedLinks[file.path]; - if (rlinks) { - debugLog("getAttachmentsInVaultByLinks - rlinks:", rlinks); - resolvedLinks[file.path] = rlinks; - } else if (oldPath) { - debugLog("getAttachmentsInVaultByLinks - oldPath:", oldPath); - // in some cases, this.app.metadataCache.resolvedLinks[file.path] will be empty since the cache is not updated - resolvedLinks[file.path] = this.app.metadataCache.resolvedLinks[oldPath]; - } - debugLog("getAttachmentsInVaultByLinks - resolvedLinks:", resolvedLinks); + if (resolvedLinks) { + for (const [mdFile, links] of Object.entries(resolvedLinks)) { + const attachmentsSet: Set = new Set(); + if (links) { + for (const [filePath] of Object.entries(links)) { + if (isAttachment(settings, filePath)) { + this.addToSet(attachmentsSet, filePath); } + } + this.addToRecord(attachmentsRecord, mdFile, attachmentsSet); } + } + } + // Loop Files and Check Frontmatter/Canvas + for (let i = 0; i < allFiles.length; i++) { + const obsFile = allFiles[i]; + const attachmentsSet: Set = new Set(); - debugLog("getAttachmentsInVaultByLinks - allFiles:", allFiles.length, allFiles); + if (obsFile.parent && isExcluded(obsFile.parent.path, this.settings)) { + continue; + } - if (resolvedLinks) { - for (const [mdFile, links] of Object.entries(resolvedLinks)) { - const attachmentsSet: Set = new Set(); - if (links) { - for (const [filePath] of Object.entries(links)) { - if (isAttachment(settings, filePath)) { - this.addToSet(attachmentsSet, filePath); - } - } - this.addToRecord(attachmentsRecord, mdFile, attachmentsSet); + // Check Frontmatter for md files and additional links that might be missed in resolved links + if (isMarkdownFile(obsFile.extension)) { + // Frontmatter + const fileCache = this.app.metadataCache.getFileCache(obsFile); + if (fileCache === null) { + continue; + } + if (fileCache.frontmatter) { + const frontmatter = fileCache.frontmatter; + for (const k of Object.keys(frontmatter)) { + if (typeof frontmatter[k] === "string") { + const formatMatch = frontmatter[k].match(bannerRegex); + if (formatMatch && formatMatch[1]) { + const fileName = formatMatch[1]; + const file = this.app.metadataCache.getFirstLinkpathDest(fileName, obsFile.path); + if (file && isAttachment(settings, file.path)) { + this.addToSet(attachmentsSet, file.path); } + } } + } } - // Loop Files and Check Frontmatter/Canvas - for (let i = 0; i < allFiles.length; i++) { - const obsFile = allFiles[i]; - const attachmentsSet: Set = new Set(); - - if (obsFile.parent && isExcluded(obsFile.parent.path, this.settings)) { - continue; - } - - // Check Frontmatter for md files and additional links that might be missed in resolved links - if (isMarkdownFile(obsFile.extension)) { - // Frontmatter - const fileCache = this.app.metadataCache.getFileCache(obsFile); - if (fileCache === null) { - continue; - } - if (fileCache.frontmatter) { - const frontmatter = fileCache.frontmatter; - for (const k of Object.keys(frontmatter)) { - if (typeof frontmatter[k] === "string") { - const formatMatch = frontmatter[k].match(bannerRegex); - if (formatMatch && formatMatch[1]) { - const fileName = formatMatch[1]; - const file = this.app.metadataCache.getFirstLinkpathDest(fileName, obsFile.path); - if (file && isAttachment(settings, file.path)) { - this.addToSet(attachmentsSet, file.path); - } - } - } - } - } - // Any Additional Link - const linkMatches: LinkMatch[] = await getAllLinkMatchesInFile(obsFile, app); - for (const linkMatch of linkMatches) { - if (isAttachment(settings, linkMatch.linkText)) { - this.addToSet(attachmentsSet, linkMatch.linkText); - } - } - } else if (isCanvasFile(obsFile.extension)) { - // check canvas for links - const fileRead = await this.app.vault.cachedRead(obsFile); - if (!fileRead || fileRead.length === 0) { - continue; - } - let canvasData; - try { - canvasData = JSON.parse(fileRead); - } catch (e) { - debugLog("getAttachmentsInVaultByLinks - parse canvas data error", e); - continue; - } - // debugLog("canvasData", canvasData); - if (canvasData.nodes && canvasData.nodes.length > 0) { - for (const node of canvasData.nodes) { - // node.type: 'text' | 'file' - if (node.type === "file") { - if (isAttachment(settings, node.file)) { - this.addToSet(attachmentsSet, node.file); - } - } else if (node.type == "text") { - const linkMatches: LinkMatch[] = await getAllLinkMatchesInFile(obsFile, app, node.text); - for (const linkMatch of linkMatches) { - if (isAttachment(settings, linkMatch.linkText)) { - this.addToSet(attachmentsSet, linkMatch.linkText); - } - } - } - } + // Any Additional Link + const linkMatches: LinkMatch[] = await getAllLinkMatchesInFile(obsFile, app); + for (const linkMatch of linkMatches) { + if (isAttachment(settings, linkMatch.linkText)) { + this.addToSet(attachmentsSet, linkMatch.linkText); + } + } + } else if (isCanvasFile(obsFile.extension)) { + // check canvas for links + const fileRead = await this.app.vault.cachedRead(obsFile); + if (!fileRead || fileRead.length === 0) { + continue; + } + let canvasData; + try { + canvasData = JSON.parse(fileRead); + } catch (e) { + debugLog("getAttachmentsInVaultByLinks - parse canvas data error", e); + continue; + } + // debugLog("canvasData", canvasData); + if (canvasData.nodes && canvasData.nodes.length > 0) { + for (const node of canvasData.nodes) { + // node.type: 'text' | 'file' + if (node.type === "file") { + if (isAttachment(settings, node.file)) { + this.addToSet(attachmentsSet, node.file); + } + } else if (node.type == "text") { + const linkMatches: LinkMatch[] = await getAllLinkMatchesInFile(obsFile, app, node.text); + for (const linkMatch of linkMatches) { + if (isAttachment(settings, linkMatch.linkText)) { + this.addToSet(attachmentsSet, linkMatch.linkText); } + } } - this.addToRecord(attachmentsRecord, obsFile.path, attachmentsSet); + } } - return attachmentsRecord; + } + this.addToRecord(attachmentsRecord, obsFile.path, attachmentsSet); } + return attachmentsRecord; + } - addToRecord(record: Record>, key: string, value: Set) { - if (record[key] === undefined) { - record[key] = value; - return; - } - const valueSet = record[key]; - - for (const val of value) { - this.addToSet(valueSet, val); - } + addToRecord(record: Record>, key: string, value: Set) { + if (record[key] === undefined) { + record[key] = value; + return; + } + const valueSet = record[key]; - record[key] = valueSet; + for (const val of value) { + this.addToSet(valueSet, val); } - addToSet(setObj: Set, value: string) { - if (!setObj.has(value)) { - setObj.add(value); - } + record[key] = valueSet; + } + + addToSet(setObj: Set, value: string) { + if (!setObj.has(value)) { + setObj.add(value); } + } - needToRename( - settings: AttachmentPathSettings, - attachPath: string, - attachName: string, - noteName: string, - link: string - ): boolean { - const linkPath = path.dirname(link); - const linkName = path.basename(link, path.extname(link)); + needToRename( + settings: AttachmentPathSettings, + attachPath: string, + attachName: string, + noteName: string, + link: string + ): boolean { + const linkPath = path.dirname(link); + const linkName = path.basename(link, path.extname(link)); - if (linkName.length !== attachName.length) { - return true; - } + if (linkName.length !== attachName.length) { + return true; + } - if (attachPath !== linkPath) { - return true; - } else { - if (settings.attachFormat.includes(SETTINGS_VARIABLES_NOTENAME) && !linkName.includes(noteName)) { - return true; - } - // suppose the ${notename} was in format - const noNoteNameAttachFormat = settings.attachFormat.split(SETTINGS_VARIABLES_NOTENAME); - if (settings.attachFormat.includes(SETTINGS_VARIABLES_DATES)) { - for (const formatPart in noNoteNameAttachFormat) { - // suppose the ${date} was in format, split each part and search in linkName - const splited = formatPart.split(SETTINGS_VARIABLES_DATES); - for (const part in splited) { - if (!linkName.includes(part)) { - return true; - } - } - } + if (attachPath !== linkPath) { + return true; + } else { + if (settings.attachFormat.includes(SETTINGS_VARIABLES_NOTENAME) && !linkName.includes(noteName)) { + return true; + } + // suppose the ${notename} was in format + const noNoteNameAttachFormat = settings.attachFormat.split(SETTINGS_VARIABLES_NOTENAME); + if (settings.attachFormat.includes(SETTINGS_VARIABLES_DATES)) { + for (const formatPart in noNoteNameAttachFormat) { + // suppose the ${date} was in format, split each part and search in linkName + const splited = formatPart.split(SETTINGS_VARIABLES_DATES); + for (const part in splited) { + if (!linkName.includes(part)) { + return true; } + } } - - return false; + } } + + return false; + } } diff --git a/src/commons.ts b/src/commons.ts index f018a3c..a43e96f 100644 --- a/src/commons.ts +++ b/src/commons.ts @@ -8,14 +8,14 @@ import { AttachmentPathSettings, ExtensionOverrideSettings } from "./settings/se * @returns - the active file or undefined if no active file */ export function getActiveFile(app: App): TFile | undefined { - const view = getActiveView(app); - if (view == null) { - return undefined; - } else if (view.file == null) { - return undefined; - } else { - return view.file; - } + const view = getActiveView(app); + if (view == null) { + return undefined; + } else if (view.file == null) { + return undefined; + } else { + return view.file; + } } /** @@ -23,7 +23,7 @@ export function getActiveFile(app: App): TFile | undefined { * @returns - the active view of text file */ export function getActiveView(app: App): TextFileView | null { - return app.workspace.getActiveViewOfType(TextFileView); + return app.workspace.getActiveViewOfType(TextFileView); } /** @@ -33,53 +33,53 @@ export function getActiveView(app: App): TextFileView | null { * @returns root path to save attachment file */ export function getRootPath(notePath: string, setting: AttachmentPathSettings | ExtensionOverrideSettings): string { - let root: string; + let root: string; - //@ts-ignore - const obsmediadir = app.vault.getConfig("attachmentFolderPath"); - // debugLog("obsmediadir", obsmediadir); - switch (setting.saveAttE) { - case `${SETTINGS_ROOT_INFOLDER}`: - root = path.join(setting.attachmentRoot); - break; - case `${SETTINGS_ROOT_NEXTTONOTE}`: - root = path.join(notePath, setting.attachmentRoot.replace("./", "")); - break; - default: - if (obsmediadir === "/") { - // in vault root folder case - root = obsmediadir; - } else if (obsmediadir === "./") { - // in current folder case - root = path.join(notePath); - } else if (obsmediadir.match(/\.\/.+/g) !== null) { - // in subfolder case - root = path.join(notePath, obsmediadir.replace("./", "")); - } else { - // in specified folder case - root = obsmediadir; - } - } + //@ts-ignore + const obsmediadir = app.vault.getConfig("attachmentFolderPath"); + // debugLog("obsmediadir", obsmediadir); + switch (setting.saveAttE) { + case `${SETTINGS_ROOT_INFOLDER}`: + root = path.join(setting.attachmentRoot); + break; + case `${SETTINGS_ROOT_NEXTTONOTE}`: + root = path.join(notePath, setting.attachmentRoot.replace("./", "")); + break; + default: + if (obsmediadir === "/") { + // in vault root folder case + root = obsmediadir; + } else if (obsmediadir === "./") { + // in current folder case + root = path.join(notePath); + } else if (obsmediadir.match(/\.\/.+/g) !== null) { + // in subfolder case + root = path.join(notePath, obsmediadir.replace("./", "")); + } else { + // in specified folder case + root = obsmediadir; + } + } - return root === "/" ? root : normalizePath(root); + return root === "/" ? root : normalizePath(root); } export async function checkEmptyFolder(adapter: DataAdapter, path: string): Promise { - const exist = await adapter.exists(path, true); - if (!exist) { - return true; - } + const exist = await adapter.exists(path, true); + if (!exist) { + return true; + } - const data = await adapter.list(path); - if (data.files.length > 0) { - return false; - } + const data = await adapter.list(path); + if (data.files.length > 0) { + return false; + } - if (data.folders.length > 0) { - for (let i = 0; i < data.folders.length; i++) { - return checkEmptyFolder(adapter, data.folders[i]); - } + if (data.folders.length > 0) { + for (let i = 0; i < data.folders.length; i++) { + return checkEmptyFolder(adapter, data.folders[i]); } + } - return true; + return true; } diff --git a/src/create.ts b/src/create.ts index 2f646ce..66bde30 100644 --- a/src/create.ts +++ b/src/create.ts @@ -11,89 +11,89 @@ import { MD5, isImage, isPastedImage } from "./utils"; import { saveOriginalName } from "./lib/originalStorage"; export class CreateHandler { - readonly plugin: Plugin; - readonly app: App; - readonly settings: AttachmentManagementPluginSettings; + readonly plugin: Plugin; + readonly app: App; + readonly settings: AttachmentManagementPluginSettings; - constructor(plugin: Plugin, settings: AttachmentManagementPluginSettings) { - this.plugin = plugin; - this.app = this.plugin.app; - this.settings = settings; + constructor(plugin: Plugin, settings: AttachmentManagementPluginSettings) { + this.plugin = plugin; + this.app = this.plugin.app; + this.settings = settings; + } + + /** + * Post-processing of created attachment file (for paste and drop event). + * @param attach - the attachment file to process + * @returns - none + */ + processAttach(attach: TFile, source: TFile) { + if (source.parent && isExcluded(source.parent.path, this.settings)) { + debugLog("processAttach - not a file or exclude path:", source.path); + new Notice(`${source.path} was excluded, skipped`); + return; } - /** - * Post-processing of created attachment file (for paste and drop event). - * @param attach - the attachment file to process - * @returns - none - */ - processAttach(attach: TFile, source: TFile) { - if (source.parent && isExcluded(source.parent.path, this.settings)) { - debugLog("processAttach - not a file or exclude path:", source.path); - new Notice(`${source.path} was excluded, skipped`); - return; - } + const { setting } = getOverrideSetting(this.settings, source); + const { extSetting } = getExtensionOverrideSetting(attach.extension, setting); - const { setting } = getOverrideSetting(this.settings, source); - const { extSetting } = getExtensionOverrideSetting(attach.extension, setting); + debugLog("processAttach - file.extension:", attach.extension); + if (extSetting === undefined && !isImage(attach.extension) && !isPastedImage(attach)) { + debugLog("renameFiles - no handle extension:", attach.extension); + return; + } - debugLog("processAttach - file.extension:", attach.extension); - if (extSetting === undefined && !isImage(attach.extension) && !isPastedImage(attach)) { - debugLog("renameFiles - no handle extension:", attach.extension); - return; - } + const metadata = getMetadata(source.path, attach); + debugLog("processAttach - metadata:", metadata); - const metadata = getMetadata(source.path, attach); - debugLog("processAttach - metadata:", metadata); + const attachPath = metadata.getAttachmentPath(setting, this.settings.dateFormat); + metadata + .getAttachFileName(setting, this.settings.dateFormat, attach.basename, this.app.vault.adapter) + .then((attachName) => { + attachName = attachName + "." + attach.extension; + // make sure the attachment path was created + this.app.vault.adapter.mkdir(attachPath).finally(() => { + debugLog("processAttach - create path:", attachPath); + const attachPathFolder = this.app.vault.getAbstractFileByPath(attachPath) as TFolder; + deduplicateNewName(attachName, attachPathFolder).then(({ name }) => { + debugLog("processAttach - new path of file:", path.join(attachPath, name)); + this.renameCreateFile(attach, attachPath, name, source); + }); + }); + }); + } - const attachPath = metadata.getAttachmentPath(setting, this.settings.dateFormat); - metadata - .getAttachFileName(setting, this.settings.dateFormat, attach.basename, this.app.vault.adapter) - .then((attachName) => { - attachName = attachName + "." + attach.extension; - // make sure the attachment path was created - this.app.vault.adapter.mkdir(attachPath).finally(() => { - debugLog("processAttach - create path:", attachPath); - const attachPathFolder = this.app.vault.getAbstractFileByPath(attachPath) as TFolder; - deduplicateNewName(attachName, attachPathFolder).then(({ name }) => { - debugLog("processAttach - new path of file:", path.join(attachPath, name)); - this.renameCreateFile(attach, attachPath, name, source); - }); - }); - }); - } + /** + * Rename the file specified by `@param file`, and update the link of the file if specified updateLink + * @param attach - file to rename + * @param attachPath - where to the renamed file will be move to + * @param attachName - name of the renamed file + * @param source - associated active file + * @returns - none + */ + renameCreateFile(attach: TFile, attachPath: string, attachName: string, source: TFile) { + const dst = normalizePath(path.join(attachPath, attachName)); + debugLog("renameFile - ", attach.path, " to ", dst); - /** - * Rename the file specified by `@param file`, and update the link of the file if specified updateLink - * @param attach - file to rename - * @param attachPath - where to the renamed file will be move to - * @param attachName - name of the renamed file - * @param source - associated active file - * @returns - none - */ - renameCreateFile(attach: TFile, attachPath: string, attachName: string, source: TFile) { - const dst = normalizePath(path.join(attachPath, attachName)); - debugLog("renameFile - ", attach.path, " to ", dst); + const original = attach.basename; + const name = attach.name; - const original = attach.basename; - const name = attach.name; - - // this api will not update the link in markdown file automatically on `create` event - // forgive using to rename, refer: https://github.com/trganda/obsidian-attachment-management/issues/46 - this.app.fileManager - .renameFile(attach, dst) - .then(() => { - new Notice(`Renamed ${name} to ${attachName}.`); - }) - .finally(() => { - // save origianl name in setting - const { setting } = getOverrideSetting(this.settings, source); - MD5(this.app.vault.adapter, attach).then((md5) => { - saveOriginalName(this.settings, setting, attach.extension, { - n: original, - md5: md5, - }); - this.plugin.saveData(this.settings); - }); - }); - } + // this api will not update the link in markdown file automatically on `create` event + // forgive using to rename, refer: https://github.com/trganda/obsidian-attachment-management/issues/46 + this.app.fileManager + .renameFile(attach, dst) + .then(() => { + new Notice(`Renamed ${name} to ${attachName}.`); + }) + .finally(() => { + // save origianl name in setting + const { setting } = getOverrideSetting(this.settings, source); + MD5(this.app.vault.adapter, attach).then((md5) => { + saveOriginalName(this.settings, setting, attach.extension, { + n: original, + md5: md5, + }); + this.plugin.saveData(this.settings); + }); + }); + } } diff --git a/src/exclude.ts b/src/exclude.ts index 9f53f23..2bca14c 100644 --- a/src/exclude.ts +++ b/src/exclude.ts @@ -2,21 +2,21 @@ import { debugLog } from "./lib/log"; import { AttachmentManagementPluginSettings } from "./settings/settings"; export function isExcluded(path: string, settings: AttachmentManagementPluginSettings): boolean { - debugLog("excludePathsArray: ", settings.excludePathsArray); + debugLog("excludePathsArray: ", settings.excludePathsArray); - for (const excludedPath of settings.excludePathsArray) { - if (excludedPath.length === 0) { - continue; - } - if (settings.excludeSubpaths && path.startsWith(excludedPath)) { - debugLog("isExcluded: ", path); - return true; - } else { - if (path === excludedPath) { - return true; - } - } + for (const excludedPath of settings.excludePathsArray) { + if (excludedPath.length === 0) { + continue; } + if (settings.excludeSubpaths && path.startsWith(excludedPath)) { + debugLog("isExcluded: ", path); + return true; + } else { + if (path === excludedPath) { + return true; + } + } + } - return false; + return false; } diff --git a/src/lib/deduplicate.ts b/src/lib/deduplicate.ts index cb127ef..8bc54f0 100644 --- a/src/lib/deduplicate.ts +++ b/src/lib/deduplicate.ts @@ -3,62 +3,62 @@ import { debugLog } from "./log"; import { path } from "./path"; export interface NameObj { - name: string; - basename: string; - extension: string; + name: string; + basename: string; + extension: string; } // ref: https://stackoverflow.com/a/6969486/596206 function escapeRegExp(s: string) { - return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } export async function deduplicateNewName(newName: string, file: TFolder): Promise { - // list files in dir - const dir = file.path; - const listed = await this.app.vault.adapter.list(dir); - debugLog("deduplicateNewName - sibling files", listed); + // list files in dir + const dir = file.path; + const listed = await this.app.vault.adapter.list(dir); + debugLog("deduplicateNewName - sibling files", listed); - // parse newName - const newNameExt = path.extname(newName), - newNameStem = newName.slice(0, newName.length - newNameExt.length - 1), - newNameStemEscaped = escapeRegExp(newNameStem), - delimiter = "-", - delimiterEscaped = escapeRegExp(delimiter); + // parse newName + const newNameExt = path.extname(newName), + newNameStem = newName.slice(0, newName.length - newNameExt.length - 1), + newNameStemEscaped = escapeRegExp(newNameStem), + delimiter = "-", + delimiterEscaped = escapeRegExp(delimiter); - const dupNameRegex = new RegExp( - `^(?${newNameStemEscaped})${delimiterEscaped}(?\\d{1,3})\\.${newNameExt}$` - ); + const dupNameRegex = new RegExp( + `^(?${newNameStemEscaped})${delimiterEscaped}(?\\d{1,3})\\.${newNameExt}$` + ); - debugLog("dupNameRegex", dupNameRegex); + debugLog("dupNameRegex", dupNameRegex); - const dupNameNumbers: number[] = []; - let isNewNameExist = false; - // match dupNames and update the number - for (let sibling of listed.files) { - sibling = path.basename(sibling); - if (sibling == newName) { - isNewNameExist = true; - continue; - } - - // match dupNames - const m = dupNameRegex.exec(sibling); - if (!m || m.groups === undefined) continue; - // parse int for m.groups.number - dupNameNumbers.push(parseInt(m.groups.number)); + const dupNameNumbers: number[] = []; + let isNewNameExist = false; + // match dupNames and update the number + for (let sibling of listed.files) { + sibling = path.basename(sibling); + if (sibling == newName) { + isNewNameExist = true; + continue; } - if (isNewNameExist) { - // get max number - const newNumber = dupNameNumbers.length > 0 ? Math.max(...dupNameNumbers) + 1 : 1; - // change newName - newName = `${newNameStem}${delimiter}${newNumber}.${newNameExt}`; - } + // match dupNames + const m = dupNameRegex.exec(sibling); + if (!m || m.groups === undefined) continue; + // parse int for m.groups.number + dupNameNumbers.push(parseInt(m.groups.number)); + } + + if (isNewNameExist) { + // get max number + const newNumber = dupNameNumbers.length > 0 ? Math.max(...dupNameNumbers) + 1 : 1; + // change newName + newName = `${newNameStem}${delimiter}${newNumber}.${newNameExt}`; + } - return { - name: newName, - basename: newName.slice(0, newName.length - newNameExt.length - 1), - extension: newNameExt, - }; + return { + name: newName, + basename: newName.slice(0, newName.length - newNameExt.length - 1), + extension: newNameExt, + }; } diff --git a/src/lib/linkDetector.ts b/src/lib/linkDetector.ts index a52b8bf..918ac00 100644 --- a/src/lib/linkDetector.ts +++ b/src/lib/linkDetector.ts @@ -6,10 +6,10 @@ import { TFile, App } from "obsidian"; type LinkType = "markdown" | "wiki" | "wikiTransclusion" | "mdTransclusion"; export interface LinkMatch { - type: LinkType; - match: string; - linkText: string; - sourceFilePath: string; + type: LinkType; + match: string; + linkText: string; + sourceFilePath: string; } /** @@ -20,88 +20,88 @@ export interface LinkMatch { * @returns Promise */ export const getAllLinkMatchesInFile = async (mdFile: TFile, app: App, fileText?: string): Promise => { - const linkMatches: LinkMatch[] = []; - if (fileText === undefined) { - fileText = await app.vault.read(mdFile); - } + const linkMatches: LinkMatch[] = []; + if (fileText === undefined) { + fileText = await app.vault.read(mdFile); + } - // --> Get All WikiLinks - const wikiRegex = /\[\[.*?\]\]/g; - const wikiMatches = fileText.match(wikiRegex); - if (wikiMatches) { - const fileRegex = /(?<=\[\[).*?(?=(\]|\|))/; + // --> Get All WikiLinks + const wikiRegex = /\[\[.*?\]\]/g; + const wikiMatches = fileText.match(wikiRegex); + if (wikiMatches) { + const fileRegex = /(?<=\[\[).*?(?=(\]|\|))/; - for (const wikiMatch of wikiMatches) { - // --> Check if it is Transclusion - if (matchIsWikiTransclusion(wikiMatch)) { - const fileName = getTransclusionFileName(wikiMatch); - const file = app.metadataCache.getFirstLinkpathDest(fileName, mdFile.path); - if (fileName !== "") { - const linkMatch: LinkMatch = { - type: "wikiTransclusion", - match: wikiMatch, - linkText: file ? file.path : fileName, - sourceFilePath: mdFile.path, - }; - linkMatches.push(linkMatch); - continue; - } - } - // --> Normal Internal Link - const fileMatch = wikiMatch.match(fileRegex); - if (fileMatch) { - // Web links are to be skipped - if (fileMatch[0].startsWith("http")) continue; - const file = app.metadataCache.getFirstLinkpathDest(fileMatch[0], mdFile.path); - const linkMatch: LinkMatch = { - type: "wiki", - match: wikiMatch, - linkText: file ? file.path : fileMatch[0], - sourceFilePath: mdFile.path, - }; - linkMatches.push(linkMatch); - } + for (const wikiMatch of wikiMatches) { + // --> Check if it is Transclusion + if (matchIsWikiTransclusion(wikiMatch)) { + const fileName = getTransclusionFileName(wikiMatch); + const file = app.metadataCache.getFirstLinkpathDest(fileName, mdFile.path); + if (fileName !== "") { + const linkMatch: LinkMatch = { + type: "wikiTransclusion", + match: wikiMatch, + linkText: file ? file.path : fileName, + sourceFilePath: mdFile.path, + }; + linkMatches.push(linkMatch); + continue; } + } + // --> Normal Internal Link + const fileMatch = wikiMatch.match(fileRegex); + if (fileMatch) { + // Web links are to be skipped + if (fileMatch[0].startsWith("http")) continue; + const file = app.metadataCache.getFirstLinkpathDest(fileMatch[0], mdFile.path); + const linkMatch: LinkMatch = { + type: "wiki", + match: wikiMatch, + linkText: file ? file.path : fileMatch[0], + sourceFilePath: mdFile.path, + }; + linkMatches.push(linkMatch); + } } + } - // --> Get All Markdown Links - const markdownRegex = /\[(^$|.*?)\]\((.*?)\)/g; - const markdownMatches = fileText.match(markdownRegex); - if (markdownMatches) { - const fileRegex = /(?<=\().*(?=\))/; - for (const markdownMatch of markdownMatches) { - // --> Check if it is Transclusion - if (matchIsMdTransclusion(markdownMatch)) { - const fileName = getTransclusionFileName(markdownMatch); - const file = app.metadataCache.getFirstLinkpathDest(fileName, mdFile.path); - if (fileName !== "") { - const linkMatch: LinkMatch = { - type: "mdTransclusion", - match: markdownMatch, - linkText: file ? file.path : fileName, - sourceFilePath: mdFile.path, - }; - linkMatches.push(linkMatch); - continue; - } - } - // --> Normal Internal Link - const fileMatch = markdownMatch.match(fileRegex); - if (fileMatch) { - // Web links are to be skipped - if (fileMatch[0].startsWith("http")) continue; - const file = app.metadataCache.getFirstLinkpathDest(fileMatch[0], mdFile.path); - const linkMatch: LinkMatch = { - type: "markdown", - match: markdownMatch, - linkText: file ? file.path : fileMatch[0], - sourceFilePath: mdFile.path, - }; - linkMatches.push(linkMatch); - } + // --> Get All Markdown Links + const markdownRegex = /\[(^$|.*?)\]\((.*?)\)/g; + const markdownMatches = fileText.match(markdownRegex); + if (markdownMatches) { + const fileRegex = /(?<=\().*(?=\))/; + for (const markdownMatch of markdownMatches) { + // --> Check if it is Transclusion + if (matchIsMdTransclusion(markdownMatch)) { + const fileName = getTransclusionFileName(markdownMatch); + const file = app.metadataCache.getFirstLinkpathDest(fileName, mdFile.path); + if (fileName !== "") { + const linkMatch: LinkMatch = { + type: "mdTransclusion", + match: markdownMatch, + linkText: file ? file.path : fileName, + sourceFilePath: mdFile.path, + }; + linkMatches.push(linkMatch); + continue; } + } + // --> Normal Internal Link + const fileMatch = markdownMatch.match(fileRegex); + if (fileMatch) { + // Web links are to be skipped + if (fileMatch[0].startsWith("http")) continue; + const file = app.metadataCache.getFirstLinkpathDest(fileMatch[0], mdFile.path); + const linkMatch: LinkMatch = { + type: "markdown", + match: markdownMatch, + linkText: file ? file.path : fileMatch[0], + sourceFilePath: mdFile.path, + }; + linkMatches.push(linkMatch); + } } - return linkMatches; + } + return linkMatches; }; /* ---------- HELPERS ---------- */ @@ -113,11 +113,11 @@ const mdTransclusionRegex = /\[.*?]\((.*?)#.*?\)/; const mdTransclusionFileNameRegex = /(?<=\]\()(.*)(?=#)/; const matchIsWikiTransclusion = (match: string): boolean => { - return wikiTransclusionRegex.test(match); + return wikiTransclusionRegex.test(match); }; const matchIsMdTransclusion = (match: string): boolean => { - return mdTransclusionRegex.test(match); + return mdTransclusionRegex.test(match); }; /** @@ -125,11 +125,11 @@ const matchIsMdTransclusion = (match: string): boolean => { * @returns file name if there is a match or empty string if no match */ const getTransclusionFileName = (match: string): string => { - const isWiki = wikiTransclusionRegex.test(match); - const isMd = mdTransclusionRegex.test(match); - if (isWiki || isMd) { - const fileNameMatch = match.match(isWiki ? wikiTransclusionFileNameRegex : mdTransclusionFileNameRegex); - if (fileNameMatch) return fileNameMatch[0]; - } - return ""; + const isWiki = wikiTransclusionRegex.test(match); + const isMd = mdTransclusionRegex.test(match); + if (isWiki || isMd) { + const fileNameMatch = match.match(isWiki ? wikiTransclusionFileNameRegex : mdTransclusionFileNameRegex); + if (fileNameMatch) return fileNameMatch[0]; + } + return ""; }; diff --git a/src/lib/log.ts b/src/lib/log.ts index 054b4f8..52ca7e2 100644 --- a/src/lib/log.ts +++ b/src/lib/log.ts @@ -2,7 +2,7 @@ export const DEBUG = !(process.env.BUILD_ENV === "production"); if (DEBUG) console.log("DEBUG is enabled"); export function debugLog(...args: unknown[]) { - if (DEBUG) { - console.log(new Date().toISOString().slice(11, 23), ...args); - } + if (DEBUG) { + console.log(new Date().toISOString().slice(11, 23), ...args); + } } diff --git a/src/lib/originalStorage.ts b/src/lib/originalStorage.ts index 9cb9244..c1b491f 100644 --- a/src/lib/originalStorage.ts +++ b/src/lib/originalStorage.ts @@ -3,61 +3,61 @@ import { AttachmentPathSettings, AttachmentManagementPluginSettings, OriginalNam import { SETTINGS_VARIABLES_ORIGINALNAME } from "./constant"; export function containOriginalNameVariable(setting: AttachmentPathSettings, ext: string): boolean { - const { extSetting } = getExtensionOverrideSetting(ext, setting); - if ( - (extSetting !== undefined && extSetting.attachFormat.contains(SETTINGS_VARIABLES_ORIGINALNAME)) || - setting.attachFormat.contains(SETTINGS_VARIABLES_ORIGINALNAME) - ) { - return true; - } - return false; + const { extSetting } = getExtensionOverrideSetting(ext, setting); + if ( + (extSetting !== undefined && extSetting.attachFormat.contains(SETTINGS_VARIABLES_ORIGINALNAME)) || + setting.attachFormat.contains(SETTINGS_VARIABLES_ORIGINALNAME) + ) { + return true; + } + return false; } export function saveOriginalName( - settings: AttachmentManagementPluginSettings, - setting: AttachmentPathSettings, - ext: string, - data: OriginalNameStorage + settings: AttachmentManagementPluginSettings, + setting: AttachmentPathSettings, + ext: string, + data: OriginalNameStorage ) { - if (settings.originalNameStorage === undefined) { - settings.originalNameStorage = []; - } + if (settings.originalNameStorage === undefined) { + settings.originalNameStorage = []; + } - if (containOriginalNameVariable(setting, ext)) { - settings.originalNameStorage - .filter((n) => n.md5 == data.md5) - .forEach((n) => settings.originalNameStorage.remove(n)); - settings.originalNameStorage.push(data); - } + if (containOriginalNameVariable(setting, ext)) { + settings.originalNameStorage + .filter((n) => n.md5 == data.md5) + .forEach((n) => settings.originalNameStorage.remove(n)); + settings.originalNameStorage.push(data); + } } export function loadOriginalName( - settings: AttachmentManagementPluginSettings, - setting: AttachmentPathSettings, - ext: string, - md5: string + settings: AttachmentManagementPluginSettings, + setting: AttachmentPathSettings, + ext: string, + md5: string ): OriginalNameStorage | undefined { - if (containOriginalNameVariable(setting, ext)) { - const first = settings.originalNameStorage.find((data) => data.md5 === md5); - const last = settings.originalNameStorage.reverse().find((data) => data.md5 === md5); + if (containOriginalNameVariable(setting, ext)) { + const first = settings.originalNameStorage.find((data) => data.md5 === md5); + const last = settings.originalNameStorage.reverse().find((data) => data.md5 === md5); - if (first === undefined || last == undefined) { - return undefined; - } - if (first.md5 === last.md5 && first.n === last.n) { - return last; - } else if (first.md5 === last.md5 && first.n !== last.n) { - // remove duplicated item, the oldder one - settings.originalNameStorage.remove(first); - return last; - } + if (first === undefined || last == undefined) { + return undefined; + } + if (first.md5 === last.md5 && first.n === last.n) { + return last; + } else if (first.md5 === last.md5 && first.n !== last.n) { + // remove duplicated item, the oldder one + settings.originalNameStorage.remove(first); + return last; } - return undefined; + } + return undefined; } export function rmOriginalName(settings: AttachmentManagementPluginSettings, md5: string) { - const prepares = settings.originalNameStorage.filter((data) => (data.md5 = md5)); - prepares.forEach((p) => { - settings.originalNameStorage.remove(p); - }); + const prepares = settings.originalNameStorage.filter((data) => (data.md5 = md5)); + prepares.forEach((p) => { + settings.originalNameStorage.remove(p); + }); } diff --git a/src/lib/path.ts b/src/lib/path.ts index 49be989..0944855 100644 --- a/src/lib/path.ts +++ b/src/lib/path.ts @@ -1,54 +1,54 @@ // modified from https://github.com/reorx/obsidian-paste-image-rename/blob/c187bf6ffc897da793eba930f9578710795460ec/src/utils.ts#L37 export const path = { - // Credit: [@creationix/path.js](https://gist.github.com/creationix/7435851) - join(...partSegments: string[]): string { - // Split the inputs into a list of path commands. - let parts: string[] = []; - for (let i = 0, l = partSegments.length; i < l; i++) { - parts = parts.concat(partSegments[i].split("/")); - } - // Interpret the path commands to get the new resolved path. - const newParts = []; - for (let i = 0, l = parts.length; i < l; i++) { - const part = parts[i]; - // Remove leading and trailing slashes - // Also remove "." segments - if (!part || part === ".") continue; - // Interpret ".." to pop the last segment - if (part === "..") newParts.pop(); - // Push new path segments. - else newParts.push(part); - } - // Preserve the initial slash if there was one. - if (parts[0] === "") newParts.unshift(""); - // Turn back into a single string path. - return newParts.join("/"); - }, + // Credit: [@creationix/path.js](https://gist.github.com/creationix/7435851) + join(...partSegments: string[]): string { + // Split the inputs into a list of path commands. + let parts: string[] = []; + for (let i = 0, l = partSegments.length; i < l; i++) { + parts = parts.concat(partSegments[i].split("/")); + } + // Interpret the path commands to get the new resolved path. + const newParts = []; + for (let i = 0, l = parts.length; i < l; i++) { + const part = parts[i]; + // Remove leading and trailing slashes + // Also remove "." segments + if (!part || part === ".") continue; + // Interpret ".." to pop the last segment + if (part === "..") newParts.pop(); + // Push new path segments. + else newParts.push(part); + } + // Preserve the initial slash if there was one. + if (parts[0] === "") newParts.unshift(""); + // Turn back into a single string path. + return newParts.join("/"); + }, - // A simple function to get the dirname of a path - // Trailing slashes are ignored. Leading slash is preserved. - dirname(filepath: string): string { - return this.join(filepath, ".."); - }, + // A simple function to get the dirname of a path + // Trailing slashes are ignored. Leading slash is preserved. + dirname(filepath: string): string { + return this.join(filepath, ".."); + }, - // returns the last part of a path, e.g. 'foo.jpg' - basename(filepath: string, extension = ""): string { - const sp = filepath.split("/"); - const filename = sp[sp.length - 1]; - if (extension !== "") { - return filename.slice(0, filename.length - extension.length - 1); - } - return sp[sp.length - 1]; - }, + // returns the last part of a path, e.g. 'foo.jpg' + basename(filepath: string, extension = ""): string { + const sp = filepath.split("/"); + const filename = sp[sp.length - 1]; + if (extension !== "") { + return filename.slice(0, filename.length - extension.length - 1); + } + return sp[sp.length - 1]; + }, - // return extension without dot, e.g. 'jpg' - extname(filepath: string): string { - const positions = [...filepath.matchAll(new RegExp("\\.", "gi"))].map((a) => a.index); - const idx = positions[positions.length - 1]; - if (idx === undefined) { - return ""; - } - return filepath.slice(idx + 1); - }, + // return extension without dot, e.g. 'jpg' + extname(filepath: string): string { + const positions = [...filepath.matchAll(new RegExp("\\.", "gi"))].map((a) => a.index); + const idx = positions[positions.length - 1]; + if (idx === undefined) { + return ""; + } + return filepath.slice(idx + 1); + }, }; diff --git a/src/main.ts b/src/main.ts index 70cb6b5..c60f186 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,11 +1,11 @@ import { Notice, Plugin, TAbstractFile, TFile, TFolder } from "obsidian"; import { - AttachmentManagementPluginSettings, - AttachmentPathSettings, - DEFAULT_SETTINGS, - OriginalNameStorage, - SETTINGS_TYPES, - SettingTab, + AttachmentManagementPluginSettings, + AttachmentPathSettings, + DEFAULT_SETTINGS, + OriginalNameStorage, + SETTINGS_TYPES, + SettingTab, } from "./settings/settings"; import { debugLog } from "./lib/log"; import { OverrideModal } from "./model/override"; @@ -19,306 +19,300 @@ import { isExcluded } from "./exclude"; import { getMetadata } from "./settings/metadata"; export default class AttachmentManagementPlugin extends Plugin { - settings: AttachmentManagementPluginSettings; - createdQueue: TFile[] = []; - originalObsAttachPath: string; - - async onload() { - await this.loadSettings(); - - console.log(`Plugin loading: ${this.manifest.name} v.${this.manifest.version}`); - - this.app.workspace.onLayoutReady(() => { - - this.addCommand({ - id: "attachment-management-rearrange-all-links", - name: "Rearrange all linked attachments", - callback: async () => { - new ConfirmModal(this).open(); - }, - }); - - this.addCommand({ - id: "attachment-management-rearrange-active-links", - name: "Rearrange linked attachments", - callback: async () => { - new ArrangeHandler(this.settings, this.app, this).rearrangeAttachment("active").finally(() => { - new Notice("Arrange completed"); - }); - }, + settings: AttachmentManagementPluginSettings; + createdQueue: TFile[] = []; + originalObsAttachPath: string; + + async onload() { + await this.loadSettings(); + + console.log(`Plugin loading: ${this.manifest.name} v.${this.manifest.version}`); + + this.app.workspace.onLayoutReady(() => { + this.addCommand({ + id: "attachment-management-rearrange-all-links", + name: "Rearrange all linked attachments", + callback: async () => { + new ConfirmModal(this).open(); + }, + }); + + this.addCommand({ + id: "attachment-management-rearrange-active-links", + name: "Rearrange linked attachments", + callback: async () => { + new ArrangeHandler(this.settings, this.app, this).rearrangeAttachment("active").finally(() => { + new Notice("Arrange completed"); + }); + }, + }); + + this.addCommand({ + id: "override-setting", + name: "Overriding setting", + checkCallback: (checking: boolean) => { + const file = getActiveFile(this.app); + + if (file) { + if (isAttachment(this.settings, file)) { + new Notice(`${file.path} is an attachment, skipped`); + return true; + } + + if (!checking) { + if (file.parent && isExcluded(file.parent.path, this.settings)) { + new Notice(`${file.path} was excluded, skipped`); + return true; + } + const { setting } = getOverrideSetting(this.settings, file); + const fileSetting = Object.assign({}, setting); + this.overrideConfiguration(file, fileSetting); + } + return true; + } + return false; + }, + }); + + this.addCommand({ + id: "reset-override-setting", + name: "Reset override setting", + checkCallback: (checking: boolean) => { + const file = getActiveFile(this.app); + if (file) { + if (isAttachment(this.settings, file)) { + new Notice(`${file.path} is an attachment, skipped`); + return true; + } + + if (!checking) { + if (file.parent && isExcluded(file.parent.path, this.settings)) { + new Notice(`${file.path} was excluded, skipped`); + return true; + } + delete this.settings.overridePath[file.path]; + this.saveSettings(); + this.loadSettings(); + new Notice(`Reset attachment setting of ${file.path}`); + } + return true; + } + return false; + }, + }); + + this.addCommand({ + id: "attachment-management-clear-unused-originalname-storage", + name: "Clear unused original name storage", + callback: async () => { + const attachments = await new ArrangeHandler(this.settings, this.app, this).getAttachmentsInVault( + this.settings, + "links" + ); + const storages: OriginalNameStorage[] = []; + for (const attachs of Object.values(attachments)) { + for (const attach of attachs) { + const link = decodeURI(attach); + const linkFile = this.app.vault.getAbstractFileByPath(link); + if (linkFile !== null && linkFile instanceof TFile) { + const md5 = await MD5(this.app.vault.adapter, linkFile); + const ret = this.settings.originalNameStorage.find((data) => data.md5 === md5); + if (ret) { + storages.filter((n) => n.md5 == md5).forEach((n) => storages.remove(n)); + storages.push(ret); + } + } + } + } + debugLog("clearUnusedOriginalNameStorage - storage:", storages); + this.settings.originalNameStorage = storages; + await this.saveSettings(); + this.loadSettings(); + }, + }); + + this.registerEvent( + this.app.workspace.on("file-menu", async (menu, file) => { + if ((file.parent && isExcluded(file.parent.path, this.settings)) || isAttachment(this.settings, file)) { + return; + } + menu.addItem((item) => { + item + .setTitle("Overriding attachment setting") + .setIcon("image-plus") + .onClick(async () => { + const { setting } = getOverrideSetting(this.settings, file); + const fileSetting = Object.assign({}, setting); + await this.overrideConfiguration(file, fileSetting); + }); + }); + }) + ); + + this.registerEvent( + this.app.vault.on("create", async (file: TAbstractFile) => { + debugLog("on create event - file:", file.path); + // only processing creatation of file, ignore folder creation + if (!(file instanceof TFile)) { + return; + } + + // if the file is modified/create more than 1 second ago, the event is most likely be fired by copy file to + // vault folder without using obsidian or sync file from remote (e.g. file manager of op system), we should ignore it. + const curentTime = new Date().getTime(); + const timeGapMs = curentTime - file.stat.mtime; + const timeGapCs = curentTime - file.stat.ctime; + // ignore markdown and canvas file. + if (timeGapMs > 1000 || timeGapCs > 1000 || isMarkdownFile(file.extension) || isCanvasFile(file.extension)) { + return; + } + + if (matchExtension(file.extension, this.settings.excludeExtensionPattern)) { + debugLog("create - excluded file by extension", file); + return; + } + + this.createdQueue.push(file); + }) + ); + + this.registerEvent( + this.app.vault.on("modify", (file: TAbstractFile) => { + debugLog("on modify event - create queue:", this.createdQueue); + if (this.createdQueue.length < 1 || !(file instanceof TFile)) { + return; + } + + debugLog("on modify event - file:", file.path); + this.app.vault.adapter.process(file.path, (data) => { + // debugLog("on modify event - file content:", data); + // processing one file at one event loop, other files will be processed in the next event loop + const f = this.createdQueue.first(); + if (f != undefined) { + this.app.vault.adapter.exists(f.path, true).then((exist) => { + if (exist) { + const processor = new CreateHandler(this, this.settings); + const link = this.app.fileManager.generateMarkdownLink(f, file.path); + if ( + (file.extension == "md" && data.indexOf(link) != -1) || + (file.extension == "canvas" && data.indexOf(f.path) != -1) + ) { + this.createdQueue.remove(f); + processor.processAttach(f, file); + } + } else { + // remove not exists file + debugLog("on modify event - file does not exist:", f.path); + this.createdQueue.remove(f); + } + }); + } + return data; + }); + }) + ); + + this.registerEvent( + // when trigger a rename event on folder, for each file/folder in this renamed folder (include itself) will trigger this event + this.app.vault.on("rename", async (file: TAbstractFile, oldPath: string) => { + debugLog("on rename event - new path and old path:", file.path, oldPath); + + const { setting } = getRenameOverrideSetting(this.settings, file, oldPath); + // update the override setting + debugLog("rename - using settings:", setting); + if (setting.type === SETTINGS_TYPES.FOLDER || setting.type === SETTINGS_TYPES.FILE) { + updateOverrideSetting(this.settings, file, oldPath); + await this.saveSettings(); + await this.loadSettings(); + } + debugLog("rename - updated settings:", setting); + + if (!this.settings.autoRenameAttachment) { + debugLog("rename - auto rename not enabled:", this.settings.autoRenameAttachment); + return; + } + + if (file instanceof TFile) { + if (file.parent && isExcluded(file.parent.path, this.settings)) { + debugLog("rename - exclude path:", file.parent.path); + new Notice(`${file.path} was excluded, skipped`); + return; + } + + // ignore attachment + if (isAttachment(this.settings, file)) { + debugLog("rename - not processing rename on attachment:", file.path); + return; + } + + await new ArrangeHandler(this.settings, this.app, this).rearrangeAttachment("file", file, oldPath); + await this.saveSettings(); + + const oldMetadata = getMetadata(oldPath); + // if the user have used the ${date} in `Attachment path` this could be not working, since the date will be change. + const oldAttachPath = oldMetadata.getAttachmentPath(setting, this.settings.dateFormat); + this.app.vault.adapter.exists(oldAttachPath, true).then((exists) => { + if (exists) { + checkEmptyFolder(this.app.vault.adapter, oldAttachPath).then((empty) => { + if (empty) { + this.app.vault.adapter.rmdir(oldAttachPath, true); + } + }); + } }); - - this.addCommand({ - id: "override-setting", - name: "Overriding setting", - checkCallback: (checking: boolean) => { - const file = getActiveFile(this.app); - - if (file) { - if (isAttachment(this.settings, file)) { - new Notice(`${file.path} is an attachment, skipped`); - return true; - } - - if (!checking) { - if (file.parent && isExcluded(file.parent.path, this.settings)) { - new Notice(`${file.path} was excluded, skipped`); - return true; - } - const { setting } = getOverrideSetting(this.settings, file); - const fileSetting = Object.assign({}, setting); - this.overrideConfiguration(file, fileSetting); - } - return true; - } - return false; - }, - }); - - this.addCommand({ - id: "reset-override-setting", - name: "Reset override setting", - checkCallback: (checking: boolean) => { - const file = getActiveFile(this.app); - if (file) { - if (isAttachment(this.settings, file)) { - new Notice(`${file.path} is an attachment, skipped`); - return true; - } - - if (!checking) { - if (file.parent && isExcluded(file.parent.path, this.settings)) { - new Notice(`${file.path} was excluded, skipped`); - return true; - } - delete this.settings.overridePath[file.path]; - this.saveSettings(); - this.loadSettings(); - new Notice(`Reset attachment setting of ${file.path}`); - } - return true; - } - return false; - }, + } else if (file instanceof TFolder) { + // ignore rename event of folder + return; + } + }) + ); + + this.registerEvent( + this.app.vault.on("delete", async (file: TAbstractFile) => { + debugLog("on delete event - file path:", file.path); + + if ((file.parent && isExcluded(file.parent.path, this.settings)) || isAttachment(this.settings, file)) { + debugLog("delete - exclude path or the file is an attachment:", file.path); + return; + } + + if (deleteOverrideSetting(this.settings, file)) { + await this.saveSettings(); + new Notice("Removed override setting of " + file.path); + } + + if (file instanceof TFile) { + const oldMetadata = getMetadata(file.path); + const { setting } = getOverrideSetting(this.settings, file); + const oldAttachPath = oldMetadata.getAttachmentPath(setting, this.settings.dateFormat); + this.app.vault.adapter.exists(oldAttachPath, true).then((exists) => { + if (exists) { + checkEmptyFolder(this.app.vault.adapter, oldAttachPath).then((empty) => { + if (empty) { + this.app.vault.adapter.rmdir(oldAttachPath, true); + } + }); + } }); - - this.addCommand({ - id: "attachment-management-clear-unused-originalname-storage", - name: "Clear unused original name storage", - callback: async () => { - const attachments = await new ArrangeHandler(this.settings, this.app, this).getAttachmentsInVault( - this.settings, - "links" - ); - const storages: OriginalNameStorage[] = []; - for (const attachs of Object.values(attachments)) { - for (const attach of attachs) { - const link = decodeURI(attach); - const linkFile = this.app.vault.getAbstractFileByPath(link); - if (linkFile !== null && linkFile instanceof TFile) { - const md5 = await MD5(this.app.vault.adapter, linkFile); - const ret = this.settings.originalNameStorage.find((data) => data.md5 === md5); - if (ret) { - storages.filter((n) => n.md5 == md5).forEach((n) => storages.remove(n)); - storages.push(ret); - } - } - } - } - debugLog("clearUnusedOriginalNameStorage - storage:", storages); - this.settings.originalNameStorage = storages; - await this.saveSettings(); - this.loadSettings(); - }, - }); - - this.registerEvent( - this.app.workspace.on("file-menu", async (menu, file) => { - if ((file.parent && isExcluded(file.parent.path, this.settings)) || isAttachment(this.settings, file)) { - return; - } - menu.addItem((item) => { - item.setTitle("Overriding attachment setting") - .setIcon("image-plus") - .onClick(async () => { - const { setting } = getOverrideSetting(this.settings, file); - const fileSetting = Object.assign({}, setting); - await this.overrideConfiguration(file, fileSetting); - }); - }); - }) - ); - - this.registerEvent( - this.app.vault.on("create", async (file: TAbstractFile) => { - debugLog("on create event - file:", file.path); - // only processing creatation of file, ignore folder creation - if (!(file instanceof TFile)) { - return; - } - - // if the file is modified/create more than 1 second ago, the event is most likely be fired by copy file to - // vault folder without using obsidian or sync file from remote (e.g. file manager of op system), we should ignore it. - const curentTime = new Date().getTime(); - const timeGapMs = curentTime - file.stat.mtime; - const timeGapCs = curentTime - file.stat.ctime; - // ignore markdown and canvas file. - if ( - timeGapMs > 1000 || - timeGapCs > 1000 || - isMarkdownFile(file.extension) || - isCanvasFile(file.extension) - ) { - return; - } - - if (matchExtension(file.extension, this.settings.excludeExtensionPattern)) { - debugLog("create - excluded file by extension", file); - return; - } - - this.createdQueue.push(file); - }) - ); - - this.registerEvent( - this.app.vault.on("modify", (file: TAbstractFile) => { - debugLog("on modify event - create queue:", this.createdQueue); - if (this.createdQueue.length < 1 || !(file instanceof TFile)) { - return; - } - - debugLog("on modify event - file:", file.path); - this.app.vault.adapter.process(file.path, (data) => { - // debugLog("on modify event - file content:", data); - // processing one file at one event loop, other files will be processed in the next event loop - const f = this.createdQueue.first(); - if (f != undefined) { - this.app.vault.adapter.exists(f.path, true).then((exist) => { - if (exist) { - const processor = new CreateHandler(this, this.settings); - const link = this.app.fileManager.generateMarkdownLink(f, file.path); - if ( - (file.extension == "md" && data.indexOf(link) != -1) || - (file.extension == "canvas" && data.indexOf(f.path) != -1) - ) { - this.createdQueue.remove(f); - processor.processAttach(f, file); - } - } else { - // remove not exists file - debugLog("on modify event - file does not exist:", f.path); - this.createdQueue.remove(f); - } - }); - } - return data; - }); - }) - ); - - this.registerEvent( - // when trigger a rename event on folder, for each file/folder in this renamed folder (include itself) will trigger this event - this.app.vault.on("rename", async (file: TAbstractFile, oldPath: string) => { - debugLog("on rename event - new path and old path:", file.path, oldPath); - - const { setting } = getRenameOverrideSetting(this.settings, file, oldPath); - // update the override setting - debugLog("rename - using settings:", setting); - if (setting.type === SETTINGS_TYPES.FOLDER || setting.type === SETTINGS_TYPES.FILE) { - updateOverrideSetting(this.settings, file, oldPath); - await this.saveSettings(); - await this.loadSettings(); - } - debugLog("rename - updated settings:", setting); - - if (!this.settings.autoRenameAttachment) { - debugLog("rename - auto rename not enabled:", this.settings.autoRenameAttachment); - return; - } - - if (file instanceof TFile) { - if (file.parent && isExcluded(file.parent.path, this.settings)) { - debugLog("rename - exclude path:", file.parent.path); - new Notice(`${file.path} was excluded, skipped`); - return; - } - - // ignore attachment - if (isAttachment(this.settings, file)) { - debugLog("rename - not processing rename on attachment:", file.path); - return; - } - - await new ArrangeHandler(this.settings, this.app, this).rearrangeAttachment("file", file, oldPath); - await this.saveSettings(); - - const oldMetadata = getMetadata(oldPath); - // if the user have used the ${date} in `Attachment path` this could be not working, since the date will be change. - const oldAttachPath = oldMetadata.getAttachmentPath(setting, this.settings.dateFormat); - this.app.vault.adapter.exists(oldAttachPath).then((exists) => { - if (exists) { - checkEmptyFolder(this.app.vault.adapter, oldAttachPath).then((empty) => { - if (empty) { - this.app.vault.adapter.rmdir(oldAttachPath, true); - } - }); - } - }); - } else if (file instanceof TFolder) { - // ignore rename event of folder - return; - } - }) - ); - - this.registerEvent( - this.app.vault.on("delete", async (file: TAbstractFile) => { - debugLog("on delete event - file path:", file.path); - - if ((file.parent && isExcluded(file.parent.path, this.settings)) || isAttachment(this.settings, file)) { - debugLog("delete - exclude path or the file is an attachment:", file.path); - return; - } - - if (deleteOverrideSetting(this.settings, file)) { - await this.saveSettings(); - new Notice("Removed override setting of " + file.path); - } - - if (file instanceof TFile) { - const oldMetadata = getMetadata(file.path); - const { setting } = getOverrideSetting(this.settings, file); - const oldAttachPath = oldMetadata.getAttachmentPath(setting, this.settings.dateFormat); - this.app.vault.adapter.exists(oldAttachPath, true).then((exists) => { - if (exists) { - checkEmptyFolder(this.app.vault.adapter, oldAttachPath).then((empty) => { - if (empty) { - this.app.vault.adapter.rmdir(oldAttachPath, true); - } - }); - } - }); - } - }) - ); - - // This adds a settings tab so the user can configure various aspects of the plugin - this.addSettingTab(new SettingTab(this.app, this)); - }); - - } - - async overrideConfiguration(file: TAbstractFile, setting: AttachmentPathSettings) { - new OverrideModal(this, file, setting).open(); - await this.loadSettings(); - } - - async loadSettings() { - this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); - } - - async saveSettings() { - await this.saveData(this.settings); - } + } + }) + ); + + // This adds a settings tab so the user can configure various aspects of the plugin + this.addSettingTab(new SettingTab(this.app, this)); + }); + } + + async overrideConfiguration(file: TAbstractFile, setting: AttachmentPathSettings) { + new OverrideModal(this, file, setting).open(); + await this.loadSettings(); + } + + async loadSettings() { + this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + } + + async saveSettings() { + await this.saveData(this.settings); + } } diff --git a/src/model/confirm.ts b/src/model/confirm.ts index 4ce076e..fecca8a 100644 --- a/src/model/confirm.ts +++ b/src/model/confirm.ts @@ -3,46 +3,47 @@ import AttachmentManagementPlugin from "../main"; import { ArrangeHandler } from "src/arrange"; export class ConfirmModal extends Modal { - plugin: AttachmentManagementPlugin; + plugin: AttachmentManagementPlugin; - constructor(plugin: AttachmentManagementPlugin) { - super(plugin.app); - this.plugin = plugin; - } + constructor(plugin: AttachmentManagementPlugin) { + super(plugin.app); + this.plugin = plugin; + } - onOpen() { - const { contentEl } = this; - contentEl.empty(); + onOpen() { + const { contentEl } = this; + contentEl.empty(); - contentEl.createEl("h3", { - text: "Tips", - }); - contentEl.createSpan("", (el) => { - el.innerText = "This operation is irreversible and experimental. Please backup your vault first!"; - }); + contentEl.createEl("h3", { + text: "Tips", + }); + contentEl.createSpan("", (el) => { + el.innerText = "This operation is irreversible and experimental. Please backup your vault first!"; + }); - new Setting(contentEl) - .addButton((btn) => { - btn.setButtonText("Cancel") - .setCta() - .onClick(() => { - this.close(); - }); - }) - .addButton((btn) => - btn.setButtonText("Continue").onClick(async () => { - new ArrangeHandler(this.plugin.settings, this.plugin.app, this.plugin) - .rearrangeAttachment("links") - .finally(() => { - new Notice("Arrange completed"); - this.close(); - }); - }) - ); - } + new Setting(contentEl) + .addButton((btn) => { + btn + .setButtonText("Cancel") + .setCta() + .onClick(() => { + this.close(); + }); + }) + .addButton((btn) => + btn.setButtonText("Continue").onClick(async () => { + new ArrangeHandler(this.plugin.settings, this.plugin.app, this.plugin) + .rearrangeAttachment("links") + .finally(() => { + new Notice("Arrange completed"); + this.close(); + }); + }) + ); + } - onClose() { - const { contentEl } = this; - contentEl.empty(); - } + onClose() { + const { contentEl } = this; + contentEl.empty(); + } } diff --git a/src/model/extensionOverride.ts b/src/model/extensionOverride.ts index 5eb6a58..f7548a5 100644 --- a/src/model/extensionOverride.ts +++ b/src/model/extensionOverride.ts @@ -1,15 +1,15 @@ import { Modal, Setting } from "obsidian"; import { - SETTINGS_ROOT_INFOLDER, - SETTINGS_ROOT_NEXTTONOTE, - SETTINGS_ROOT_OBSFOLDER, - SETTINGS_VARIABLES_DATES, - SETTINGS_VARIABLES_MD5, - SETTINGS_VARIABLES_NOTENAME, - SETTINGS_VARIABLES_NOTEPARENT, - SETTINGS_VARIABLES_NOTEPATH, - SETTINGS_VARIABLES_ORIGINALNAME, + SETTINGS_ROOT_INFOLDER, + SETTINGS_ROOT_NEXTTONOTE, + SETTINGS_ROOT_OBSFOLDER, + SETTINGS_VARIABLES_DATES, + SETTINGS_VARIABLES_MD5, + SETTINGS_VARIABLES_NOTENAME, + SETTINGS_VARIABLES_NOTEPARENT, + SETTINGS_VARIABLES_NOTEPATH, + SETTINGS_VARIABLES_ORIGINALNAME, } from "../lib/constant"; import AttachmentManagementPlugin from "../main"; import { AttachmentPathSettings, DEFAULT_SETTINGS, ExtensionOverrideSettings } from "../settings/settings"; @@ -24,129 +24,129 @@ import { debugLog } from "src/lib/log"; * @return {{ extSetting: ExtensionOverrideSettings | undefined }} - The override setting for the extension. */ export function getExtensionOverrideSetting( - extension: string, - settings: AttachmentPathSettings + extension: string, + settings: AttachmentPathSettings ): { extSetting: ExtensionOverrideSettings | undefined } { - if (settings.extensionOverride === undefined || settings.extensionOverride.length === 0) { - return { extSetting: undefined }; - } + if (settings.extensionOverride === undefined || settings.extensionOverride.length === 0) { + return { extSetting: undefined }; + } - for (let i = 0; i < settings.extensionOverride.length; i++) { - if (matchExtension(extension, settings.extensionOverride[i].extension)) { - debugLog( - "getExtensionOverrideSetting - ", - settings.extensionOverride[i].extension, - settings.extensionOverride[i] - ); - return { extSetting: settings.extensionOverride[i] }; - } + for (let i = 0; i < settings.extensionOverride.length; i++) { + if (matchExtension(extension, settings.extensionOverride[i].extension)) { + debugLog( + "getExtensionOverrideSetting - ", + settings.extensionOverride[i].extension, + settings.extensionOverride[i] + ); + return { extSetting: settings.extensionOverride[i] }; } + } - return { extSetting: undefined }; + return { extSetting: undefined }; } export class OverrideExtensionModal extends Modal { - plugin: AttachmentManagementPlugin; - settings: ExtensionOverrideSettings; - onSubmit: (result: ExtensionOverrideSettings) => void; + plugin: AttachmentManagementPlugin; + settings: ExtensionOverrideSettings; + onSubmit: (result: ExtensionOverrideSettings) => void; - constructor( - plugin: AttachmentManagementPlugin, - settings: ExtensionOverrideSettings, - onSubmit: (result: ExtensionOverrideSettings) => void - ) { - super(plugin.app); - this.plugin = plugin; - this.settings = settings; - this.onSubmit = onSubmit; - } - - displaySw(cont: HTMLElement): void { - cont.findAll(".setting-item").forEach((el: HTMLElement) => { - if (el.getAttr("class")?.includes("override_root_folder_set")) { - if (this.settings.saveAttE === "obsFolder") { - el.hide(); - } else { - el.show(); - } - } - }); - } + constructor( + plugin: AttachmentManagementPlugin, + settings: ExtensionOverrideSettings, + onSubmit: (result: ExtensionOverrideSettings) => void + ) { + super(plugin.app); + this.plugin = plugin; + this.settings = settings; + this.onSubmit = onSubmit; + } - onOpen(): void { - const { contentEl } = this; - contentEl.empty(); - - contentEl.createEl("h3", { - text: `Extension settings for ${this.settings.extension}`, - }); - - new Setting(contentEl) - .setName("Root path to save attachment") - .setDesc("Select root path of attachment") - .addDropdown((text) => - text - .addOption(`${SETTINGS_ROOT_OBSFOLDER}`, "Copy Obsidian settings") - .addOption(`${SETTINGS_ROOT_INFOLDER}`, "In the folder specified below") - .addOption(`${SETTINGS_ROOT_NEXTTONOTE}`, "Next to note in folder specified below") - .setValue(this.settings.saveAttE) - .onChange(async (value) => { - this.settings.saveAttE = value; - this.displaySw(contentEl); - this.onOpen(); - }) - ); - if (this.settings.saveAttE !== "obsFolder") { - new Setting(contentEl) - .setName("Root folder") - .setClass("override_root_folder_set") - .addText((text) => - text - .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachmentRoot) - .setValue(this.settings.attachmentRoot) - .onChange(async (value) => { - this.settings.attachmentRoot = value; - }) - ); + displaySw(cont: HTMLElement): void { + cont.findAll(".setting-item").forEach((el: HTMLElement) => { + if (el.getAttr("class")?.includes("override_root_folder_set")) { + if (this.settings.saveAttE === "obsFolder") { + el.hide(); + } else { + el.show(); } - new Setting(contentEl) - .setName("Attachment path") - .setDesc( - `Path of attachment in root folder, available variables ${SETTINGS_VARIABLES_NOTEPATH}, ${SETTINGS_VARIABLES_NOTENAME} and ${SETTINGS_VARIABLES_NOTEPARENT}` - ) - .addText((text) => - text - .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachmentPath) - .setValue(this.settings.attachmentPath) - .onChange(async (value) => { - this.settings.attachmentPath = value; - }) - ); + } + }); + } + + onOpen(): void { + const { contentEl } = this; + contentEl.empty(); - new Setting(contentEl) - .setName("Attachment format") - .setDesc( - `Define how to name the attachment file, available variables ${SETTINGS_VARIABLES_DATES}, ${SETTINGS_VARIABLES_NOTENAME}, ${SETTINGS_VARIABLES_MD5} and ${SETTINGS_VARIABLES_ORIGINALNAME}.` - ) - .addText((text) => - text - .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachFormat) - .setValue(this.settings.attachFormat) - .onChange(async (value: string) => { - this.settings.attachFormat = value; - }) - ); + contentEl.createEl("h3", { + text: `Extension settings for ${this.settings.extension}`, + }); - new Setting(contentEl).addButton((button) => - button.setButtonText("Save").onClick(async () => { - this.onSubmit(this.settings); - this.close(); + new Setting(contentEl) + .setName("Root path to save attachment") + .setDesc("Select root path of attachment") + .addDropdown((text) => + text + .addOption(`${SETTINGS_ROOT_OBSFOLDER}`, "Copy Obsidian settings") + .addOption(`${SETTINGS_ROOT_INFOLDER}`, "In the folder specified below") + .addOption(`${SETTINGS_ROOT_NEXTTONOTE}`, "Next to note in folder specified below") + .setValue(this.settings.saveAttE) + .onChange(async (value) => { + this.settings.saveAttE = value; + this.displaySw(contentEl); + this.onOpen(); + }) + ); + if (this.settings.saveAttE !== "obsFolder") { + new Setting(contentEl) + .setName("Root folder") + .setClass("override_root_folder_set") + .addText((text) => + text + .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachmentRoot) + .setValue(this.settings.attachmentRoot) + .onChange(async (value) => { + this.settings.attachmentRoot = value; }) ); } + new Setting(contentEl) + .setName("Attachment path") + .setDesc( + `Path of attachment in root folder, available variables ${SETTINGS_VARIABLES_NOTEPATH}, ${SETTINGS_VARIABLES_NOTENAME} and ${SETTINGS_VARIABLES_NOTEPARENT}` + ) + .addText((text) => + text + .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachmentPath) + .setValue(this.settings.attachmentPath) + .onChange(async (value) => { + this.settings.attachmentPath = value; + }) + ); - onClose(): void { - const { contentEl } = this; - contentEl.empty(); - } + new Setting(contentEl) + .setName("Attachment format") + .setDesc( + `Define how to name the attachment file, available variables ${SETTINGS_VARIABLES_DATES}, ${SETTINGS_VARIABLES_NOTENAME}, ${SETTINGS_VARIABLES_MD5} and ${SETTINGS_VARIABLES_ORIGINALNAME}.` + ) + .addText((text) => + text + .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachFormat) + .setValue(this.settings.attachFormat) + .onChange(async (value: string) => { + this.settings.attachFormat = value; + }) + ); + + new Setting(contentEl).addButton((button) => + button.setButtonText("Save").onClick(async () => { + this.onSubmit(this.settings); + this.close(); + }) + ); + } + + onClose(): void { + const { contentEl } = this; + contentEl.empty(); + } } diff --git a/src/model/override.ts b/src/model/override.ts index fed8720..12bf438 100644 --- a/src/model/override.ts +++ b/src/model/override.ts @@ -1,193 +1,193 @@ import { Modal, TFile, TAbstractFile, Setting, TFolder, Notice } from "obsidian"; import { AttachmentPathSettings, DEFAULT_SETTINGS, SETTINGS_TYPES } from "../settings/settings"; import { - SETTINGS_ROOT_OBSFOLDER, - SETTINGS_ROOT_INFOLDER, - SETTINGS_ROOT_NEXTTONOTE, - SETTINGS_VARIABLES_NOTEPATH, - SETTINGS_VARIABLES_NOTENAME, - SETTINGS_VARIABLES_DATES, - SETTINGS_VARIABLES_NOTEPARENT, - SETTINGS_VARIABLES_ORIGINALNAME, - SETTINGS_VARIABLES_MD5, + SETTINGS_ROOT_OBSFOLDER, + SETTINGS_ROOT_INFOLDER, + SETTINGS_ROOT_NEXTTONOTE, + SETTINGS_VARIABLES_NOTEPATH, + SETTINGS_VARIABLES_NOTENAME, + SETTINGS_VARIABLES_DATES, + SETTINGS_VARIABLES_NOTEPARENT, + SETTINGS_VARIABLES_ORIGINALNAME, + SETTINGS_VARIABLES_MD5, } from "../lib/constant"; import AttachmentManagementPlugin from "../main"; import { OverrideExtensionModal } from "./extensionOverride"; import { debugLog } from "src/lib/log"; export class OverrideModal extends Modal { - plugin: AttachmentManagementPlugin; - file: TAbstractFile; - setting: AttachmentPathSettings; + plugin: AttachmentManagementPlugin; + file: TAbstractFile; + setting: AttachmentPathSettings; - constructor(plugin: AttachmentManagementPlugin, file: TAbstractFile, setting: AttachmentPathSettings) { - super(plugin.app); - this.plugin = plugin; - this.file = file; - this.setting = setting; - } + constructor(plugin: AttachmentManagementPlugin, file: TAbstractFile, setting: AttachmentPathSettings) { + super(plugin.app); + this.plugin = plugin; + this.file = file; + this.setting = setting; + } - displaySw(cont: HTMLElement): void { - cont.findAll(".setting-item").forEach((el: HTMLElement) => { - if (el.getAttr("class")?.includes("override_root_folder_set")) { - if (this.setting.saveAttE === "obsFolder") { - el.hide(); - } else { - el.show(); - } - } - }); - } + displaySw(cont: HTMLElement): void { + cont.findAll(".setting-item").forEach((el: HTMLElement) => { + if (el.getAttr("class")?.includes("override_root_folder_set")) { + if (this.setting.saveAttE === "obsFolder") { + el.hide(); + } else { + el.show(); + } + } + }); + } - onOpen() { - const { contentEl } = this; - contentEl.empty(); + onOpen() { + const { contentEl } = this; + contentEl.empty(); - contentEl.createEl("h3", { - text: "Overriding Settings", - }); + contentEl.createEl("h3", { + text: "Overriding Settings", + }); - new Setting(contentEl) - .setName("Root path to save attachment") - .setDesc("Select root path of attachment") - .addDropdown((text) => - text - .addOption(`${SETTINGS_ROOT_OBSFOLDER}`, "Copy Obsidian settings") - .addOption(`${SETTINGS_ROOT_INFOLDER}`, "In the folder specified below") - .addOption(`${SETTINGS_ROOT_NEXTTONOTE}`, "Next to note in folder specified below") - .setValue(this.setting.saveAttE) - .onChange(async (value) => { - this.setting.saveAttE = value; - this.displaySw(contentEl); - }) - ); + new Setting(contentEl) + .setName("Root path to save attachment") + .setDesc("Select root path of attachment") + .addDropdown((text) => + text + .addOption(`${SETTINGS_ROOT_OBSFOLDER}`, "Copy Obsidian settings") + .addOption(`${SETTINGS_ROOT_INFOLDER}`, "In the folder specified below") + .addOption(`${SETTINGS_ROOT_NEXTTONOTE}`, "Next to note in folder specified below") + .setValue(this.setting.saveAttE) + .onChange(async (value) => { + this.setting.saveAttE = value; + this.displaySw(contentEl); + }) + ); - new Setting(contentEl) - .setName("Root folder") - .setClass("override_root_folder_set") - .addText((text) => - text - .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachmentRoot) - .setValue(this.setting.attachmentRoot) - .onChange(async (value) => { - debugLog("override - attachment root:" + value); - this.setting.attachmentRoot = value; - }) - ); + new Setting(contentEl) + .setName("Root folder") + .setClass("override_root_folder_set") + .addText((text) => + text + .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachmentRoot) + .setValue(this.setting.attachmentRoot) + .onChange(async (value) => { + debugLog("override - attachment root:" + value); + this.setting.attachmentRoot = value; + }) + ); - new Setting(contentEl) - .setName("Attachment path") - .setDesc( - `Path of attachment in root folder, available variables ${SETTINGS_VARIABLES_NOTEPATH}, ${SETTINGS_VARIABLES_NOTENAME} and ${SETTINGS_VARIABLES_NOTEPARENT}` - ) - .addText((text) => - text - .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachmentPath) - .setValue(this.setting.attachmentPath) - .onChange(async (value) => { - debugLog("override - attachment path:" + value); - this.setting.attachmentPath = value; - }) - ); + new Setting(contentEl) + .setName("Attachment path") + .setDesc( + `Path of attachment in root folder, available variables ${SETTINGS_VARIABLES_NOTEPATH}, ${SETTINGS_VARIABLES_NOTENAME} and ${SETTINGS_VARIABLES_NOTEPARENT}` + ) + .addText((text) => + text + .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachmentPath) + .setValue(this.setting.attachmentPath) + .onChange(async (value) => { + debugLog("override - attachment path:" + value); + this.setting.attachmentPath = value; + }) + ); - new Setting(contentEl) - .setName("Attachment format") - .setDesc( - `Define how to name the attachment file, available variables ${SETTINGS_VARIABLES_DATES}, ${SETTINGS_VARIABLES_NOTENAME}, ${SETTINGS_VARIABLES_MD5} and ${SETTINGS_VARIABLES_ORIGINALNAME}.` - ) - .addText((text) => - text - .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachFormat) - .setValue(this.setting.attachFormat) - .onChange(async (value: string) => { - debugLog("override - attachment format:" + value); - this.setting.attachFormat = value; - }) - ); + new Setting(contentEl) + .setName("Attachment format") + .setDesc( + `Define how to name the attachment file, available variables ${SETTINGS_VARIABLES_DATES}, ${SETTINGS_VARIABLES_NOTENAME}, ${SETTINGS_VARIABLES_MD5} and ${SETTINGS_VARIABLES_ORIGINALNAME}.` + ) + .addText((text) => + text + .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachFormat) + .setValue(this.setting.attachFormat) + .onChange(async (value: string) => { + debugLog("override - attachment format:" + value); + this.setting.attachFormat = value; + }) + ); - new Setting(contentEl).addButton((btn) => { - btn.setButtonText("Add extension overrides").onClick(async () => { - if (this.setting.extensionOverride === undefined) { - this.setting.extensionOverride = []; - } - this.setting.extensionOverride.push({ - extension: "", - saveAttE: this.setting.saveAttE, - attachmentRoot: this.setting.attachmentRoot, - attachmentPath: this.setting.attachmentPath, - attachFormat: this.setting.attachFormat, - }); - this.onOpen(); - }); + new Setting(contentEl).addButton((btn) => { + btn.setButtonText("Add extension overrides").onClick(async () => { + if (this.setting.extensionOverride === undefined) { + this.setting.extensionOverride = []; + } + this.setting.extensionOverride.push({ + extension: "", + saveAttE: this.setting.saveAttE, + attachmentRoot: this.setting.attachmentRoot, + attachmentPath: this.setting.attachmentPath, + attachFormat: this.setting.attachFormat, }); + this.onOpen(); + }); + }); - if (this.setting.extensionOverride !== undefined) { - this.setting.extensionOverride.forEach((ext) => { - new Setting(contentEl) - .setName("Extension") - .setDesc("Extension to override") - .setClass("override_extension_set") - .addText((text) => - text - .setPlaceholder("pdf") - .setValue(ext.extension) - .onChange(async (value) => { - ext.extension = value; - }) - ) - .addButton((btn) => { - btn.setIcon("trash").onClick(async () => { - //get index of extension - const index = this.setting.extensionOverride?.indexOf(ext) ?? -1; - //remove extension from array - this.setting.extensionOverride?.splice(index, 1); - this.onOpen(); - }); - }) - .addButton((btn) => { - btn.setIcon("pencil").onClick(async () => { - new OverrideExtensionModal(this.plugin, ext, (result) => { - ext = result; - }).open(); - }); - }); + if (this.setting.extensionOverride !== undefined) { + this.setting.extensionOverride.forEach((ext) => { + new Setting(contentEl) + .setName("Extension") + .setDesc("Extension to override") + .setClass("override_extension_set") + .addText((text) => + text + .setPlaceholder("pdf") + .setValue(ext.extension) + .onChange(async (value) => { + ext.extension = value; + }) + ) + .addButton((btn) => { + btn.setIcon("trash").onClick(async () => { + //get index of extension + const index = this.setting.extensionOverride?.indexOf(ext) ?? -1; + //remove extension from array + this.setting.extensionOverride?.splice(index, 1); + this.onOpen(); }); - } + }) + .addButton((btn) => { + btn.setIcon("pencil").onClick(async () => { + new OverrideExtensionModal(this.plugin, ext, (result) => { + ext = result; + }).open(); + }); + }); + }); + } - new Setting(contentEl) - .addButton((btn) => { - btn.setButtonText("Reset").onClick(async () => { - this.setting = this.plugin.settings.attachPath; - delete this.plugin.settings.overridePath[this.file.path]; - await this.plugin.saveSettings(); - await this.plugin.loadSettings(); - new Notice(`Reset attachment setting of ${this.file.path}`); - this.close(); - }); - }) - .addButton((btn) => - btn - .setButtonText("Submit") - .setCta() - .onClick(async () => { - if (this.file instanceof TFile) { - this.setting.type = SETTINGS_TYPES.FILE; - } else if (this.file instanceof TFolder) { - this.setting.type = SETTINGS_TYPES.FOLDER; - } - this.plugin.settings.overridePath[this.file.path] = this.setting; - await this.plugin.saveSettings(); - debugLog("override - overriding settings:", this.file.path, this.setting); - new Notice(`Overridden attachment setting of ${this.file.path}`); - this.close(); - }) - ); + new Setting(contentEl) + .addButton((btn) => { + btn.setButtonText("Reset").onClick(async () => { + this.setting = this.plugin.settings.attachPath; + delete this.plugin.settings.overridePath[this.file.path]; + await this.plugin.saveSettings(); + await this.plugin.loadSettings(); + new Notice(`Reset attachment setting of ${this.file.path}`); + this.close(); + }); + }) + .addButton((btn) => + btn + .setButtonText("Submit") + .setCta() + .onClick(async () => { + if (this.file instanceof TFile) { + this.setting.type = SETTINGS_TYPES.FILE; + } else if (this.file instanceof TFolder) { + this.setting.type = SETTINGS_TYPES.FOLDER; + } + this.plugin.settings.overridePath[this.file.path] = this.setting; + await this.plugin.saveSettings(); + debugLog("override - overriding settings:", this.file.path, this.setting); + new Notice(`Overridden attachment setting of ${this.file.path}`); + this.close(); + }) + ); - this.displaySw(contentEl); - } + this.displaySw(contentEl); + } - onClose() { - const { contentEl } = this; - contentEl.empty(); - } + onClose() { + const { contentEl } = this; + contentEl.empty(); + } } diff --git a/src/override.ts b/src/override.ts index 0c5e958..211007d 100644 --- a/src/override.ts +++ b/src/override.ts @@ -13,72 +13,72 @@ import { stripPaths } from "./utils"; * subpath of the settingPath. */ export function getOverrideSetting( - settings: AttachmentManagementPluginSettings, - file: TAbstractFile, - oldPath = "" + settings: AttachmentManagementPluginSettings, + file: TAbstractFile, + oldPath = "" ): { settingPath: string; setting: AttachmentPathSettings } { - if (Object.keys(settings.overridePath).length === 0) { - return { settingPath: "", setting: settings.attachPath }; - } - - const candidates: Record = {}; - let fileType: boolean; - let filePath: string; - - fileType = file instanceof TFile; - fileType = !(file instanceof TFolder); - - if (oldPath === "") { - filePath = file.path; + if (Object.keys(settings.overridePath).length === 0) { + return { settingPath: "", setting: settings.attachPath }; + } + + const candidates: Record = {}; + let fileType: boolean; + let filePath: string; + + fileType = file instanceof TFile; + fileType = !(file instanceof TFolder); + + if (oldPath === "") { + filePath = file.path; + } else { + filePath = oldPath; + } + + for (const overridePath of Object.keys(settings.overridePath)) { + const overrideSetting = settings.overridePath[overridePath]; + if (fileType) { + if (overridePath === filePath && overrideSetting.type === SETTINGS_TYPES.FILE) { + // best match + return { settingPath: overridePath, setting: overrideSetting }; + } else if ( + filePath.startsWith(overridePath) && + filePath.charAt(overridePath.length) === "/" && + overrideSetting.type === SETTINGS_TYPES.FOLDER + ) { + // parent path + candidates[overridePath] = overrideSetting; + } } else { - filePath = oldPath; - } - - for (const overridePath of Object.keys(settings.overridePath)) { - const overrideSetting = settings.overridePath[overridePath]; - if (fileType) { - if (overridePath === filePath && overrideSetting.type === SETTINGS_TYPES.FILE) { - // best match - return { settingPath: overridePath, setting: overrideSetting }; - } else if ( - filePath.startsWith(overridePath) && - filePath.charAt(overridePath.length) === "/" && - overrideSetting.type === SETTINGS_TYPES.FOLDER - ) { - // parent path - candidates[overridePath] = overrideSetting; - } - } else { - if (overridePath === filePath && overrideSetting.type === SETTINGS_TYPES.FOLDER) { - // best match - return { settingPath: overridePath, setting: overrideSetting }; - } else if ( - filePath.startsWith(overridePath) && - filePath.charAt(overridePath.length) === "/" && - overrideSetting.type === SETTINGS_TYPES.FOLDER - ) { - // parent path - candidates[overridePath] = overrideSetting; - } - } + if (overridePath === filePath && overrideSetting.type === SETTINGS_TYPES.FOLDER) { + // best match + return { settingPath: overridePath, setting: overrideSetting }; + } else if ( + filePath.startsWith(overridePath) && + filePath.charAt(overridePath.length) === "/" && + overrideSetting.type === SETTINGS_TYPES.FOLDER + ) { + // parent path + candidates[overridePath] = overrideSetting; + } } + } - if (Object.keys(candidates).length === 0) { - return { settingPath: "", setting: settings.attachPath }; - } - - // sort by splitted path length, descending - const sortedK = Object.keys(candidates).sort((a, b) => - a.split("/").length > b.split("/").length ? -1 : a.split("/").length < b.split("/").length ? 1 : 0 - ); - debugLog("getOverrideSetting - sortedK:", sortedK); - for (const k of sortedK) { - if (filePath.startsWith(k)) { - return { settingPath: k, setting: candidates[k] }; - } + if (Object.keys(candidates).length === 0) { + return { settingPath: "", setting: settings.attachPath }; + } + + // sort by splitted path length, descending + const sortedK = Object.keys(candidates).sort((a, b) => + a.split("/").length > b.split("/").length ? -1 : a.split("/").length < b.split("/").length ? 1 : 0 + ); + debugLog("getOverrideSetting - sortedK:", sortedK); + for (const k of sortedK) { + if (filePath.startsWith(k)) { + return { settingPath: k, setting: candidates[k] }; } + } - return { settingPath: "", setting: settings.attachPath }; + return { settingPath: "", setting: settings.attachPath }; } /** @@ -95,52 +95,52 @@ export function getOverrideSetting( * subpath of the settingPath. */ export function getRenameOverrideSetting( - settings: AttachmentManagementPluginSettings, - file: TAbstractFile, - oldPath: string + settings: AttachmentManagementPluginSettings, + file: TAbstractFile, + oldPath: string ): { settingPath: string; setting: AttachmentPathSettings } { - if (Object.keys(settings.overridePath).length === 0) { - return { settingPath: "", setting: settings.attachPath }; - } - - const { settingPath: np, setting: ns } = getOverrideSetting(settings, file); - const { settingPath: op, setting: os } = getOverrideSetting(settings, file, oldPath); - - if (ns.type === SETTINGS_TYPES.GLOBAL) { - return { settingPath: op, setting: os }; - } + if (Object.keys(settings.overridePath).length === 0) { + return { settingPath: "", setting: settings.attachPath }; + } - if (os.type === SETTINGS_TYPES.GLOBAL) { - return { settingPath: np, setting: ns }; - } + const { settingPath: np, setting: ns } = getOverrideSetting(settings, file); + const { settingPath: op, setting: os } = getOverrideSetting(settings, file, oldPath); - if (ns.type === SETTINGS_TYPES.FILE && os.type === SETTINGS_TYPES.FILE) { - // This should not happen - debugLog("getRenameOverrideSetting - both file type setting", np, op); - return { settingPath: "", setting: settings.attachPath }; - } + if (ns.type === SETTINGS_TYPES.GLOBAL) { + return { settingPath: op, setting: os }; + } - if (ns.type === SETTINGS_TYPES.FILE && os.type === SETTINGS_TYPES.FOLDER) { - return { settingPath: np, setting: ns }; - } else if (ns.type === SETTINGS_TYPES.FOLDER && os.type === SETTINGS_TYPES.FILE) { - return { settingPath: op, setting: os }; - } + if (os.type === SETTINGS_TYPES.GLOBAL) { + return { settingPath: np, setting: ns }; + } - if (ns.type === SETTINGS_TYPES.FOLDER && os.type === SETTINGS_TYPES.FOLDER) { - const l = np.split("/").length; - const r = op.split("/").length; - - if (l > r) { - return { settingPath: np, setting: ns }; - } else if (l < r) { - return { settingPath: op, setting: os }; - } else if (l === r) { - // same case, np == op, return any one - return { settingPath: "", setting: os }; - } + if (ns.type === SETTINGS_TYPES.FILE && os.type === SETTINGS_TYPES.FILE) { + // This should not happen + debugLog("getRenameOverrideSetting - both file type setting", np, op); + return { settingPath: "", setting: settings.attachPath }; + } + + if (ns.type === SETTINGS_TYPES.FILE && os.type === SETTINGS_TYPES.FOLDER) { + return { settingPath: np, setting: ns }; + } else if (ns.type === SETTINGS_TYPES.FOLDER && os.type === SETTINGS_TYPES.FILE) { + return { settingPath: op, setting: os }; + } + + if (ns.type === SETTINGS_TYPES.FOLDER && os.type === SETTINGS_TYPES.FOLDER) { + const l = np.split("/").length; + const r = op.split("/").length; + + if (l > r) { + return { settingPath: np, setting: ns }; + } else if (l < r) { + return { settingPath: op, setting: os }; + } else if (l === r) { + // same case, np == op, return any one + return { settingPath: "", setting: os }; } + } - return { settingPath: "", setting: settings.attachPath }; + return { settingPath: "", setting: settings.attachPath }; } /** @@ -151,44 +151,44 @@ export function getRenameOverrideSetting( * @returns */ export function updateOverrideSetting( - settings: AttachmentManagementPluginSettings, - file: TAbstractFile, - oldPath: string + settings: AttachmentManagementPluginSettings, + file: TAbstractFile, + oldPath: string ) { - const keys = Object.keys(settings.overridePath); - if (keys.length === 0 || file.path === oldPath) { - return; - } - - const { settingPath, setting } = getOverrideSetting(settings, file, oldPath); - const copySetting = Object.assign({}, setting); - - // if the file was overridden, skip - if (file.path === settingPath) { - return; - } - - if (oldPath === settingPath) { - settings.overridePath[file.path] = copySetting; - delete settings.overridePath[settingPath]; - return; - } else { - const { stripedSrc, stripedDst } = stripPaths(oldPath, file.path); - if (stripedSrc === settingPath) { - settings.overridePath[stripedDst] = copySetting; - delete settings.overridePath[settingPath]; - return; - } + const keys = Object.keys(settings.overridePath); + if (keys.length === 0 || file.path === oldPath) { + return; + } + + const { settingPath, setting } = getOverrideSetting(settings, file, oldPath); + const copySetting = Object.assign({}, setting); + + // if the file was overridden, skip + if (file.path === settingPath) { + return; + } + + if (oldPath === settingPath) { + settings.overridePath[file.path] = copySetting; + delete settings.overridePath[settingPath]; + return; + } else { + const { stripedSrc, stripedDst } = stripPaths(oldPath, file.path); + if (stripedSrc === settingPath) { + settings.overridePath[stripedDst] = copySetting; + delete settings.overridePath[settingPath]; + return; } + } } export function deleteOverrideSetting(settings: AttachmentManagementPluginSettings, file: TAbstractFile): boolean { - const keys = Object.keys(settings.overridePath); - for (const key of keys) { - if (file.path === key) { - delete settings.overridePath[key]; - return true; - } + const keys = Object.keys(settings.overridePath); + for (const key of keys) { + if (file.path === key) { + delete settings.overridePath[key]; + return true; } - return false; + } + return false; } diff --git a/src/settings/metadata.ts b/src/settings/metadata.ts index 5f18a2a..d9cf705 100644 --- a/src/settings/metadata.ts +++ b/src/settings/metadata.ts @@ -1,12 +1,12 @@ import { DataAdapter, TFile, normalizePath } from "obsidian"; import { AttachmentPathSettings } from "./settings"; import { - SETTINGS_VARIABLES_DATES, - SETTINGS_VARIABLES_MD5, - SETTINGS_VARIABLES_NOTENAME, - SETTINGS_VARIABLES_NOTEPARENT, - SETTINGS_VARIABLES_NOTEPATH, - SETTINGS_VARIABLES_ORIGINALNAME, + SETTINGS_VARIABLES_DATES, + SETTINGS_VARIABLES_MD5, + SETTINGS_VARIABLES_NOTENAME, + SETTINGS_VARIABLES_NOTEPARENT, + SETTINGS_VARIABLES_NOTEPATH, + SETTINGS_VARIABLES_ORIGINALNAME, } from "../lib/constant"; import { getRootPath } from "../commons"; import { path } from "../lib/path"; @@ -17,133 +17,133 @@ import { getExtensionOverrideSetting } from "../model/extensionOverride"; * Metadata of notes file */ class Metadata { - /** path of file */ - path: string; - - /** name of file (with extension) */ - name: string; - - /** basename of file (without extension) */ - basename: string; - - /** extension of file */ - extension: string; - - /** parent path of file */ - parentPath = ""; - - /** parent path basename of file */ - parentName = ""; - - attachmentFile?: TFile; - - constructor( - path: string, - name: string, - basename: string, - extension: string, - parentPath: string, - parentName: string, - attachmentFile?: TFile - ) { - this.path = path; - this.name = name; - this.basename = basename; - this.extension = extension; - this.parentPath = parentPath; - this.parentName = parentName; - this.attachmentFile = attachmentFile; + /** path of file */ + path: string; + + /** name of file (with extension) */ + name: string; + + /** basename of file (without extension) */ + basename: string; + + /** extension of file */ + extension: string; + + /** parent path of file */ + parentPath = ""; + + /** parent path basename of file */ + parentName = ""; + + attachmentFile?: TFile; + + constructor( + path: string, + name: string, + basename: string, + extension: string, + parentPath: string, + parentName: string, + attachmentFile?: TFile + ) { + this.path = path; + this.name = name; + this.basename = basename; + this.extension = extension; + this.parentPath = parentPath; + this.parentName = parentName; + this.attachmentFile = attachmentFile; + } + + /** + * Returns a formatted attachment file name according to the provided settings. + * + * @param {AttachmentPathSettings} setting - attachment path settings object + * @param {string} dateFormat - format string for date and time + * @param {string} originalName - name of the original attachment + * @param {string} [linkName] - optional name for the attachment link + * @return {string} the formatted attachment file name + */ + async getAttachFileName( + setting: AttachmentPathSettings, + dateFormat: string, + originalName: string, + adapter: DataAdapter, + linkName?: string + ): Promise { + const dateTime = window.moment().format(dateFormat); + + let md5 = ""; + let attachFormat = ""; + if (this.attachmentFile !== undefined) { + md5 = await MD5(adapter, this.attachmentFile); + const { extSetting } = getExtensionOverrideSetting(this.attachmentFile.extension, setting); + if (extSetting !== undefined) { + attachFormat = extSetting.attachFormat; + } else { + attachFormat = setting.attachFormat; + } } - /** - * Returns a formatted attachment file name according to the provided settings. - * - * @param {AttachmentPathSettings} setting - attachment path settings object - * @param {string} dateFormat - format string for date and time - * @param {string} originalName - name of the original attachment - * @param {string} [linkName] - optional name for the attachment link - * @return {string} the formatted attachment file name - */ - async getAttachFileName( - setting: AttachmentPathSettings, - dateFormat: string, - originalName: string, - adapter: DataAdapter, - linkName?: string - ): Promise { - const dateTime = window.moment().format(dateFormat); - - let md5 = ""; - let attachFormat = ""; - if (this.attachmentFile !== undefined) { - md5 = await MD5(adapter, this.attachmentFile); - const { extSetting } = getExtensionOverrideSetting(this.attachmentFile.extension, setting); - if (extSetting !== undefined) { - attachFormat = extSetting.attachFormat; - } else { - attachFormat = setting.attachFormat; - } - } - - if (attachFormat.includes(SETTINGS_VARIABLES_ORIGINALNAME)) { - // we have no persistence of original name, return current linking name - if (originalName === "" && linkName != undefined) { - return linkName; - } else { - return attachFormat - .replace(`${SETTINGS_VARIABLES_DATES}`, dateTime) - .replace(`${SETTINGS_VARIABLES_NOTENAME}`, this.basename) - .replace(`${SETTINGS_VARIABLES_ORIGINALNAME}`, originalName) - .replace(`${SETTINGS_VARIABLES_MD5}`, md5); - } - } + if (attachFormat.includes(SETTINGS_VARIABLES_ORIGINALNAME)) { + // we have no persistence of original name, return current linking name + if (originalName === "" && linkName != undefined) { + return linkName; + } else { return attachFormat - .replace(`${SETTINGS_VARIABLES_DATES}`, dateTime) - .replace(`${SETTINGS_VARIABLES_NOTENAME}`, this.basename) - .replace(`${SETTINGS_VARIABLES_MD5}`, md5); + .replace(`${SETTINGS_VARIABLES_DATES}`, dateTime) + .replace(`${SETTINGS_VARIABLES_NOTENAME}`, this.basename) + .replace(`${SETTINGS_VARIABLES_ORIGINALNAME}`, originalName) + .replace(`${SETTINGS_VARIABLES_MD5}`, md5); + } } - - /** - * Returns the attachment path based on the given AttachmentPathSettings object. - * - * @param {AttachmentPathSettings} setting - An object containing the attachment path settings. - * @return {string} The normalized attachment path. - */ - getAttachmentPath(setting: AttachmentPathSettings, dateFormat: string): string { - const dateTime = window.moment().format(dateFormat); - let root = ""; - let attachPath = ""; - - if (this.attachmentFile !== undefined) { - // using extension override setting first - const { extSetting } = getExtensionOverrideSetting(this.attachmentFile.extension, setting); - if (extSetting !== undefined) { - root = getRootPath(this.parentPath, extSetting); - attachPath = path.join( - root, - extSetting.attachmentPath - .replace(`${SETTINGS_VARIABLES_NOTEPATH}`, this.parentPath) - .replace(`${SETTINGS_VARIABLES_NOTENAME}`, this.basename) - .replace(`${SETTINGS_VARIABLES_NOTEPARENT}`, this.parentName) - .replace(`${SETTINGS_VARIABLES_DATES}`, dateTime) - ); - - return normalizePath(attachPath); - } - } - - root = getRootPath(this.parentPath, setting); + return attachFormat + .replace(`${SETTINGS_VARIABLES_DATES}`, dateTime) + .replace(`${SETTINGS_VARIABLES_NOTENAME}`, this.basename) + .replace(`${SETTINGS_VARIABLES_MD5}`, md5); + } + + /** + * Returns the attachment path based on the given AttachmentPathSettings object. + * + * @param {AttachmentPathSettings} setting - An object containing the attachment path settings. + * @return {string} The normalized attachment path. + */ + getAttachmentPath(setting: AttachmentPathSettings, dateFormat: string): string { + const dateTime = window.moment().format(dateFormat); + let root = ""; + let attachPath = ""; + + if (this.attachmentFile !== undefined) { + // using extension override setting first + const { extSetting } = getExtensionOverrideSetting(this.attachmentFile.extension, setting); + if (extSetting !== undefined) { + root = getRootPath(this.parentPath, extSetting); attachPath = path.join( - root, - setting.attachmentPath - .replace(`${SETTINGS_VARIABLES_NOTEPATH}`, this.parentPath) - .replace(`${SETTINGS_VARIABLES_NOTENAME}`, this.basename) - .replace(`${SETTINGS_VARIABLES_NOTEPARENT}`, this.parentName) - .replace(`${SETTINGS_VARIABLES_DATES}`, dateTime) + root, + extSetting.attachmentPath + .replace(`${SETTINGS_VARIABLES_NOTEPATH}`, this.parentPath) + .replace(`${SETTINGS_VARIABLES_NOTENAME}`, this.basename) + .replace(`${SETTINGS_VARIABLES_NOTEPARENT}`, this.parentName) + .replace(`${SETTINGS_VARIABLES_DATES}`, dateTime) ); return normalizePath(attachPath); + } } + + root = getRootPath(this.parentPath, setting); + attachPath = path.join( + root, + setting.attachmentPath + .replace(`${SETTINGS_VARIABLES_NOTEPATH}`, this.parentPath) + .replace(`${SETTINGS_VARIABLES_NOTENAME}`, this.basename) + .replace(`${SETTINGS_VARIABLES_NOTEPARENT}`, this.parentName) + .replace(`${SETTINGS_VARIABLES_DATES}`, dateTime) + ); + + return normalizePath(attachPath); + } } /** @@ -153,11 +153,11 @@ class Metadata { * @return {Metadata} A new instance of Metadata containing information about the file. */ export function getMetadata(file: string, attach?: TFile): Metadata { - const parentPath = path.dirname(file); - const parentName = path.basename(parentPath); - const name = path.basename(file); - const extension = path.extname(file); - const basename = path.basename(file, extension); + const parentPath = path.dirname(file); + const parentName = path.basename(parentPath); + const name = path.basename(file); + const extension = path.extname(file); + const basename = path.basename(file, extension); - return new Metadata(file, name, basename, extension, parentPath, parentName, attach); + return new Metadata(file, name, basename, extension, parentPath, parentName, attach); } diff --git a/src/settings/settings.ts b/src/settings/settings.ts index 8a3b7c0..ed211e7 100644 --- a/src/settings/settings.ts +++ b/src/settings/settings.ts @@ -1,362 +1,358 @@ import { App, MomentFormatComponent, Notice, PluginSettingTab, Setting, TextAreaComponent } from "obsidian"; import AttachmentManagementPlugin from "../main"; import { - SETTINGS_ROOT_OBSFOLDER, - SETTINGS_VARIABLES_NOTEPATH, - SETTINGS_VARIABLES_NOTENAME, - SETTINGS_VARIABLES_NOTEPARENT, - SETTINGS_VARIABLES_DATES, - SETTINGS_ROOT_INFOLDER, - SETTINGS_ROOT_NEXTTONOTE, - SETTINGS_VARIABLES_ORIGINALNAME, - SETTINGS_VARIABLES_MD5, + SETTINGS_ROOT_OBSFOLDER, + SETTINGS_VARIABLES_NOTEPATH, + SETTINGS_VARIABLES_NOTENAME, + SETTINGS_VARIABLES_NOTEPARENT, + SETTINGS_VARIABLES_DATES, + SETTINGS_ROOT_INFOLDER, + SETTINGS_ROOT_NEXTTONOTE, + SETTINGS_VARIABLES_ORIGINALNAME, + SETTINGS_VARIABLES_MD5, } from "../lib/constant"; import { OverrideExtensionModal } from "src/model/extensionOverride"; import { validateExtensionEntry, generateErrorExtensionMessage } from "src/utils"; import { debugLog } from "src/lib/log"; export enum SETTINGS_TYPES { - GLOBAL = "GLOBAL", - FOLDER = "FOLDER", - FILE = "FILE", + GLOBAL = "GLOBAL", + FOLDER = "FOLDER", + FILE = "FILE", } export interface AttachmentPathSettings { - // Attachment root path - attachmentRoot: string; - // How to save attachment, in fixed folder, current folder or subfolder in current folder - saveAttE: string; - // Attachment path - attachmentPath: string; - // How to renamed the attachment file - attachFormat: string; - // Override type - type: SETTINGS_TYPES; - // Extension override - extensionOverride?: ExtensionOverrideSettings[]; + // Attachment root path + attachmentRoot: string; + // How to save attachment, in fixed folder, current folder or subfolder in current folder + saveAttE: string; + // Attachment path + attachmentPath: string; + // How to renamed the attachment file + attachFormat: string; + // Override type + type: SETTINGS_TYPES; + // Extension override + extensionOverride?: ExtensionOverrideSettings[]; } export interface OriginalNameStorage { - // Original name - n: string; - // Current name - md5: string; + // Original name + n: string; + // Current name + md5: string; } export interface ExtensionOverrideSettings { - // Extension - extension: string; - // Attachment root path - attachmentRoot: string; - // How to save attachment, in fixed folder, current folder or subfolder in current folder - saveAttE: string; - // Attachment path - attachmentPath: string; - // How to renamed the attachment file - attachFormat: string; + // Extension + extension: string; + // Attachment root path + attachmentRoot: string; + // How to save attachment, in fixed folder, current folder or subfolder in current folder + saveAttE: string; + // Attachment path + attachmentPath: string; + // How to renamed the attachment file + attachFormat: string; } export interface AttachmentManagementPluginSettings { - // Disable notification - disableNotification: boolean; - // Path - attachPath: AttachmentPathSettings; - // Date format - dateFormat: string; - // Exclude extension not to rename - excludeExtensionPattern: string; - // Auto-rename attachment folder or filename and update the link - autoRenameAttachment: boolean; - // Exclude path not to rename - excludedPaths: string; - // Exclude path array - excludePathsArray: string[]; - // Exclude subpath also - excludeSubpaths: boolean; - // Presistence storage of original name - originalNameStorage: OriginalNameStorage[]; - // Path of notes that override global configuration - overridePath: Record; + // Disable notification + disableNotification: boolean; + // Path + attachPath: AttachmentPathSettings; + // Date format + dateFormat: string; + // Exclude extension not to rename + excludeExtensionPattern: string; + // Auto-rename attachment folder or filename and update the link + autoRenameAttachment: boolean; + // Exclude path not to rename + excludedPaths: string; + // Exclude path array + excludePathsArray: string[]; + // Exclude subpath also + excludeSubpaths: boolean; + // Presistence storage of original name + originalNameStorage: OriginalNameStorage[]; + // Path of notes that override global configuration + overridePath: Record; } export const DEFAULT_SETTINGS: AttachmentManagementPluginSettings = { - attachPath: { - attachmentRoot: "", - saveAttE: `${SETTINGS_ROOT_OBSFOLDER}`, - attachmentPath: `${SETTINGS_VARIABLES_NOTEPATH}/${SETTINGS_VARIABLES_NOTENAME}`, - attachFormat: `IMG-${SETTINGS_VARIABLES_DATES}`, - type: SETTINGS_TYPES.GLOBAL, - }, - dateFormat: "YYYYMMDDHHmmssSSS", - excludeExtensionPattern: "", - autoRenameAttachment: true, - excludedPaths: "", - excludePathsArray: [], - excludeSubpaths: false, - originalNameStorage: [], - overridePath: {}, - disableNotification: false, + attachPath: { + attachmentRoot: "", + saveAttE: `${SETTINGS_ROOT_OBSFOLDER}`, + attachmentPath: `${SETTINGS_VARIABLES_NOTEPATH}/${SETTINGS_VARIABLES_NOTENAME}`, + attachFormat: `IMG-${SETTINGS_VARIABLES_DATES}`, + type: SETTINGS_TYPES.GLOBAL, + }, + dateFormat: "YYYYMMDDHHmmssSSS", + excludeExtensionPattern: "", + autoRenameAttachment: true, + excludedPaths: "", + excludePathsArray: [], + excludeSubpaths: false, + originalNameStorage: [], + overridePath: {}, + disableNotification: false, }; export class SettingTab extends PluginSettingTab { - plugin: AttachmentManagementPlugin; + plugin: AttachmentManagementPlugin; - constructor(app: App, plugin: AttachmentManagementPlugin) { - super(app, plugin); - this.plugin = plugin; - } + constructor(app: App, plugin: AttachmentManagementPlugin) { + super(app, plugin); + this.plugin = plugin; + } - displaySw(cont: HTMLElement): void { - cont.findAll(".setting-item").forEach((el: HTMLElement) => { - if (el.getAttr("class")?.includes("root_folder_set")) { - if (this.plugin.settings.attachPath.saveAttE === "obsFolder") { - el.hide(); - } else { - el.show(); - } - } - }); - } - - splitPath(path: string): { splittedPaths: string[] } { - const splitted = path.split(";"); - const rets = []; - for (const s of splitted) { - rets.push(s.trim()); + displaySw(cont: HTMLElement): void { + cont.findAll(".setting-item").forEach((el: HTMLElement) => { + if (el.getAttr("class")?.includes("root_folder_set")) { + if (this.plugin.settings.attachPath.saveAttE === "obsFolder") { + el.hide(); + } else { + el.show(); } - return { splittedPaths: rets }; + } + }); + } + + splitPath(path: string): { splittedPaths: string[] } { + const splitted = path.split(";"); + const rets = []; + for (const s of splitted) { + rets.push(s.trim()); } + return { splittedPaths: rets }; + } - display(): void { - const { containerEl } = this; + display(): void { + const { containerEl } = this; - containerEl.empty(); + containerEl.empty(); - // new Setting(containerEl).setName("Disable notification").addToggle((toggle) => { - // toggle.setValue(this.plugin.settings.disableNotification).onChange(async (value) => { - // this.plugin.settings.disableNotification = value; - // await this.plugin.saveSettings(); - // }); - // }); + // new Setting(containerEl).setName("Disable notification").addToggle((toggle) => { + // toggle.setValue(this.plugin.settings.disableNotification).onChange(async (value) => { + // this.plugin.settings.disableNotification = value; + // await this.plugin.saveSettings(); + // }); + // }); - new Setting(containerEl) - .setName("Root path to save attachment") - .setDesc("Select root path of attachment") - .addDropdown((text) => - text - .addOption(`${SETTINGS_ROOT_OBSFOLDER}`, "Copy Obsidian settings") - .addOption(`${SETTINGS_ROOT_INFOLDER}`, "In the folder specified below") - .addOption(`${SETTINGS_ROOT_NEXTTONOTE}`, "Next to note in folder specified below") - .setValue(this.plugin.settings.attachPath.saveAttE) - .onChange(async (value) => { - this.plugin.settings.attachPath.saveAttE = value; - this.displaySw(containerEl); - await this.plugin.saveSettings(); - }) - ); + new Setting(containerEl) + .setName("Root path to save attachment") + .setDesc("Select root path of attachment") + .addDropdown((text) => + text + .addOption(`${SETTINGS_ROOT_OBSFOLDER}`, "Copy Obsidian settings") + .addOption(`${SETTINGS_ROOT_INFOLDER}`, "In the folder specified below") + .addOption(`${SETTINGS_ROOT_NEXTTONOTE}`, "Next to note in folder specified below") + .setValue(this.plugin.settings.attachPath.saveAttE) + .onChange(async (value) => { + this.plugin.settings.attachPath.saveAttE = value; + this.displaySw(containerEl); + await this.plugin.saveSettings(); + }) + ); - new Setting(containerEl) - .setName("Root folder") - .setDesc("Root folder of new attachment") - .setClass("root_folder_set") - .addText((text) => - text - .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachmentRoot) - .setValue(this.plugin.settings.attachPath.attachmentRoot) - .onChange(async (value) => { - debugLog("setting - attachment root:" + value); - this.plugin.settings.attachPath.attachmentRoot = value; - await this.plugin.saveSettings(); - }) - ); + new Setting(containerEl) + .setName("Root folder") + .setDesc("Root folder of new attachment") + .setClass("root_folder_set") + .addText((text) => + text + .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachmentRoot) + .setValue(this.plugin.settings.attachPath.attachmentRoot) + .onChange(async (value) => { + debugLog("setting - attachment root:" + value); + this.plugin.settings.attachPath.attachmentRoot = value; + await this.plugin.saveSettings(); + }) + ); - new Setting(containerEl) - .setName("Attachment path") - .setDesc( - `Path of attachment in root folder, available variables ${SETTINGS_VARIABLES_NOTEPATH}, ${SETTINGS_VARIABLES_NOTENAME}, ${SETTINGS_VARIABLES_NOTEPARENT}` - ) - .addText((text) => - text - .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachmentPath) - .setValue(this.plugin.settings.attachPath.attachmentPath) - .onChange(async (value) => { - debugLog("setting - attachment path:" + value); - this.plugin.settings.attachPath.attachmentPath = value; - await this.plugin.saveSettings(); - }) - ); + new Setting(containerEl) + .setName("Attachment path") + .setDesc( + `Path of attachment in root folder, available variables ${SETTINGS_VARIABLES_NOTEPATH}, ${SETTINGS_VARIABLES_NOTENAME}, ${SETTINGS_VARIABLES_NOTEPARENT}` + ) + .addText((text) => + text + .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachmentPath) + .setValue(this.plugin.settings.attachPath.attachmentPath) + .onChange(async (value) => { + debugLog("setting - attachment path:" + value); + this.plugin.settings.attachPath.attachmentPath = value; + await this.plugin.saveSettings(); + }) + ); - new Setting(containerEl) - .setName("Attachment format") - .setDesc( - `Define how to name the attachment file, available variables ${SETTINGS_VARIABLES_DATES}, ${SETTINGS_VARIABLES_NOTENAME}, ${SETTINGS_VARIABLES_MD5} and ${SETTINGS_VARIABLES_ORIGINALNAME}.` - ) - .addText((text) => - text - .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachFormat) - .setValue(this.plugin.settings.attachPath.attachFormat) - .onChange(async (value: string) => { - debugLog("setting - attachment format:" + value); - this.plugin.settings.attachPath.attachFormat = value; - await this.plugin.saveSettings(); - }) - ); + new Setting(containerEl) + .setName("Attachment format") + .setDesc( + `Define how to name the attachment file, available variables ${SETTINGS_VARIABLES_DATES}, ${SETTINGS_VARIABLES_NOTENAME}, ${SETTINGS_VARIABLES_MD5} and ${SETTINGS_VARIABLES_ORIGINALNAME}.` + ) + .addText((text) => + text + .setPlaceholder(DEFAULT_SETTINGS.attachPath.attachFormat) + .setValue(this.plugin.settings.attachPath.attachFormat) + .onChange(async (value: string) => { + debugLog("setting - attachment format:" + value); + this.plugin.settings.attachPath.attachFormat = value; + await this.plugin.saveSettings(); + }) + ); - new Setting(containerEl) - .setName("Date format") - .setDesc( - createFragment((frag) => { - frag.appendText("Moment date format to use "); - frag.createEl("a", { - href: "https://momentjscom.readthedocs.io/en/latest/moment/04-displaying/01-format", - text: "Moment format options", - }); - }) - ) - .addMomentFormat((component: MomentFormatComponent) => { - component - .setPlaceholder(DEFAULT_SETTINGS.dateFormat) - .setValue(this.plugin.settings.dateFormat) - .onChange(async (value) => { - debugLog("setting - date format:" + value); - this.plugin.settings.dateFormat = value; - await this.plugin.saveSettings(); - }); - }); + new Setting(containerEl) + .setName("Date format") + .setDesc( + createFragment((frag) => { + frag.appendText("Moment date format to use "); + frag.createEl("a", { + href: "https://momentjscom.readthedocs.io/en/latest/moment/04-displaying/01-format", + text: "Moment format options", + }); + }) + ) + .addMomentFormat((component: MomentFormatComponent) => { + component + .setPlaceholder(DEFAULT_SETTINGS.dateFormat) + .setValue(this.plugin.settings.dateFormat) + .onChange(async (value) => { + debugLog("setting - date format:" + value); + this.plugin.settings.dateFormat = value; + await this.plugin.saveSettings(); + }); + }); - new Setting(containerEl) - .setName("Automatically rename attachment") - .setDesc( - "Automatically rename the attachment folder/filename when you rename the folder/filename where the corresponding md/canvas file be placed." - ) - .addToggle((toggle) => - toggle.setValue(this.plugin.settings.autoRenameAttachment).onChange(async (value) => { - debugLog("setting - automatically rename attachment folder:" + value); - this.plugin.settings.autoRenameAttachment = value; - await this.plugin.saveSettings(); - }) - ); + new Setting(containerEl) + .setName("Automatically rename attachment") + .setDesc( + "Automatically rename the attachment folder/filename when you rename the folder/filename where the corresponding md/canvas file be placed." + ) + .addToggle((toggle) => + toggle.setValue(this.plugin.settings.autoRenameAttachment).onChange(async (value) => { + debugLog("setting - automatically rename attachment folder:" + value); + this.plugin.settings.autoRenameAttachment = value; + await this.plugin.saveSettings(); + }) + ); - new Setting(containerEl).addButton((btn) => { - btn.setButtonText("Add extension overrides").onClick(async () => { - if (this.plugin.settings.attachPath.extensionOverride === undefined) { - this.plugin.settings.attachPath.extensionOverride = []; + new Setting(containerEl).addButton((btn) => { + btn.setButtonText("Add extension overrides").onClick(async () => { + if (this.plugin.settings.attachPath.extensionOverride === undefined) { + this.plugin.settings.attachPath.extensionOverride = []; + } + this.plugin.settings.attachPath.extensionOverride.push({ + extension: "", + attachmentRoot: this.plugin.settings.attachPath.attachmentRoot, + saveAttE: this.plugin.settings.attachPath.saveAttE, + attachmentPath: this.plugin.settings.attachPath.attachmentPath, + attachFormat: this.plugin.settings.attachPath.attachFormat, + }); + await this.plugin.saveSettings(); + this.display(); + }); + }); + + if (this.plugin.settings.attachPath.extensionOverride !== undefined) { + this.plugin.settings.attachPath.extensionOverride.forEach((ext) => { + new Setting(containerEl) + .setName("Extension") + .setDesc("Extension to override") + .setClass("override_extension_set") + .addText((text) => + text + .setPlaceholder("pdf") + .setValue(ext.extension) + .onChange(async (value) => { + ext.extension = value; + }) + ) + .addButton((btn) => { + btn + .setIcon("trash") + .setTooltip("Remove extension override") + .onClick(async () => { + //get index of extension + const index = this.plugin.settings.attachPath.extensionOverride?.indexOf(ext) ?? -1; + //remove extension from array + this.plugin.settings.attachPath.extensionOverride?.splice(index, 1); + await this.plugin.saveSettings(); + this.display(); + }); + }) + .addButton((btn) => { + btn + .setIcon("pencil") + .setTooltip("Edit extension override") + .onClick(async () => { + new OverrideExtensionModal(this.plugin, ext, (result) => { + ext = result; + }).open(); + }); + }) + .addButton((btn) => { + btn + .setIcon("check") + .setTooltip("Save extension override") + .onClick(async () => { + const wrongIndex = validateExtensionEntry(this.plugin.settings.attachPath, this.plugin.settings); + if (wrongIndex.length > 0) { + for (const i of wrongIndex) { + const resIndex = i.index < 0 ? 0 : i.index; + const wrongSetting = containerEl.getElementsByClassName("override_extension_set")[resIndex]; + wrongSetting.getElementsByTagName("input")[0].style.border = "1px solid var(--color-red)"; + generateErrorExtensionMessage(i.type); + } + return; } - this.plugin.settings.attachPath.extensionOverride.push({ - extension: "", - attachmentRoot: this.plugin.settings.attachPath.attachmentRoot, - saveAttE: this.plugin.settings.attachPath.saveAttE, - attachmentPath: this.plugin.settings.attachPath.attachmentPath, - attachFormat: this.plugin.settings.attachPath.attachFormat, - }); await this.plugin.saveSettings(); this.display(); - }); - }); - - if (this.plugin.settings.attachPath.extensionOverride !== undefined) { - this.plugin.settings.attachPath.extensionOverride.forEach((ext) => { - new Setting(containerEl) - .setName("Extension") - .setDesc("Extension to override") - .setClass("override_extension_set") - .addText((text) => - text - .setPlaceholder("pdf") - .setValue(ext.extension) - .onChange(async (value) => { - ext.extension = value; - }) - ) - .addButton((btn) => { - btn.setIcon("trash") - .setTooltip("Remove extension override") - .onClick(async () => { - //get index of extension - const index = this.plugin.settings.attachPath.extensionOverride?.indexOf(ext) ?? -1; - //remove extension from array - this.plugin.settings.attachPath.extensionOverride?.splice(index, 1); - await this.plugin.saveSettings(); - this.display(); - }); - }) - .addButton((btn) => { - btn.setIcon("pencil") - .setTooltip("Edit extension override") - .onClick(async () => { - new OverrideExtensionModal(this.plugin, ext, (result) => { - ext = result; - }).open(); - }); - }) - .addButton((btn) => { - btn.setIcon("check") - .setTooltip("Save extension override") - .onClick(async () => { - const wrongIndex = validateExtensionEntry( - this.plugin.settings.attachPath, - this.plugin.settings - ); - if (wrongIndex.length > 0) { - for (const i of wrongIndex) { - const resIndex = i.index < 0 ? 0 : i.index; - const wrongSetting = - containerEl.getElementsByClassName("override_extension_set")[resIndex]; - wrongSetting.getElementsByTagName("input")[0].style.border = - "1px solid var(--color-red)"; - generateErrorExtensionMessage(i.type); - } - return; - } - await this.plugin.saveSettings(); - this.display(); - new Notice("Saved extension override"); - }); - }); - }); - } + new Notice("Saved extension override"); + }); + }); + }); + } - new Setting(containerEl) - .setName("Exclude extension pattern") - .setDesc(`Regex pattern to exclude certain extensions from being handled.`) - .addText((text) => - text - .setPlaceholder("pdf|docx?|xlsx?|pptx?|zip|rar") - .setValue(this.plugin.settings.excludeExtensionPattern) - .onChange(async (value) => { - this.plugin.settings.excludeExtensionPattern = value; - await this.plugin.saveSettings(); - }) - ); + new Setting(containerEl) + .setName("Exclude extension pattern") + .setDesc(`Regex pattern to exclude certain extensions from being handled.`) + .addText((text) => + text + .setPlaceholder("pdf|docx?|xlsx?|pptx?|zip|rar") + .setValue(this.plugin.settings.excludeExtensionPattern) + .onChange(async (value) => { + this.plugin.settings.excludeExtensionPattern = value; + await this.plugin.saveSettings(); + }) + ); - new Setting(containerEl) - .setName("Excluded paths") - .setDesc( - `Provide the full path of the folder names (case sensitive and without leading slash '/') divided by semicolon (;) to be excluded from renaming.` - ) - .addTextArea((component: TextAreaComponent) => { - component.setValue(this.plugin.settings.excludedPaths).onChange(async (value) => { - this.plugin.settings.excludedPaths = value; - const { splittedPaths } = this.splitPath(value); - this.plugin.settings.excludePathsArray = splittedPaths; - debugLog("setting - excluded paths:" + value, splittedPaths); - await this.plugin.saveSettings(); - }); - }); + new Setting(containerEl) + .setName("Excluded paths") + .setDesc( + `Provide the full path of the folder names (case sensitive and without leading slash '/') divided by semicolon (;) to be excluded from renaming.` + ) + .addTextArea((component: TextAreaComponent) => { + component.setValue(this.plugin.settings.excludedPaths).onChange(async (value) => { + this.plugin.settings.excludedPaths = value; + const { splittedPaths } = this.splitPath(value); + this.plugin.settings.excludePathsArray = splittedPaths; + debugLog("setting - excluded paths:" + value, splittedPaths); + await this.plugin.saveSettings(); + }); + }); - new Setting(containerEl) - .setName("Exclude subpaths") - .setDesc( - "Turn on this option if you want to also exclude all subfolders of the folder paths provided above." - ) - .addToggle((toggle) => - toggle.setValue(this.plugin.settings.excludeSubpaths).onChange(async (value) => { - debugLog("setting - excluded subpaths:" + value); - this.plugin.settings.excludeSubpaths = value; - await this.plugin.saveSettings(); - }) - ); + new Setting(containerEl) + .setName("Exclude subpaths") + .setDesc("Turn on this option if you want to also exclude all subfolders of the folder paths provided above.") + .addToggle((toggle) => + toggle.setValue(this.plugin.settings.excludeSubpaths).onChange(async (value) => { + debugLog("setting - excluded subpaths:" + value); + this.plugin.settings.excludeSubpaths = value; + await this.plugin.saveSettings(); + }) + ); - this.displaySw(containerEl); - } + this.displaySw(containerEl); + } } diff --git a/src/utils.ts b/src/utils.ts index e69f3b2..8a48c50 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,57 +1,42 @@ import { DataAdapter, Notice, TAbstractFile, TFile } from "obsidian"; import { AttachmentManagementPluginSettings, AttachmentPathSettings } from "./settings/settings"; -import { - SETTINGS_VARIABLES_NOTENAME, - SETTINGS_VARIABLES_NOTEPATH, - SETTINGS_VARIABLES_NOTEPARENT, -} from "./lib/constant"; -import { Md5 } from "ts-md5"; -export enum ATTACHMENT_RENAME_TYPE { - // need to rename the attachment folder and file name - BOTH = "BOTH", - // need to rename the attachment folder - FOLDER = "FOLDER", - // need to rename the attachment file name - FILE = "FILE", - // no need to rename - NULL = "NULL", -} +import { Md5 } from "ts-md5"; const PASTED_IMAGE_PREFIX = "Pasted image "; const ImageExtensionRegex = /^(jpe?g|png|gif|svg|bmp|eps|webp)$/i; export const blobToArrayBuffer = (blob: Blob) => { - return new Promise((resolve) => { - const reader = new FileReader(); - reader.onloadend = () => resolve(reader.result); - reader.readAsArrayBuffer(blob); - }); + return new Promise((resolve) => { + const reader = new FileReader(); + reader.onloadend = () => resolve(reader.result); + reader.readAsArrayBuffer(blob); + }); }; export function isMarkdownFile(extension: string): boolean { - return extension === "md"; + return extension === "md"; } export function isCanvasFile(extension: string): boolean { - return extension === "canvas"; + return extension === "canvas"; } export function isPastedImage(file: TAbstractFile): boolean { - if (file instanceof TFile) { - if (file.name.startsWith(PASTED_IMAGE_PREFIX)) { - return true; - } + if (file instanceof TFile) { + if (file.name.startsWith(PASTED_IMAGE_PREFIX)) { + return true; } - return false; + } + return false; } export function isImage(extension: string): boolean { - const match = extension.match(ImageExtensionRegex); - if (match !== null) { - return true; - } - return false; + const match = extension.match(ImageExtensionRegex); + if (match !== null) { + return true; + } + return false; } /** @@ -67,33 +52,33 @@ export function isImage(extension: string): boolean { * @returns the first different prefix, otherwise, return the original path */ export function stripPaths(src: string, dst: string): { stripedSrc: string; stripedDst: string } { - if (src === dst) { - return { stripedSrc: src, stripedDst: dst }; + if (src === dst) { + return { stripedSrc: src, stripedDst: dst }; + } + + const srcParts = src.split("/"); + const dstParts = dst.split("/"); + + // if src and dst have difference count of parts, + // we think the paths was not in a same parent folder and no need to strip the prefix + if (srcParts.length !== dstParts.length) { + return { stripedSrc: src, stripedDst: dst }; + } + + for (let i = 0; i < srcParts.length; i++) { + const srcPart = srcParts[i]; + const dstPart = dstParts[i]; + + // find the first different part + if (srcPart !== dstPart) { + return { + stripedSrc: srcParts.slice(0, i + 1).join("/"), + stripedDst: dstParts.slice(0, i + 1).join("/"), + }; } + } - const srcParts = src.split("/"); - const dstParts = dst.split("/"); - - // if src and dst have difference count of parts, - // we think the paths was not in a same parent folder and no need to strip the prefix - if (srcParts.length !== dstParts.length) { - return { stripedSrc: src, stripedDst: dst }; - } - - for (let i = 0; i < srcParts.length; i++) { - const srcPart = srcParts[i]; - const dstPart = dstParts[i]; - - // find the first different part - if (srcPart !== dstPart) { - return { - stripedSrc: srcParts.slice(0, i + 1).join("/"), - stripedDst: dstParts.slice(0, i + 1).join("/"), - }; - } - } - - return { stripedSrc: "", stripedDst: "" }; + return { stripedSrc: "", stripedDst: "" }; } /** @@ -103,8 +88,8 @@ export function stripPaths(src: string, dst: string): { stripedSrc: string; stri * @returns true if matched, false otherwise */ export function matchExtension(extension: string, pattern: string): boolean { - if (!pattern || pattern === "") return false; - return new RegExp(pattern).test(extension); + if (!pattern || pattern === "") return false; + return new RegExp(pattern).test(extension); } /** @@ -114,127 +99,97 @@ export function matchExtension(extension: string, pattern: string): boolean { * @returns true if the file is an attachment, false otherwise */ export function isAttachment(settings: AttachmentManagementPluginSettings, filePath: string | TAbstractFile): boolean { - let file = null; - if (filePath instanceof TAbstractFile) { - file = filePath; - } else { - file = this.app.vault.getAbstractFileByPath(filePath); - } - - if (file === null || !(file instanceof TFile)) { - return false; - } - - if (isMarkdownFile(file.extension) || isCanvasFile(file.extension)) { - return false; - } - - return !matchExtension(file.extension, settings.excludeExtensionPattern); -} + let file = null; + if (filePath instanceof TAbstractFile) { + file = filePath; + } else { + file = this.app.vault.getAbstractFileByPath(filePath); + } + + if (file === null || !(file instanceof TFile)) { + return false; + } -/** - * Returns the attachment rename type based on the given attachment path settings. - * - * @param {AttachmentPathSettings} setting - The attachment path settings to examine. - * @return {ATTACHMENT_RENAME_TYPE} - The attachment rename type based on the given attachment path settings. - */ -export function attachRenameType(setting: AttachmentPathSettings): ATTACHMENT_RENAME_TYPE { - let ret = ATTACHMENT_RENAME_TYPE.BOTH; - - if (setting.attachFormat.includes(SETTINGS_VARIABLES_NOTENAME)) { - if ( - setting.attachmentPath.includes(SETTINGS_VARIABLES_NOTENAME) || - setting.attachmentPath.includes(SETTINGS_VARIABLES_NOTEPATH) || - setting.attachmentPath.includes(SETTINGS_VARIABLES_NOTEPARENT) - ) { - ret = ATTACHMENT_RENAME_TYPE.BOTH; - } else { - ret = ATTACHMENT_RENAME_TYPE.FILE; - } - } else if ( - setting.attachmentPath.includes(SETTINGS_VARIABLES_NOTENAME) || - setting.attachmentPath.includes(SETTINGS_VARIABLES_NOTEPATH) || - setting.attachmentPath.includes(SETTINGS_VARIABLES_NOTEPARENT) - ) { - ret = ATTACHMENT_RENAME_TYPE.FOLDER; - } + if (isMarkdownFile(file.extension) || isCanvasFile(file.extension)) { + return false; + } - return ret; + return !matchExtension(file.extension, settings.excludeExtensionPattern); } export function getParentFolder(rf: TFile) { - const parent = rf.parent; - let parentPath = "/"; - let parentName = "/"; - if (parent) { - parentPath = parent.path; - parentName = parent.name; - } - return { parentPath, parentName }; + const parent = rf.parent; + let parentPath = "/"; + let parentName = "/"; + if (parent) { + parentPath = parent.path; + parentName = parent.name; + } + return { parentPath, parentName }; } export async function MD5(adapter: DataAdapter, file: TFile): Promise { - const md5 = new Md5(); + const md5 = new Md5(); - if (!adapter.exists(file.path, true)) { - return ""; - } + if (!adapter.exists(file.path, true)) { + return ""; + } - const content = await adapter.readBinary(file.path); - md5.appendByteArray(new Uint8Array(content)); - const ret = md5.end() as string; + const content = await adapter.readBinary(file.path); + md5.appendByteArray(new Uint8Array(content)); + const ret = md5.end() as string; - return ret.toUpperCase(); + return ret.toUpperCase(); } export function validateExtensionEntry(setting: AttachmentPathSettings, plugin: AttachmentManagementPluginSettings) { - const wrongIndex: { - type: "empty" | "duplicate" | "md" | "canvas" | "excluded"; - index: number; - }[] = []; - if (setting.extensionOverride !== undefined) { - const extOverride = setting.extensionOverride; - if (extOverride.some((ext) => ext.extension === "")) { - wrongIndex.push({ type: "empty", index: extOverride.findIndex((ext) => ext.extension === "") }); - } - const duplicate = extOverride - .map((ext) => ext.extension) - .filter((value, index, self) => self.indexOf(value) !== index); - if (duplicate.length > 0) { - duplicate.forEach((dupli) => { - wrongIndex.push({ type: "duplicate", index: extOverride.findIndex((ext) => dupli === ext.extension) }); - }); - } - const markdown = extOverride.filter((ext) => ext.extension === "md"); - if (markdown.length > 0) { - wrongIndex.push({ type: "md", index: extOverride.findIndex((ext) => ext.extension === "md") }); - } - const canvas = extOverride.filter((ext) => ext.extension === "canvas"); - if (canvas.length > 0) { - wrongIndex.push({ type: "canvas", index: extOverride.findIndex((ext) => ext.extension === "canvas") }); - } - const excludedFromSettings = plugin.excludeExtensionPattern.split("|"); - const excluded = extOverride.filter((ext) => excludedFromSettings.includes(ext.extension)); - if (excluded.length > 0) { - wrongIndex.push({ - type: "excluded", - index: extOverride.findIndex((ext) => excludedFromSettings.includes(ext.extension)), - }); - } + const wrongIndex: { + type: "empty" | "duplicate" | "md" | "canvas" | "excluded"; + index: number; + }[] = []; + if (setting.extensionOverride !== undefined) { + const extOverride = setting.extensionOverride; + if (extOverride.some((ext) => ext.extension === "")) { + wrongIndex.push({ type: "empty", index: extOverride.findIndex((ext) => ext.extension === "") }); + } + const duplicate = extOverride + .map((ext) => ext.extension) + .filter((value, index, self) => self.indexOf(value) !== index); + if (duplicate.length > 0) { + duplicate.forEach((dupli) => { + wrongIndex.push({ type: "duplicate", index: extOverride.findIndex((ext) => dupli === ext.extension) }); + }); + } + const markdown = extOverride.filter((ext) => ext.extension === "md"); + if (markdown.length > 0) { + wrongIndex.push({ type: "md", index: extOverride.findIndex((ext) => ext.extension === "md") }); } - return wrongIndex; + const canvas = extOverride.filter((ext) => ext.extension === "canvas"); + if (canvas.length > 0) { + wrongIndex.push({ type: "canvas", index: extOverride.findIndex((ext) => ext.extension === "canvas") }); + } + const excludedFromSettings = plugin.excludeExtensionPattern.split("|"); + const excluded = extOverride.filter((ext) => excludedFromSettings.includes(ext.extension)); + if (excluded.length > 0) { + wrongIndex.push({ + type: "excluded", + index: extOverride.findIndex((ext) => excludedFromSettings.includes(ext.extension)), + }); + } + } + return wrongIndex; } export function generateErrorExtensionMessage(type: "md" | "canvas" | "empty" | "duplicate" | "excluded") { - if (type === "canvas") { - new Notice("Canvas is not supported as an extension override."); - } else if (type === "md") { - new Notice("Markdown is not supported as an extension override."); - } else if (type === "empty") { - new Notice("Extension override cannot be empty."); - } else if (type === "duplicate") { - new Notice("Duplicate extension override."); - } else if (type === "excluded") { - new Notice("Extension override cannot be an excluded extension."); - } + if (type === "canvas") { + new Notice("Canvas is not supported as an extension override."); + } else if (type === "md") { + new Notice("Markdown is not supported as an extension override."); + } else if (type === "empty") { + new Notice("Extension override cannot be empty."); + } else if (type === "duplicate") { + new Notice("Duplicate extension override."); + } else if (type === "excluded") { + new Notice("Extension override cannot be an excluded extension."); + } }