From c6dff278d2b4533d09bb9d2c6f2201f1f8def546 Mon Sep 17 00:00:00 2001 From: vorotamoroz Date: Tue, 18 Aug 2026 04:15:17 +0000 Subject: [PATCH] fix: align source with Community Review --- .github/workflows/ci.yml | 5 +- eslint.community.config.mjs | 46 + main.ts | 17 +- package-lock.json | 950 ++++-------------- package.json | 16 +- src/CombinedFragment.ts | 2 +- src/DiffZipSettingTab.ts | 57 +- src/ObsHttpHandler.ts | 45 +- src/ProgressFragment.ts | 14 +- src/StorageAccessor/DirectVault.ts | 6 +- .../ExternalVaultFilesystem.ts | 59 +- src/StorageAccessor/NormalVault.ts | 6 +- src/StorageAccessor/S3Bucket.ts | 13 +- src/SyncEngine.test.ts | 19 +- src/SyncEngine.ts | 116 +-- src/SyncPlanner.ts | 55 +- src/SyncRemoteDialog.ts | 11 +- src/legacySettingsCrypto.ts | 19 + src/types.ts | 2 +- tests/ui/ObsHttpHandler.test.ts | 60 ++ tests/ui/legacySettingsCrypto.test.ts | 22 + tests/ui/obsidianMock.ts | 3 + vitest.config.ts | 6 + 23 files changed, 487 insertions(+), 1062 deletions(-) create mode 100644 eslint.community.config.mjs create mode 100644 src/legacySettingsCrypto.ts create mode 100644 tests/ui/ObsHttpHandler.test.ts create mode 100644 tests/ui/legacySettingsCrypto.test.ts create mode 100644 tests/ui/obsidianMock.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3f8d49..d66e05d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: deno-version: v2.x - name: Install dependencies - run: npm ci + run: npx --yes npm@10.9.4 ci - name: Build run: npm run build @@ -35,6 +35,9 @@ jobs: - name: Lint run: npm run lint + - name: Community review blockers + run: npm run lint:community -- --quiet + - name: UI tests run: npm run test:ui diff --git a/eslint.community.config.mjs b/eslint.community.config.mjs new file mode 100644 index 0000000..a9caf5c --- /dev/null +++ b/eslint.community.config.mjs @@ -0,0 +1,46 @@ +import obsidianmd from "eslint-plugin-obsidianmd"; +import globals from "globals"; +import { defineConfig, globalIgnores } from "eslint/config"; + +export default defineConfig( + globalIgnores([ + "node_modules", + "dist", + "coverage", + "main.js", + "package.json", + "package-lock.json", + "versions.json", + "**/*.svelte", + "**/*.test.ts", + "test/**", + ]), + { + languageOptions: { + globals: { + ...globals.browser, + }, + parserOptions: { + project: "./tsconfig.json", + tsconfigRootDir: import.meta.dirname, + }, + }, + }, + ...obsidianmd.configs.recommended, + { + rules: { + // The directory review reports console usage as guidance rather than a release blocker. + "obsidianmd/rule-custom-message": "off", + "no-console": "warn", + // Keep existing type-safety debt visible while reserving errors for directory-review blockers. + "@typescript-eslint/no-unsafe-argument": "warn", + "@typescript-eslint/no-unsafe-assignment": "warn", + "@typescript-eslint/no-unsafe-call": "warn", + "@typescript-eslint/no-unsafe-member-access": "warn", + "@typescript-eslint/no-unsafe-return": "warn", + "@typescript-eslint/no-base-to-string": "warn", + "@typescript-eslint/no-redundant-type-constituents": "warn", + "@typescript-eslint/no-unnecessary-type-assertion": "warn", + }, + } +); diff --git a/main.ts b/main.ts index f75e398..fca0241 100644 --- a/main.ts +++ b/main.ts @@ -72,8 +72,9 @@ export default class DiffZipBackupPlugin extends Plugin { } get sep(): string { - //@ts-ignore - return (this.isDesktopMode ? this.app.vault.adapter.path.sep : "/") as string; + if (!this.isDesktopMode) return "/"; + const desktopAdapter = this.app.vault.adapter as unknown as { path: { sep: string } }; + return desktopAdapter.path.sep; } messages = {} as Record; @@ -113,9 +114,8 @@ export default class DiffZipBackupPlugin extends Plugin { delete this.messages[key]; } } - logWrite(message: string, _key?: string) { - const dt = new Date().toLocaleString(); - console.log(`${dt}\t${message}`); + logWrite(_message: string, _key?: string): void { + // Detailed operational logging is intentionally quiet in production. } async getFiles(path: string, ignoreList: string[], progress: ProgressFragment) { @@ -158,9 +158,8 @@ export default class DiffZipBackupPlugin extends Plugin { } else { this.logWrite(`Backup information has been loaded`, "proc-index"); } - } catch (ex) { + } catch { this.logMessage(`Something went wrong while parsing Backup information`, "proc-index"); - console.warn(ex); toc = {}; } } else { @@ -188,8 +187,8 @@ export default class DiffZipBackupPlugin extends Plugin { }, 1000); }, }); - const noticeFragment = activeDocument.createDocumentFragment(); - const noticeContainer = activeDocument.createElement("div"); + const noticeFragment = createFragment(); + const noticeContainer = noticeFragment.createDiv(); noticeContainer.classList.add("diffzip-progress-notice"); noticeContainer.appendChild(progress.fragment); noticeFragment.appendChild(noticeContainer); diff --git a/package-lock.json b/package-lock.json index 55a78f0..e121e9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,22 +22,23 @@ "@smithy/fetch-http-handler": "^5.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.17.2", "@sveltejs/vite-plugin-svelte": "^7.1.4", "@testing-library/svelte": "^5.4.2", "@testing-library/user-event": "^14.6.1", "@tsconfig/svelte": "^5.0.4", "@types/node": "^22.19.19", - "@typescript-eslint/eslint-plugin": "8.56.1", - "@typescript-eslint/parser": "^8.56.1", + "@typescript-eslint/eslint-plugin": "^8.67.0", + "@typescript-eslint/parser": "^8.67.0", "@vrtmrz/obsidian-test-session": "0.2.0", "esbuild": "0.28.1", "esbuild-svelte": "^0.9.5", "eslint": "^9.39.3", - "eslint-plugin-obsidianmd": "^0.3.0", + "eslint-plugin-obsidianmd": "^0.4.1", "eslint-plugin-svelte": "^3.15.0", "globals": "^14.0.0", "jsdom": "^29.1.1", - "obsidian": "^1.8.7", + "obsidian": "^1.13.1", "playwright": "^1.61.1", "prettier": "^3.5.3", "svelte": "^5.1.15", @@ -46,7 +47,8 @@ "svelte-preprocess": "^6.0.3", "tslib": "2.8.1", "tsx": "^4.23.0", - "typescript": "5.7.3", + "typescript": "^5.9.3", + "typescript-eslint": "^8.67.0", "vite": "^8.1.3", "vitest": "^4.1.10" } @@ -590,7 +592,6 @@ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -967,7 +968,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" }, @@ -1016,7 +1016,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" } @@ -1069,206 +1068,12 @@ } } }, - "node_modules/@dword-design/eslint-plugin-import-alias/node_modules/@typescript-eslint/project-service": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.61.1.tgz", - "integrity": "sha512-PrC4JYGmR241lYnfhmKGTXkFqv8+ymbTFgSAY0fVXpY82/QkMw5TZPl+vGzuDDU2QYJk9fIDOBTntF+yDv9LEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.61.1", - "@typescript-eslint/types": "^8.61.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@dword-design/eslint-plugin-import-alias/node_modules/@typescript-eslint/scope-manager": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.61.1.tgz", - "integrity": "sha512-L2bdIeoQS8FlKAvONAr20w6OcLXeB+qiDKbAooS9A0Ben+iSIkBef0FxqwKWYqt5sa0i4KJtxVyVmhMylKzF5w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.61.1", - "@typescript-eslint/visitor-keys": "8.61.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@dword-design/eslint-plugin-import-alias/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.1.tgz", - "integrity": "sha512-UN/H4di+OO7EWx2ovME+8t31YO+KVnK0RRKEHR3kOt21/Ay8BOq3M1OMvWs5vNiqcFCYGYoxK3MXPZzmMUE+yg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@dword-design/eslint-plugin-import-alias/node_modules/@typescript-eslint/types": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.61.1.tgz", - "integrity": "sha512-G+CRlPqLv7Bz1IZVs03x5K59F1veqL0EJUROAdGhKsEq8qOiRiZbI+HUojPq5l0fEGOKModD9br6lObhB8zkoA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@dword-design/eslint-plugin-import-alias/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.61.1.tgz", - "integrity": "sha512-u+oQD3BqYWPc8YV9Zab4vaJElJuwOLPRc10Jm1o/qS+6Qwen14HCWwx0Seo4LnSn2wxea2Ik8DxPt2/FHmuhrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.61.1", - "@typescript-eslint/tsconfig-utils": "8.61.1", - "@typescript-eslint/types": "8.61.1", - "@typescript-eslint/visitor-keys": "8.61.1", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@dword-design/eslint-plugin-import-alias/node_modules/@typescript-eslint/utils": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.61.1.tgz", - "integrity": "sha512-1+P/3Dj6jvtybE1q0HQ6yBt/gq+oKJyLdEv4HdnqasaEXRSYCAsD59mXEVQnM/ULNdQxbX77tdG4jPRjIS6knA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.61.1", - "@typescript-eslint/types": "8.61.1", - "@typescript-eslint/typescript-estree": "8.61.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@dword-design/eslint-plugin-import-alias/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.61.1.tgz", - "integrity": "sha512-6fJ9MHWtK14C1DSkiMlHUSOmrVebL7150xZJBlJiL62jjhIA4JmOq6flwBgDxIdBKKdoiZRel+dfPD5MLfny3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.61.1", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@dword-design/eslint-plugin-import-alias/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@dword-design/eslint-plugin-import-alias/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@dword-design/eslint-plugin-import-alias/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@dword-design/eslint-plugin-import-alias/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@emnapi/core": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" @@ -1280,7 +1085,6 @@ "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -1737,6 +1541,36 @@ "node": ">=18" } }, + "node_modules/@eslint-community/eslint-plugin-eslint-comments": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-4.7.2.tgz", + "integrity": "sha512-LF03qURSwEWm2dz5wtdDCzNk+7Opl0X7q6I3undsaIuNsEiNvRV3BCtqu14Q/6Pzg1tBj44LcxpW2EpSLZStZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^4.0.0", + "ignore": "^7.0.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/@eslint-community/eslint-plugin-eslint-comments/node_modules/ignore": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", @@ -2080,7 +1914,8 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.3.tgz", "integrity": "sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@microsoft/eslint-plugin-sdl": { "version": "1.1.0", @@ -2564,9 +2399,9 @@ } }, "node_modules/@smithy/types": { - "version": "4.14.4", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.4.tgz", - "integrity": "sha512-B2S9+UGm1+/pHkcx3ZoLVX1a+pmSk8rqxRR+ZsNqZaJ5q9FWX9AFGQVM4qG5+OBeQUZVy99HY8HqW8gK/wgXzQ==", + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.17.2.tgz", + "integrity": "sha512-FOKpVZob9MPTn2znRzGrnsMHv7BOsKVw3XiP/cOyYLDVZ9qKp4nifIiSCuUU/fIj5Vu0UOAxCFr+qRAtG0NUkA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2889,7 +2724,6 @@ "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -2911,20 +2745,20 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", - "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.67.0.tgz", + "integrity": "sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/type-utils": "8.56.1", - "@typescript-eslint/utils": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", + "@typescript-eslint/scope-manager": "8.67.0", + "@typescript-eslint/type-utils": "8.67.0", + "@typescript-eslint/utils": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2934,9 +2768,9 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.56.1", + "@typescript-eslint/parser": "^8.67.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { @@ -2950,17 +2784,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", - "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.67.0.tgz", + "integrity": "sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", + "@typescript-eslint/scope-manager": "8.67.0", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0", "debug": "^4.4.3" }, "engines": { @@ -2972,18 +2805,18 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.3.tgz", - "integrity": "sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.67.0.tgz", + "integrity": "sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.59.3", - "@typescript-eslint/types": "^8.59.3", + "@typescript-eslint/tsconfig-utils": "^8.67.0", + "@typescript-eslint/types": "^8.67.0", "debug": "^4.4.3" }, "engines": { @@ -2997,29 +2830,15 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/project-service/node_modules/@typescript-eslint/types": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.3.tgz", - "integrity": "sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", - "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.67.0.tgz", + "integrity": "sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1" + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3030,9 +2849,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.3.tgz", - "integrity": "sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.67.0.tgz", + "integrity": "sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==", "dev": true, "license": "MIT", "engines": { @@ -3047,17 +2866,17 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", - "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.67.0.tgz", + "integrity": "sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0", + "@typescript-eslint/utils": "8.67.0", "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3068,13 +2887,13 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", - "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz", + "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==", "dev": true, "license": "MIT", "engines": { @@ -3086,61 +2905,22 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", - "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.67.0.tgz", + "integrity": "sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.56.1", - "@typescript-eslint/tsconfig-utils": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", + "@typescript-eslint/project-service": "8.67.0", + "@typescript-eslint/tsconfig-utils": "8.67.0", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", - "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.56.1", - "@typescript-eslint/types": "^8.56.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "ts-api-utils": "^2.5.0" }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", - "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", - "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -3149,7 +2929,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { @@ -3163,26 +2943,26 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.5" + "brace-expansion": "^5.0.8" }, "engines": { "node": "18 || 20 || >=22" @@ -3192,16 +2972,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", - "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.67.0.tgz", + "integrity": "sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1" + "@typescript-eslint/scope-manager": "8.67.0", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3212,17 +2992,17 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", - "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.67.0.tgz", + "integrity": "sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/types": "8.67.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -3397,7 +3177,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3810,7 +3589,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", @@ -3997,7 +3775,8 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.7.tgz", "integrity": "sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -4484,7 +4263,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -4566,7 +4344,6 @@ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -4918,12 +4695,13 @@ } }, "node_modules/eslint-plugin-obsidianmd": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-obsidianmd/-/eslint-plugin-obsidianmd-0.3.0.tgz", - "integrity": "sha512-QvGDI6B2nxJBrsZKGTg31da2A/fEJNlnwN+fRZkaoPIu1QL3fYXUdpP7ThyMdr/0iTYQxifb9lt2X9cpydQx1w==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-obsidianmd/-/eslint-plugin-obsidianmd-0.4.1.tgz", + "integrity": "sha512-Nv3593kVsFOS8kir/HWaJ5CR3xcyiPWEPyXst5Pib8mxRYYuLYPpJS2ALMoZXHulHyiGwoYW8AaxvLRc4rhrRg==", "dev": true, "license": "MIT", "dependencies": { + "@eslint-community/eslint-plugin-eslint-comments": "^4.7.2", "@eslint/config-helpers": "^0.4.2", "@eslint/js": "^9.30.1", "@eslint/json": "0.14.0", @@ -4932,7 +4710,7 @@ "@types/node": "20.12.12", "@typescript-eslint/types": "^8.33.1", "@typescript-eslint/utils": "^8.33.1", - "eslint": ">=9.0.0", + "eslint": ">=9.19.0", "eslint-plugin-depend": "1.3.1", "eslint-plugin-import": "^2.31.0", "eslint-plugin-json-schema-validator": "5.1.0", @@ -4945,181 +4723,42 @@ "typescript-eslint": "^8.35.1" }, "bin": { - "eslint-plugin-obsidian": "dist/lib/index.js" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@eslint/js": "^9.30.1", - "@eslint/json": "0.14.0", - "eslint": ">=9.0.0", - "obsidian": "1.8.7", - "typescript-eslint": "^8.35.1" - } - }, - "node_modules/eslint-plugin-obsidianmd/node_modules/@types/node": { - "version": "20.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", - "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/eslint-plugin-obsidianmd/node_modules/@typescript-eslint/scope-manager": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.3.tgz", - "integrity": "sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/visitor-keys": "8.59.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-obsidianmd/node_modules/@typescript-eslint/types": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.3.tgz", - "integrity": "sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-obsidianmd/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.3.tgz", - "integrity": "sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.59.3", - "@typescript-eslint/tsconfig-utils": "8.59.3", - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/visitor-keys": "8.59.3", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/eslint-plugin-obsidianmd/node_modules/@typescript-eslint/utils": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.3.tgz", - "integrity": "sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.59.3", - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/typescript-estree": "8.59.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/eslint-plugin-obsidianmd/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.3.tgz", - "integrity": "sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.59.3", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-obsidianmd/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", + "eslint-plugin-obsidian": "dist/lib/index.js" + }, "engines": { - "node": "18 || 20 || >=22" + "node": ">= 18" + }, + "peerDependencies": { + "@eslint/js": "^9.30.1", + "@eslint/json": "0.14.0", + "eslint": ">=9.19.0", + "obsidian": "1.8.7", + "typescript-eslint": "^8.35.1" } }, - "node_modules/eslint-plugin-obsidianmd/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "node_modules/eslint-plugin-obsidianmd/node_modules/@types/node": { + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/eslint-plugin-obsidianmd/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "undici-types": "~5.26.4" } }, - "node_modules/eslint-plugin-obsidianmd/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "node_modules/eslint-plugin-obsidianmd/node_modules/obsidian": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.12.3.tgz", + "integrity": "sha512-HxWqe763dOqzXjnNiHmAJTRERN8KILBSqxDSEqbeSr7W8R8Jxezzbca+nz1LiiqXnMpM8lV2jzAezw3CZ4xNUw==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" + "@types/codemirror": "5.60.8", + "moment": "2.29.4" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "@codemirror/state": "6.5.0", + "@codemirror/view": "6.38.6" } }, "node_modules/eslint-plugin-obsidianmd/node_modules/typescript": { @@ -5128,7 +4767,6 @@ "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7400,11 +7038,10 @@ } }, "node_modules/obsidian": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.12.3.tgz", - "integrity": "sha512-HxWqe763dOqzXjnNiHmAJTRERN8KILBSqxDSEqbeSr7W8R8Jxezzbca+nz1LiiqXnMpM8lV2jzAezw3CZ4xNUw==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/obsidian/-/obsidian-1.13.1.tgz", + "integrity": "sha512-qtTEA2pmhJzhuhJqzbBFRYhpIOqvW+krDYjtFynv66KbxBbumHBlsJfWw3I4jtnK/6fZwbQhCrmmDdRwXmX56w==", "license": "MIT", - "peer": true, "dependencies": { "@types/codemirror": "5.60.8", "moment": "2.29.4" @@ -7730,7 +7367,6 @@ "integrity": "sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "playwright-core": "1.61.1" }, @@ -7802,7 +7438,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", @@ -8642,7 +8277,8 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/supports-color": { "version": "7.2.0", @@ -8676,7 +8312,6 @@ "integrity": "sha512-w7JvrM5IFl5cmfbY0TLik9o7mjRUJmRMhOR51tBPu708Gr/MjbGs7VnJnr/B0CaXeI4vtnOh7RKxDr0cwhMdDA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", @@ -8741,6 +8376,21 @@ } } }, + "node_modules/svelte-check/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/svelte-eslint-parser": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-1.8.0.tgz", @@ -8950,7 +8600,6 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -9082,7 +8731,6 @@ "integrity": "sha512-eUdUIaCr963q2h5u3+QwvYp0+eqPvn+egeqZUm0hwERCqqx1E3kK5ehbGCvqSE5MQAULr67ww0cA3jKc3YkM1w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "~0.28.0" }, @@ -9217,12 +8865,11 @@ } }, "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9232,180 +8879,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.3.tgz", - "integrity": "sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.59.3", - "@typescript-eslint/parser": "8.59.3", - "@typescript-eslint/typescript-estree": "8.59.3", - "@typescript-eslint/utils": "8.59.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.3.tgz", - "integrity": "sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.59.3", - "@typescript-eslint/type-utils": "8.59.3", - "@typescript-eslint/utils": "8.59.3", - "@typescript-eslint/visitor-keys": "8.59.3", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.59.3", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.3.tgz", - "integrity": "sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@typescript-eslint/scope-manager": "8.59.3", - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/typescript-estree": "8.59.3", - "@typescript-eslint/visitor-keys": "8.59.3", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.3.tgz", - "integrity": "sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA==", + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.67.0.tgz", + "integrity": "sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/visitor-keys": "8.59.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.3.tgz", - "integrity": "sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/typescript-estree": "8.59.3", - "@typescript-eslint/utils": "8.59.3", - "debug": "^4.4.3", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.3.tgz", - "integrity": "sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.3.tgz", - "integrity": "sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.59.3", - "@typescript-eslint/tsconfig-utils": "8.59.3", - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/visitor-keys": "8.59.3", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.3.tgz", - "integrity": "sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.59.3", - "@typescript-eslint/types": "8.59.3", - "@typescript-eslint/typescript-estree": "8.59.3" + "@typescript-eslint/eslint-plugin": "8.67.0", + "@typescript-eslint/parser": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0", + "@typescript-eslint/utils": "8.67.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9419,86 +8902,6 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.3.tgz", - "integrity": "sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.59.3", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/typescript-eslint/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/typescript-eslint/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/typescript-eslint/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/typescript-eslint/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", @@ -9589,7 +8992,6 @@ "integrity": "sha512-Ds+gBRbj0lwRO2Y5hwnUBdxSwlAve9LeRyU4sNnAr0ewW0gWF0n5bgXgUzbgZ49MV9BVUAQUFYVcDUcilUExMA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", @@ -9701,7 +9103,6 @@ "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vitest/expect": "4.1.10", "@vitest/mocker": "4.1.10", @@ -9803,7 +9204,8 @@ "version": "2.2.8", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", diff --git a/package.json b/package.json index 2c3b809..80861e9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "diffzip", "version": "0.1.11", + "packageManager": "npm@10.9.4", "description": "Differential ZIP Backup", "main": "main.js", "scripts": { @@ -20,7 +21,8 @@ "pretty": "npm run prettyNoWrite -- --write --log-level error", "prettyCheck": "npm run prettyNoWrite -- --check", "prettyNoWrite": "prettier --config ./.prettierrc \"*.ts\" ", - "lint": "eslint src" + "lint": "eslint src", + "lint:community": "eslint --config eslint.community.config.mjs --concurrency off main.ts src" }, "keywords": [], "author": "vorotamoroz", @@ -33,22 +35,23 @@ "@smithy/fetch-http-handler": "^5.0.1", "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.17.2", "@sveltejs/vite-plugin-svelte": "^7.1.4", "@testing-library/svelte": "^5.4.2", "@testing-library/user-event": "^14.6.1", "@tsconfig/svelte": "^5.0.4", "@types/node": "^22.19.19", - "@typescript-eslint/eslint-plugin": "8.56.1", - "@typescript-eslint/parser": "^8.56.1", + "@typescript-eslint/eslint-plugin": "^8.67.0", + "@typescript-eslint/parser": "^8.67.0", "@vrtmrz/obsidian-test-session": "0.2.0", "esbuild": "0.28.1", "esbuild-svelte": "^0.9.5", "eslint": "^9.39.3", - "eslint-plugin-obsidianmd": "^0.3.0", + "eslint-plugin-obsidianmd": "^0.4.1", "eslint-plugin-svelte": "^3.15.0", "globals": "^14.0.0", "jsdom": "^29.1.1", - "obsidian": "^1.8.7", + "obsidian": "^1.13.1", "playwright": "^1.61.1", "prettier": "^3.5.3", "svelte": "^5.1.15", @@ -57,7 +60,8 @@ "svelte-preprocess": "^6.0.3", "tslib": "2.8.1", "tsx": "^4.23.0", - "typescript": "5.7.3", + "typescript": "^5.9.3", + "typescript-eslint": "^8.67.0", "vite": "^8.1.3", "vitest": "^4.1.10" }, diff --git a/src/CombinedFragment.ts b/src/CombinedFragment.ts index 21257bb..4226516 100644 --- a/src/CombinedFragment.ts +++ b/src/CombinedFragment.ts @@ -28,7 +28,7 @@ export class CombinedFragment { * @returns The combined DocumentFragment. */ buildFragment(fragments: (() => DocumentFragment)[]) { - const f = activeDocument.createDocumentFragment(); + const f = createFragment(); fragments.forEach(fragment => { f.appendChild(fragment()); }); diff --git a/src/DiffZipSettingTab.ts b/src/DiffZipSettingTab.ts index bfcbe5e..c25d733 100644 --- a/src/DiffZipSettingTab.ts +++ b/src/DiffZipSettingTab.ts @@ -1,10 +1,24 @@ -import { PluginSettingTab, type App, Setting, Notice } from "obsidian"; -import { encrypt, decrypt } from "octagonal-wheels/encryption.js"; +import { PluginSettingTab, type App, type ButtonComponent, Setting, Notice } from "obsidian"; import DiffZipBackupPlugin from "../main.ts"; import { askSelectString } from "./dialog.ts"; +import { decryptSettingsFromUri, encryptSettingsForUri } from "./legacySettingsCrypto.ts"; import { S3Bucket } from "./StorageAccessor/S3Bucket.ts"; import { AutoBackupType, type DiffZipBackupSettings } from "./types.ts"; +interface DestructiveButtonCompatibility { + setDestructive?: () => void; + setWarning: () => void; +} + +function setDestructiveButton(button: ButtonComponent): void { + const compatibleButton = button as unknown as DestructiveButtonCompatibility; + if (compatibleButton.setDestructive !== undefined) { + compatibleButton.setDestructive(); + } else { + compatibleButton.setWarning(); + } +} + export class DiffZipSettingTab extends PluginSettingTab { plugin: DiffZipBackupPlugin; @@ -14,6 +28,10 @@ export class DiffZipSettingTab extends PluginSettingTab { } display(): void { + this.renderSettings(); + } + + private renderSettings(): void { const { containerEl } = this; containerEl.empty(); new Setting(containerEl).setName("Basic").setHeading(); @@ -94,7 +112,7 @@ export class DiffZipSettingTab extends PluginSettingTab { this.plugin.settings.desktopFolderEnabled = value == "desktop"; this.plugin.settings.bucketEnabled = value == "s3"; await this.plugin.saveSettings(); - this.display(); + this.renderSettings(); }) ); @@ -182,8 +200,7 @@ export class DiffZipSettingTab extends PluginSettingTab { } else { new Notice("Connection is successful, aut bucket is missing"); } - } catch (ex) { - console.dir(ex); + } catch { new Notice("Connection failed"); } }) @@ -201,7 +218,6 @@ export class DiffZipSettingTab extends PluginSettingTab { } catch (ex) { const message = ex instanceof Error ? ex.message : String(ex); new Notice(`Bucket creation failed\n-----\n${message ?? "Unknown error"}`); - console.dir(ex); } }) ); @@ -302,14 +318,12 @@ export class DiffZipSettingTab extends PluginSettingTab { new Setting(containerEl) .setName("Reset Backup Information") .setDesc("After resetting, backup information will be lost.") - .addButton((button) => - button - .setWarning() - .setButtonText("Reset") - .onClick(async () => { - await this.plugin.resetToC(); - }) - ); + .addButton((button) => { + setDestructiveButton(button); + button.setButtonText("Reset").onClick(async () => { + await this.plugin.resetToC(); + }); + }); new Setting(containerEl) .setName("Encryption") .setDesc( @@ -348,9 +362,7 @@ export class DiffZipSettingTab extends PluginSettingTab { .addButton((button) => { button.setButtonText("Copy to Clipboard").onClick(async () => { const setting = JSON.stringify(this.plugin.settings); - // Compatibility with old versions - // eslint-disable-next-line @typescript-eslint/no-deprecated -- encrypt is deprecated but kept for backwards compatibility - const encrypted = await encrypt(setting, passphrase, false); + const encrypted = await encryptSettingsForUri(setting, passphrase); const uri = `obsidian://diffzip/settings?data=${encodeURIComponent(encrypted)}`; await navigator.clipboard.writeText(uri); new Notice("URI has been copied to the clipboard"); @@ -370,14 +382,12 @@ export class DiffZipSettingTab extends PluginSettingTab { }) .addButton((button) => { button.setButtonText("Apply"); - button.setWarning(); + setDestructiveButton(button); button.onClick(async () => { const uri = copiedURI; const data = decodeURIComponent(uri.split("?data=")[1]); try { - // Compatibility with old versions - // eslint-disable-next-line @typescript-eslint/no-deprecated -- decrypt is deprecated but kept for backwards compatibility - const decrypted = await decrypt(data, passphrase, false); + const decrypted = await decryptSettingsFromUri(data, passphrase); const settings = JSON.parse(decrypted) as DiffZipBackupSettings; if ( (await askSelectString(this.app, "Are you sure to overwrite the settings?", [ @@ -387,13 +397,12 @@ export class DiffZipSettingTab extends PluginSettingTab { ) { Object.assign(this.plugin.settings, settings); await this.plugin.saveSettings(); - this.display(); + this.renderSettings(); } else { new Notice("Cancelled"); } - } catch (e) { + } catch { new Notice("Failed to decrypt the settings"); - console.warn(e); } }); }); diff --git a/src/ObsHttpHandler.ts b/src/ObsHttpHandler.ts index 683182c..05347f2 100644 --- a/src/ObsHttpHandler.ts +++ b/src/ObsHttpHandler.ts @@ -1,20 +1,43 @@ -/* eslint-disable @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-deprecated -- This file is based on an external library (remotely-save) and uses legacy/untyped APIs */ -// deno-lint-ignore-file // This file is based on a file that was published by the @remotely-save, under the Apache 2 License. // I would love to express my deepest gratitude to the original authors for their hard work and dedication. Without their contributions, this project would not have been possible. // // Original Implementation is here: https://github.com/remotely-save/remotely-save/blob/28b99557a864ef59c19d2ad96101196e401718f0/src/remoteForS3.ts import { FetchHttpHandler, type FetchHttpHandlerOptions } from "@smithy/fetch-http-handler"; -import { HttpRequest, HttpResponse, type HttpHandlerOptions } from "@smithy/protocol-http"; -//@ts-ignore -import { requestTimeout } from "@smithy/fetch-http-handler/dist-es/request-timeout"; +import { HttpRequest, HttpResponse } from "@smithy/protocol-http"; import { buildQueryString } from "@smithy/querystring-builder"; +import type { HttpHandlerOptions } from "@smithy/types"; import { requestUrl, type RequestUrlParam } from "obsidian"; + //////////////////////////////////////////////////////////////////////////////// // special handler using Obsidian requestUrl //////////////////////////////////////////////////////////////////////////////// +function requestTimeout(timeoutInMs: number = 0): Promise { + return new Promise((_, reject) => { + if (timeoutInMs) { + window.setTimeout(() => { + const timeoutError = new Error(`Request did not complete within ${timeoutInMs} ms`); + timeoutError.name = "TimeoutError"; + reject(timeoutError); + }, timeoutInMs); + } + }); +} + +function normaliseRequestBody(body: unknown): string | ArrayBuffer | undefined { + if (body === undefined) return undefined; + if (typeof body === "string" || body instanceof ArrayBuffer) return body; + if (ArrayBuffer.isView(body)) { + if (body.buffer instanceof ArrayBuffer && body.byteOffset === 0 && body.byteLength === body.buffer.byteLength) { + return body.buffer; + } + return new Uint8Array(body.buffer, body.byteOffset, body.byteLength).slice().buffer; + } + const bodyType = typeof body === "object" && body !== null ? body.constructor.name : typeof body; + throw new TypeError(`Obsidian requestUrl does not support the request body type ${bodyType}`); +} + /** * This is close to origin implementation of FetchHttpHandler * https://github.com/aws/aws-sdk-js-v3/blob/main/packages/fetch-http-handler/src/fetch-http-handler.ts @@ -29,7 +52,10 @@ export class ObsHttpHandler extends FetchHttpHandler { this.requestTimeoutInMs = options === undefined ? undefined : options.requestTimeout; this.reverseProxyNoSignUrl = reverseProxyNoSignUrl; } - async handle(request: HttpRequest, { abortSignal }: HttpHandlerOptions = {}): Promise<{ response: HttpResponse }> { + override async handle( + request: HttpRequest, + { abortSignal }: HttpHandlerOptions = {} + ): Promise<{ response: HttpResponse }> { if (abortSignal?.aborted) { const abortError = new Error("Request aborted"); abortError.name = "AbortError"; @@ -51,7 +77,7 @@ export class ObsHttpHandler extends FetchHttpHandler { urlObj.host = this.reverseProxyNoSignUrl; url = urlObj.href; } - const body = method === "GET" || method === "HEAD" ? undefined : request.body; + const body: unknown = method === "GET" || method === "HEAD" ? undefined : request.body; const transformedHeaders: Record = {}; for (const key of Object.keys(request.headers)) { @@ -67,10 +93,7 @@ export class ObsHttpHandler extends FetchHttpHandler { contentType = transformedHeaders["content-type"]; } - let transformedBody: any = body; - if (ArrayBuffer.isView(body)) { - transformedBody = new Uint8Array(body.buffer).buffer; - } + const transformedBody = normaliseRequestBody(body); const param: RequestUrlParam = { body: transformedBody, diff --git a/src/ProgressFragment.ts b/src/ProgressFragment.ts index ad28c19..e15555d 100644 --- a/src/ProgressFragment.ts +++ b/src/ProgressFragment.ts @@ -303,24 +303,24 @@ export class ProgressFragment { * @returns The constructed DocumentFragment. */ constructFragment() { - const f = activeDocument.createDocumentFragment(); - const d = activeDocument.createElement("div"); + const f = createFragment(); + const d = f.createDiv(); d.classList.add("diffzip-progress-wrap"); - const titleLine = activeDocument.createElement("div"); + const titleLine = d.createDiv(); titleLine.classList.add("diffzip-progress-title-line"); - const lbl = activeDocument.createElement("label"); + const lbl = titleLine.createEl("label"); lbl.classList.add("diffzip-progress-title"); this._titleEl = lbl; - const numeric = activeDocument.createElement("span"); + const numeric = titleLine.createSpan(); numeric.classList.add("diffzip-progress-numeric"); this._numericStatusEl = numeric; titleLine.appendChild(lbl); titleLine.appendChild(numeric); d.appendChild(titleLine); - const p = activeDocument.createElement("progress"); + const p = d.createEl("progress"); p.classList.add("diffzip-progress-bar"); this._progressEl = p; - this._noteEl = activeDocument.createElement("span"); + this._noteEl = d.createSpan(); this._noteEl.classList.add("diffzip-progress-note"); d.appendChild(p); d.appendChild(this._noteEl); diff --git a/src/StorageAccessor/DirectVault.ts b/src/StorageAccessor/DirectVault.ts index 9ee770a..110c1e9 100644 --- a/src/StorageAccessor/DirectVault.ts +++ b/src/StorageAccessor/DirectVault.ts @@ -28,8 +28,7 @@ export class DirectVault extends StorageAccessor { try { await this.app.vault.adapter.writeBinary(path, data); return true; - } catch (e) { - console.error(e); + } catch { return false; } } @@ -44,8 +43,7 @@ export class DirectVault extends StorageAccessor { if (!(await this.isFileExists(path))) return true; await this.app.vault.adapter.remove(path); return true; - } catch (e) { - console.error(e); + } catch { return false; } } diff --git a/src/StorageAccessor/ExternalVaultFilesystem.ts b/src/StorageAccessor/ExternalVaultFilesystem.ts index ad7b0b5..ac78e24 100644 --- a/src/StorageAccessor/ExternalVaultFilesystem.ts +++ b/src/StorageAccessor/ExternalVaultFilesystem.ts @@ -1,23 +1,45 @@ import type { Stat } from "obsidian"; -// eslint-disable-next-line import/no-nodejs-modules -- Electron exposes the Node filesystem API used here. -import type { promises } from "node:fs"; import { StorageAccessor } from "./StorageAccessor.ts"; import { FileType, StorageAccessorTypes } from "./storage-accessor-types.ts"; import { toArrayBuffer } from "../util.ts"; -type FsAPI = Pick; +type DesktopPathAPI = { + sep: string; + normalize: (path: string) => string; + resolve: (...paths: string[]) => string; +}; + +type DesktopFileStat = { + isDirectory: () => boolean; + isFile: () => boolean; +}; + +type FsAPI = { + mkdir: (path: string, options: { recursive: true }) => Promise; + writeFile: (path: string, data: Uint8Array) => Promise; + readFile: (path: string) => Promise>; + stat: (path: string) => Promise; + rm: (path: string, options: { force: true }) => Promise; +}; + +type DesktopFileSystemAdapter = { + path: DesktopPathAPI; + basePath: string; + fsPromises: FsAPI; +}; export class ExternalVaultFilesystem extends StorageAccessor { type = StorageAccessorTypes.EXTERNAL; + private get desktopAdapter(): DesktopFileSystemAdapter { + return this.app.vault.adapter as unknown as DesktopFileSystemAdapter; + } + get sep(): string { - //@ts-ignore internal API - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- internal API access - return this.app.vault.adapter.path.sep as string; + return this.desktopAdapter.path.sep; } get fsPromises(): FsAPI { - //@ts-ignore internal API - return this.app.vault.adapter.fsPromises as FsAPI; + return this.desktopAdapter.fsPromises; } async createFolder(absolutePath: string): Promise { @@ -34,11 +56,9 @@ export class ExternalVaultFilesystem extends StorageAccessor { async _writeBinary(fullPath: string, data: ArrayBuffer) { try { - // eslint-disable-next-line no-undef -- Buffer is global in Node/Electron environment - await this.fsPromises.writeFile(fullPath, Buffer.from(data)); + await this.fsPromises.writeFile(fullPath, new Uint8Array(data)); return true; - } catch (e) { - console.error(e); + } catch { return false; } } @@ -52,8 +72,7 @@ export class ExternalVaultFilesystem extends StorageAccessor { try { await this.fsPromises.rm(path, { force: true }); return true; - } catch (e) { - console.error(e); + } catch { return false; } } @@ -72,17 +91,9 @@ export class ExternalVaultFilesystem extends StorageAccessor { } normalizePath(path: string): string { - //@ts-ignore internal API - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- internal API access - const f = this.app.vault.adapter.path; - //@ts-ignore internal API - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- internal API access - const basePath = this.app.vault.adapter.basePath; - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access -- internal API access + const { path: f, basePath } = this.desktopAdapter; const normalizedPath = f.normalize(path); - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access -- internal API access - const result = f.resolve(basePath, normalizedPath); - return result as string; + return f.resolve(basePath, normalizedPath); } async stat(_path: string): Promise { diff --git a/src/StorageAccessor/NormalVault.ts b/src/StorageAccessor/NormalVault.ts index a82dff1..17ce6a1 100644 --- a/src/StorageAccessor/NormalVault.ts +++ b/src/StorageAccessor/NormalVault.ts @@ -36,8 +36,7 @@ export class NormalVault extends StorageAccessor { await this.app.vault.modifyBinary(af, data); return true; } - } catch (e) { - console.error(e); + } catch { return false; } throw new Error("Folder exists with the same name."); @@ -57,8 +56,7 @@ export class NormalVault extends StorageAccessor { return true; } return false; - } catch (e) { - console.error(e); + } catch { return false; } } diff --git a/src/StorageAccessor/S3Bucket.ts b/src/StorageAccessor/S3Bucket.ts index 63e4ea3..3869dbd 100644 --- a/src/StorageAccessor/S3Bucket.ts +++ b/src/StorageAccessor/S3Bucket.ts @@ -58,14 +58,8 @@ export class S3Bucket extends StorageAccessor { Key: fullPath, Body: new Uint8Array(data), }); - if (~~((r.$metadata.httpStatusCode ?? 500) / 100) == 2) { - return true; - } else { - console.error(`Failed to write binary to ${fullPath} (response code:${r.$metadata.httpStatusCode}).`); - } - return false; - } catch (e) { - console.error(e); + return ~~((r.$metadata.httpStatusCode ?? 500) / 100) == 2; + } catch { return false; } } @@ -90,8 +84,7 @@ export class S3Bucket extends StorageAccessor { Key: path, }); return true; - } catch (e) { - console.error(e); + } catch { return false; } } diff --git a/src/SyncEngine.test.ts b/src/SyncEngine.test.ts index 35beaa8..d1f98ef 100644 --- a/src/SyncEngine.test.ts +++ b/src/SyncEngine.test.ts @@ -364,19 +364,12 @@ Deno.test("executeSend: oversized file is placed in solo ZIP and reported", asyn vault.addFile("huge.md", "0123456789", BASE_MTIME + 1000); const backup = new MemoryBackup(); - const warn = console.warn; - let result!: Awaited>; - try { - console.warn = () => {}; - result = await executeSend( - [sendItem("small.md"), sendItem("huge.md")], vault, backup, - async () => ({}), - makeZipName, - { ...defaultOptions, maxTotalSizeInZip: 6 }, - ); - } finally { - console.warn = warn; - } + const result = await executeSend( + [sendItem("small.md"), sendItem("huge.md")], vault, backup, + async () => ({}), + makeZipName, + { ...defaultOptions, maxTotalSizeInZip: 6 }, + ); assertEquals(result.sentCount, 2, "Both files should be sent"); assertEquals(result.oversizedFiles, ["huge.md"], "Huge file should be reported as oversized"); diff --git a/src/SyncEngine.ts b/src/SyncEngine.ts index d7d97a5..ac9f849 100644 --- a/src/SyncEngine.ts +++ b/src/SyncEngine.ts @@ -4,7 +4,7 @@ */ import { Archiver } from "./Archive.ts"; -import { computeDigest, humanReadableSize, pieces, toArrayBuffer } from "./util.ts"; +import { computeDigest, pieces, toArrayBuffer } from "./util.ts"; import { InfoFile, type FileInfos } from "./types.ts"; import { applySendBatchToToc, @@ -49,8 +49,6 @@ export type SyncEngineOptions = { maxSize: number; // bytes for ZIP split (0 = no split) /** Serialize an object as YAML text. Defaults to JSON.stringify for testability. */ serializeYaml?: (obj: unknown) => string; - /** Emit verbose execution logs for fetch/send update flow. */ - debugExecutionToConsole?: boolean; }; // ── executeFetch ─────────────────────────────────────────────────── @@ -65,7 +63,6 @@ export async function executeFetch( extractor: ZipExtractAdapter, vaultDelete: VaultDeleteAdapter, onProgress?: (note: string) => void, - debugExecutionToConsole = false, ): Promise { const zipFileMap = new Map(); const deleteFiles: string[] = []; @@ -80,69 +77,29 @@ export async function executeFetch( } } - if (debugExecutionToConsole) { - console.log("[DiffZip][SyncExec][Fetch] start", { - totalItems: fetchItems.length, - extractZipCount: zipFileMap.size, - deleteCount: deleteFiles.length, - items: fetchItems.map((i) => ({ - filename: i.filename, - operation: i.operation, - action: i.action, - zipName: i.zipName, - })), - }); - } - let done = 0; const failed: string[] = []; for (const [zipName, files] of zipFileMap) { onProgress?.(`Extracting ${zipName}`); - if (debugExecutionToConsole) { - console.log("[DiffZip][SyncExec][Fetch] extracting", { zipName, files }); - } try { await extractor.extract(zipName, files); done += files.length; - if (debugExecutionToConsole) { - console.log("[DiffZip][SyncExec][Fetch] extracted", { zipName, files, done }); - } - } catch (e) { + } catch { failed.push(...files); - if (debugExecutionToConsole) { - console.warn("[DiffZip][SyncExec][Fetch] extract failed", { - zipName, - files, - error: e instanceof Error ? e.message : String(e), - }); - } } } for (const filename of deleteFiles) { onProgress?.(`Deleting ${filename}`); - if (debugExecutionToConsole) { - console.log("[DiffZip][SyncExec][Fetch] deleting", { filename }); - } try { await vaultDelete.deleteLocal(filename); done++; - if (debugExecutionToConsole) { - console.log("[DiffZip][SyncExec][Fetch] deleted", { filename, done }); - } } catch { failed.push(filename); - if (debugExecutionToConsole) { - console.warn("[DiffZip][SyncExec][Fetch] delete failed", { filename }); - } } } - if (debugExecutionToConsole) { - console.log("[DiffZip][SyncExec][Fetch] done", { done, failed }); - } - return { done, failed }; } @@ -162,8 +119,6 @@ export async function executeSend( options: SyncEngineOptions, onProgress?: (note: string) => void, ): Promise { - const debugExecutionToConsole = options.debugExecutionToConsole === true; - type PreparedFile = { filename: string; content: Uint8Array; @@ -176,22 +131,10 @@ export async function executeSend( const preparedMissing: { filename: string; modifiedTime: number }[] = []; for (const item of sendItems) { - if (debugExecutionToConsole) { - console.log("[DiffZip][SyncExec][Send] preparing", { - filename: item.filename, - operation: item.operation, - action: item.action, - }); - } const normalized = vault.normalizePath(item.filename); const stat = await vault.stat(normalized); if (!stat) { preparedMissing.push({ filename: item.filename, modifiedTime: Date.now() }); - if (debugExecutionToConsole) { - console.warn("[DiffZip][SyncExec][Send] local stat missing -> mark missing", { - filename: item.filename, - }); - } continue; } const content = await vault.readBinary(normalized); @@ -199,14 +142,6 @@ export async function executeSend( const bytes = new Uint8Array(content); const digest = await computeDigest(bytes); preparedFiles.push({ filename: item.filename, content: bytes, digest, mtime: stat.mtime, size: bytes.byteLength }); - if (debugExecutionToConsole) { - console.log("[DiffZip][SyncExec][Send] prepared", { - filename: item.filename, - mtime: stat.mtime, - size: bytes.byteLength, - digest, - }); - } } const maxTotalSizeInZip = options.maxTotalSizeInZip; @@ -215,34 +150,10 @@ export async function executeSend( options.maxFilesInZip, maxTotalSizeInZip, ); - if (oversizedFiles.length > 0) { - const oversizedList = oversizedFiles - .map((filename) => { - const file = preparedFiles.find((entry) => entry.filename === filename); - return file ? `${filename} (${humanReadableSize(file.size)})` : filename; - }) - .join(", "); - console.warn(`⚠️ Oversized files placed in solo ZIPs: ${oversizedList}`); - } const preparedFileByPath = new Map(preparedFiles.map((f) => [f.filename, f] as const)); const effectiveBatches = batches.length > 0 ? batches : [{ files: [], totalSize: 0 }]; - if (debugExecutionToConsole) { - console.log("[DiffZip][SyncExec][Send] planned", { - sendItemCount: sendItems.length, - preparedFileCount: preparedFiles.length, - preparedMissingCount: preparedMissing.length, - batchCount: effectiveBatches.length, - oversizedFiles, - batches: effectiveBatches.map((b, i) => ({ - index: i, - totalSize: b.totalSize, - files: b.files.map((f) => f.filename), - })), - }); - } - let toc = await loadToc(); let sentCount = 0; @@ -266,15 +177,6 @@ export async function executeSend( } } - if (debugExecutionToConsole) { - console.log("[DiffZip][SyncExec][Send] batch start", { - index, - zipName, - files: zippedFiles.map((f) => f.filename), - updateCount: updates.length, - }); - } - const nextToc = applySendBatchToToc(toc, updates, zipName, processedAt) satisfies TocMap; // Write ZIP (with splitting) @@ -296,24 +198,10 @@ export async function executeSend( throw new Error(`TOC update failed after writing ${zipName}. ZIP files rolled back.`); } - if (debugExecutionToConsole) { - console.log("[DiffZip][SyncExec][Send] batch done", { - index, - zipName, - writtenFiles, - tocFilePath, - tocSaved, - }); - } - toc = nextToc; sentCount += updates.length; } - if (debugExecutionToConsole) { - console.log("[DiffZip][SyncExec][Send] done", { sentCount, oversizedFiles }); - } - return { sentCount, oversizedFiles }; } diff --git a/src/SyncPlanner.ts b/src/SyncPlanner.ts index 6165c49..be858eb 100644 --- a/src/SyncPlanner.ts +++ b/src/SyncPlanner.ts @@ -147,7 +147,6 @@ export type BuildSyncItemsOptions = { ignoreHidden?: boolean; ignorePatterns?: string[]; mtimeToleranceMs?: number; - debugDiffToConsole?: boolean; }; export function buildSyncItems( @@ -161,7 +160,6 @@ export function buildSyncItems( ignoreHidden = false, ignorePatterns = [], mtimeToleranceMs = 0, - debugDiffToConsole = false, } = options; const shouldIgnore = (filename: string): boolean => { @@ -187,16 +185,9 @@ export function buildSyncItems( const latest = history[0]; const isRemoteMissing = fileInfo.missing === true; const localInfo = localFileMap.get(filename); - const fallbackHistoryDigest = history.find((h) => !!h.digest)?.digest ?? ""; - const topLevelDigest = fileInfo.digest ?? ""; - const remoteDigest = latest.digest || fallbackHistoryDigest || topLevelDigest; - const remoteDigestSource = latest.digest - ? "latest" - : fallbackHistoryDigest - ? "history-fallback" - : topLevelDigest - ? "toc" - : "missing"; + const fallbackHistoryDigest = history.find((h) => !!h.digest)?.digest ?? ""; + const topLevelDigest = fileInfo.digest ?? ""; + const remoteDigest = latest.digest || fallbackHistoryDigest || topLevelDigest; let operation: SyncOperation | undefined; @@ -219,34 +210,6 @@ export function buildSyncItems( const defaultAction = getDefaultAction(operation, { destructiveDefaultsEnabled }); const action = isActionAllowed(operation, defaultAction) ? defaultAction : "None"; items.push({ filename, operation, zipName: latest.zipName, modified: latest.modified, action, allowedActions, defaultAction }); - - if (debugDiffToConsole && operation !== "Same") { - const remoteMtime = new Date(latest.modified).getTime(); - const localMtime = localInfo?.mtime ?? null; - const mtimeDiff = localMtime == null ? null : remoteMtime - localMtime; - console.log("[DiffZip][SyncDiff]", { - filename, - operation, - action, - remote: { - zipName: latest.zipName, - modified: latest.modified, - mtime: remoteMtime, - digest: remoteDigest, - digestSource: remoteDigestSource, - rawLatestDigest: latest.digest, - missing: isRemoteMissing, - }, - local: localInfo - ? { - mtime: localInfo.mtime, - digest: localInfo.digest, - } - : null, - mtimeDiff, - mtimeToleranceMs, - }); - } } } @@ -259,18 +222,6 @@ export function buildSyncItems( const defaultAction = getDefaultAction(operation, { destructiveDefaultsEnabled }); const action = isActionAllowed(operation, defaultAction) ? defaultAction : "None"; items.push({ filename, operation, zipName: "", modified: "", action, allowedActions, defaultAction }); - - if (debugDiffToConsole) { - console.log("[DiffZip][SyncDiff]", { - filename, - operation, - action, - remote: null, - local: localFileMap.get(filename) ?? null, - mtimeDiff: null, - mtimeToleranceMs, - }); - } } } diff --git a/src/SyncRemoteDialog.ts b/src/SyncRemoteDialog.ts index e496049..6cbbd80 100644 --- a/src/SyncRemoteDialog.ts +++ b/src/SyncRemoteDialog.ts @@ -15,9 +15,6 @@ import { executeFetch, executeSend } from "./SyncEngine.ts"; export type { SyncAction, SyncItem, SyncOperation } from "./SyncPlanner.ts"; -declare const __DIFFZIP_DEBUG__: boolean; -const DEBUG_SYNC_LOG = __DIFFZIP_DEBUG__; - const OP_ORDER: Record = { Conflict: 0, Add: 1, @@ -102,7 +99,6 @@ export class SyncRemoteDialog extends Modal { ignoreHidden: !this.plugin.settings.includeHiddenFolder, ignorePatterns, mtimeToleranceMs: 2000, - debugDiffToConsole: DEBUG_SYNC_LOG, }); items.sort((a, b) => { const oDiff = OP_ORDER[a.operation] - OP_ORDER[b.operation]; @@ -234,7 +230,6 @@ export class SyncRemoteDialog extends Modal { progress.note = note; progress.value = ++done; }, - DEBUG_SYNC_LOG, ); progressNotice.hide(); @@ -248,7 +243,7 @@ export class SyncRemoteDialog extends Modal { async applySend(sendItems: SyncItem[]) { return await this.plugin.runWhileAwake("selective-sync-send", async () => { - const { sentCount } = await executeSend( + const { sentCount, oversizedFiles } = await executeSend( sendItems, this.plugin.vaultAccess, this.plugin.backups, @@ -267,9 +262,11 @@ export class SyncRemoteDialog extends Modal { ? this.plugin.settings.maxSize * 1024 * 1024 : 0, serializeYaml: stringifyYaml, - debugExecutionToConsole: DEBUG_SYNC_LOG, }, ); + if (oversizedFiles.length > 0) { + new Notice(`Oversized files were placed in separate ZIPs: ${oversizedFiles.join(", ")}`); + } return sentCount; }); } diff --git a/src/legacySettingsCrypto.ts b/src/legacySettingsCrypto.ts new file mode 100644 index 0000000..42cbc68 --- /dev/null +++ b/src/legacySettingsCrypto.ts @@ -0,0 +1,19 @@ +import * as legacyEncryptionModule from "octagonal-wheels/encryption.js"; + +type LegacySettingsCrypto = { + encrypt: (input: string, passphrase: string, autoCalculateIterations: boolean) => Promise; + decrypt: (encryptedResult: string, passphrase: string, autoCalculateIterations: boolean) => Promise; +}; + +// Settings URIs predate octagonal-wheels' HKDF format. Keep their wire format +// behind one typed compatibility boundary so existing URIs and older devices +// continue to interoperate without spreading deprecated API use through the UI. +const legacySettingsCrypto = legacyEncryptionModule as unknown as LegacySettingsCrypto; + +export function encryptSettingsForUri(settings: string, passphrase: string): Promise { + return legacySettingsCrypto.encrypt(settings, passphrase, false); +} + +export function decryptSettingsFromUri(encryptedSettings: string, passphrase: string): Promise { + return legacySettingsCrypto.decrypt(encryptedSettings, passphrase, false); +} diff --git a/src/types.ts b/src/types.ts index 6f465f2..3340e3c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -69,7 +69,7 @@ export type FileInfo = { export type FileInfos = Record; export type NoticeWithTimer = { notice: Notice; - timer?: ReturnType | number; + timer?: number; }; diff --git a/tests/ui/ObsHttpHandler.test.ts b/tests/ui/ObsHttpHandler.test.ts new file mode 100644 index 0000000..398ee34 --- /dev/null +++ b/tests/ui/ObsHttpHandler.test.ts @@ -0,0 +1,60 @@ +import { HttpRequest } from "@smithy/protocol-http"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const requestUrlMock = vi.hoisted(() => + vi.fn< + (param: { body?: string | ArrayBuffer }) => Promise<{ + headers: Record; + status: number; + arrayBuffer: ArrayBuffer; + }> + >() +); + +vi.mock("obsidian", () => ({ + requestUrl: requestUrlMock, +})); + +import { ObsHttpHandler } from "../../src/ObsHttpHandler.ts"; + +function requestWithBody(body: unknown) { + return new HttpRequest({ + protocol: "https:", + hostname: "objects.example.com", + method: "PUT", + path: "/bucket/object", + headers: {}, + body, + }); +} + +describe("ObsHttpHandler request bodies", () => { + beforeEach(() => { + requestUrlMock.mockReset(); + requestUrlMock.mockResolvedValue({ + headers: {}, + status: 200, + arrayBuffer: new ArrayBuffer(0), + }); + }); + + it("sends only the bytes addressed by an ArrayBuffer view", async () => { + const body = new Uint8Array([0, 1, 2, 3]).subarray(1, 3); + + await new ObsHttpHandler().handle(requestWithBody(body)); + + expect(requestUrlMock).toHaveBeenCalledOnce(); + const transmittedBody = requestUrlMock.mock.calls[0][0].body; + expect(transmittedBody).toBeInstanceOf(ArrayBuffer); + expect([...new Uint8Array(transmittedBody as ArrayBuffer)]).toEqual([1, 2]); + }); + + it("rejects an unsupported body instead of dispatching an empty request", async () => { + const body = new ReadableStream(); + + await expect(new ObsHttpHandler().handle(requestWithBody(body))).rejects.toThrow( + "Obsidian requestUrl does not support the request body type ReadableStream" + ); + expect(requestUrlMock).not.toHaveBeenCalled(); + }); +}); diff --git a/tests/ui/legacySettingsCrypto.test.ts b/tests/ui/legacySettingsCrypto.test.ts new file mode 100644 index 0000000..2e065a0 --- /dev/null +++ b/tests/ui/legacySettingsCrypto.test.ts @@ -0,0 +1,22 @@ +import { describe, expect, it } from "vitest"; +import { decryptSettingsFromUri, encryptSettingsForUri } from "../../src/legacySettingsCrypto.ts"; + +const LEGACY_SETTINGS_FIXTURE = + "%7193d00f753372827c6e9fed01000000e006fa31ccd6923b7a5ef4e9fd692254tKGMX2fYsXsvRD+EVOwk2nLov2XOKkubI5C6tLIWmMpBTcJiuwudviTehFs="; + +describe("legacy settings URI encryption", () => { + it("decrypts settings produced by an earlier DiffZip release", async () => { + await expect(decryptSettingsFromUri(LEGACY_SETTINGS_FIXTURE, "compat-passphrase")).resolves.toBe( + '{"startBackupAtLaunch":true}' + ); + }); + + it("keeps newly copied settings compatible with the legacy URI format", async () => { + const settings = '{"backupFolderMobile":"backup"}'; + + const encrypted = await encryptSettingsForUri(settings, "roundtrip-passphrase"); + + expect(encrypted.startsWith("%") || encrypted.startsWith("[")).toBe(true); + await expect(decryptSettingsFromUri(encrypted, "roundtrip-passphrase")).resolves.toBe(settings); + }); +}); diff --git a/tests/ui/obsidianMock.ts b/tests/ui/obsidianMock.ts new file mode 100644 index 0000000..3297a9c --- /dev/null +++ b/tests/ui/obsidianMock.ts @@ -0,0 +1,3 @@ +export async function requestUrl(): Promise { + throw new Error("The Obsidian requestUrl test mock was not configured"); +} diff --git a/vitest.config.ts b/vitest.config.ts index 46590d3..a77a659 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,9 +1,15 @@ import { svelte } from "@sveltejs/vite-plugin-svelte"; import { svelteTesting } from "@testing-library/svelte/vite"; import { defineConfig } from "vitest/config"; +import { fileURLToPath } from "node:url"; export default defineConfig({ plugins: [svelte(), svelteTesting()], + resolve: { + alias: { + obsidian: fileURLToPath(new URL("./tests/ui/obsidianMock.ts", import.meta.url)), + }, + }, test: { environment: "jsdom", include: ["tests/ui/**/*.test.ts"],