reduce no-explicit-any

This commit is contained in:
vorotamoroz
2026-06-09 05:59:02 +01:00
parent 0856693aac
commit 54c2b1c6db
43 changed files with 230 additions and 170 deletions
+35 -2
View File
@@ -19,11 +19,15 @@ const packageJson = JSON.parse(fs.readFileSync("./package.json") + "");
const updateInfo = JSON.stringify(fs.readFileSync("./updates.md") + ""); const updateInfo = JSON.stringify(fs.readFileSync("./updates.md") + "");
const PATHS_TEST_INSTALL = process.env?.PATHS_TEST_INSTALL || ""; const PATHS_TEST_INSTALL = process.env?.PATHS_TEST_INSTALL || "";
const PATH_TEST_INSTALL = PATHS_TEST_INSTALL.split(path.delimiter).map(p => p.trim()).filter(p => p.length); const PATH_TEST_INSTALL = PATHS_TEST_INSTALL.split(path.delimiter)
.map((p) => p.trim())
.filter((p) => p.length);
if (PATH_TEST_INSTALL) { if (PATH_TEST_INSTALL) {
console.log(`Built files will be copied to ${PATH_TEST_INSTALL}`); console.log(`Built files will be copied to ${PATH_TEST_INSTALL}`);
} else { } else {
console.log("Development build: You can install the plug-in to Obsidian for testing by exporting the PATHS_TEST_INSTALL environment variable with the paths to your vault plugins directories separated by your system path delimiter (':' on Unix, ';' on Windows)."); console.log(
"Development build: You can install the plug-in to Obsidian for testing by exporting the PATHS_TEST_INSTALL environment variable with the paths to your vault plugins directories separated by your system path delimiter (':' on Unix, ';' on Windows)."
);
} }
const moduleAliasPlugin = { const moduleAliasPlugin = {
@@ -66,6 +70,34 @@ const moduleAliasPlugin = {
}, },
}; };
const removePragmaCommentsPlugin = {
name: "remove-pragma-comments",
setup(build) {
// Filter target extensions (e.g., JavaScript and TypeScript)
build.onLoad({ filter: /\.[jt]s?$/ }, async (args) => {
const source = await fs.promises.readFile(args.path, "utf8");
// Regex targeting both single-line and multi-line comments
// This regex looks for:
// - /* eslint ... */ (multi-line)
// const esLintPragmaRegexBlock = /\/\*[\s\S]*?eslint[\s\S]*?\*\/|([^\\:]|^)\/\/.*eslint.*$/gm;
// - // eslint-disable-next-line
let cleanedSource = source;
const tsIgnoreRegex = /\/\*\s*@ts-ignore\s*\*\/|([^\\:]|^)\/\/.*?@ts-ignore.*$/gm;
const esLintPragmaRegexLine = /([^\\:]|^)\/\/.*?eslint-.*$/gm;
const exps = [tsIgnoreRegex, esLintPragmaRegexLine];
for (const exp of exps) {
cleanedSource = cleanedSource.replace(exp, "$1");
}
return {
contents: cleanedSource,
loader: args.path.endsWith("ts") ? "ts" : "js",
};
});
},
};
/** @type esbuild.Plugin[] */ /** @type esbuild.Plugin[] */
const plugins = [ const plugins = [
{ {
@@ -177,6 +209,7 @@ const context = await esbuild.context({
preprocess: sveltePreprocess(), preprocess: sveltePreprocess(),
compilerOptions: { css: "injected", preserveComments: false }, compilerOptions: { css: "injected", preserveComments: false },
}), }),
removePragmaCommentsPlugin,
...plugins, ...plugins,
], ],
}); });
+2 -1
View File
@@ -73,11 +73,12 @@ export default defineConfig([
"no-unused-labels": "off", "no-unused-labels": "off",
"no-prototype-builtins": "off", "no-prototype-builtins": "off",
"require-await": "off", "require-await": "off",
// -- TypeScript specific rules (Gradual adoption of stricter rules, currently set to 'warn' for a while).
"@typescript-eslint/no-explicit-any": "warn",
// -- TypeScript specific rules // -- TypeScript specific rules
// @typescript-eslint/no-unsafe-* rules and @typescript-eslint/no-explicit-any: // @typescript-eslint/no-unsafe-* rules and @typescript-eslint/no-explicit-any:
// This project contains a lot of library-sh code where the use of `any` is often necessary and justified. // This project contains a lot of library-sh code where the use of `any` is often necessary and justified.
// Rules is now set to 'off' for a while. // Rules is now set to 'off' for a while.
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unsafe-argument": "off", "@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/no-unsafe-call": "off", "@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-unsafe-member-access": "off", "@typescript-eslint/no-unsafe-member-access": "off",
+1
View File
@@ -120,6 +120,7 @@ export class LiveSyncBaseCore<
* @param constructor * @param constructor
* @returns * @returns
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getModule<T extends AbstractModule>(constructor: new (...args: any[]) => T): T { getModule<T extends AbstractModule>(constructor: new (...args: any[]) => T): T {
for (const module of this.modules) { for (const module of this.modules) {
if (module.constructor === constructor) return module as T; if (module.constructor === constructor) return module as T;
+5 -1
View File
@@ -109,7 +109,11 @@ Deno.test("daemon: ignore rules behaviour", async (t) => {
await runCliOrFail(vaultDir, "--settings", settingsFile, "mirror"); await runCliOrFail(vaultDir, "--settings", settingsFile, "mirror");
const dbList = await runCliOrFail(vaultDir, "--settings", settingsFile, "ls"); const dbList = await runCliOrFail(vaultDir, "--settings", settingsFile, "ls");
assertNotContains(dbList, "debug.log", "debug.log (ignored via .gitignore import) was unexpectedly synced to database"); assertNotContains(
dbList,
"debug.log",
"debug.log (ignored via .gitignore import) was unexpectedly synced to database"
);
assertContains(dbList, "regular.md", "regular.md was not synced normally alongside .gitignore import rules"); assertContains(dbList, "regular.md", "regular.md was not synced normally alongside .gitignore import rules");
console.log("[PASS] Case 3 verified successfully"); console.log("[PASS] Case 3 verified successfully");
}); });
+4 -31
View File
@@ -46,9 +46,7 @@ Deno.test("decoupled database and vault", async () => {
console.log("[INFO] applying CouchDB environment variables to settings"); console.log("[INFO] applying CouchDB environment variables to settings");
await applyCouchdbSettings(settingsFile, uri, user, password, dbname); await applyCouchdbSettings(settingsFile, uri, user, password, dbname);
} else { } else {
console.warn( console.warn("[WARN] CouchDB environment variables are not fully set. Push and pull operations may fail.");
"[WARN] CouchDB environment variables are not fully set. Push and pull operations may fail."
);
await markSettingsConfigured(settingsFile); await markSettingsConfigured(settingsFile);
} }
@@ -59,29 +57,11 @@ Deno.test("decoupled database and vault", async () => {
// 1. Test push command with decoupled vault directory // 1. Test push command with decoupled vault directory
console.log(`[INFO] push with decoupled vault -> ${REMOTE_PATH}`); console.log(`[INFO] push with decoupled vault -> ${REMOTE_PATH}`);
await runCliOrFail( await runCliOrFail(dbDir, "--vault", vaultDir, "--settings", settingsFile, "push", srcFile, REMOTE_PATH);
dbDir,
"--vault",
vaultDir,
"--settings",
settingsFile,
"push",
srcFile,
REMOTE_PATH
);
// 2. Test pull command with decoupled vault directory // 2. Test pull command with decoupled vault directory
console.log(`[INFO] pull with decoupled vault <- ${REMOTE_PATH}`); console.log(`[INFO] pull with decoupled vault <- ${REMOTE_PATH}`);
await runCliOrFail( await runCliOrFail(dbDir, "--vault", vaultDir, "--settings", settingsFile, "pull", REMOTE_PATH, pulledFile);
dbDir,
"--vault",
vaultDir,
"--settings",
settingsFile,
"pull",
REMOTE_PATH,
pulledFile
);
const pulled = await Deno.readTextFile(pulledFile); const pulled = await Deno.readTextFile(pulledFile);
assertEquals(pulled, content, "push/pull roundtrip with decoupled vault content mismatch"); assertEquals(pulled, content, "push/pull roundtrip with decoupled vault content mismatch");
@@ -93,14 +73,7 @@ Deno.test("decoupled database and vault", async () => {
// 4. Test mirror command with decoupled vault directory // 4. Test mirror command with decoupled vault directory
console.log("[INFO] mirror with decoupled vault"); console.log("[INFO] mirror with decoupled vault");
await runCliOrFail( await runCliOrFail(dbDir, "--vault", vaultDir, "--settings", settingsFile, "mirror");
dbDir,
"--vault",
vaultDir,
"--settings",
settingsFile,
"mirror"
);
const restoredFile = join(vaultDir, REMOTE_PATH); const restoredFile = join(vaultDir, REMOTE_PATH);
const restored = await Deno.readTextFile(restoredFile); const restored = await Deno.readTextFile(restoredFile);
@@ -14,7 +14,7 @@ import { getOptimalLoopbackIp } from "./helpers/net.ts";
Deno.test("p2p-peers: discovers host through local relay", async () => { Deno.test("p2p-peers: discovers host through local relay", async () => {
const loopbackIp = await getOptimalLoopbackIp(); const loopbackIp = await getOptimalLoopbackIp();
const loopbackHost = loopbackIp === "::1" ? "[::1]" : loopbackIp; const loopbackHost = loopbackIp === "::1" ? "[::1]" : loopbackIp;
const relay = Deno.env.get("RELAY") ?? `ws://${loopbackHost}:4000/`; const relay = Deno.env.get("RELAY") ?? `ws://${loopbackHost}:4000/`;
const roomId = Deno.env.get("ROOM_ID") ?? `room-${Date.now()}`; const roomId = Deno.env.get("ROOM_ID") ?? `room-${Date.now()}`;
const passphrase = Deno.env.get("PASSPHRASE") ?? "test"; const passphrase = Deno.env.get("PASSPHRASE") ?? "test";
+1 -1
View File
@@ -15,7 +15,7 @@ import { getOptimalLoopbackIp } from "./helpers/net.ts";
Deno.test("p2p-sync: discovers peer and completes sync", async () => { Deno.test("p2p-sync: discovers peer and completes sync", async () => {
const loopbackIp = await getOptimalLoopbackIp(); const loopbackIp = await getOptimalLoopbackIp();
const loopbackHost = loopbackIp === "::1" ? "[::1]" : loopbackIp; const loopbackHost = loopbackIp === "::1" ? "[::1]" : loopbackIp;
const relay = Deno.env.get("RELAY") ?? `ws://${loopbackHost}:4000/`; const relay = Deno.env.get("RELAY") ?? `ws://${loopbackHost}:4000/`;
const roomId = Deno.env.get("ROOM_ID") ?? `room-${Date.now()}`; const roomId = Deno.env.get("ROOM_ID") ?? `room-${Date.now()}`;
const passphrase = Deno.env.get("PASSPHRASE") ?? "test"; const passphrase = Deno.env.get("PASSPHRASE") ?? "test";
@@ -15,7 +15,7 @@ import { getOptimalLoopbackIp } from "./helpers/net.ts";
Deno.test("p2p: three nodes detect and resolve conflicts", async () => { Deno.test("p2p: three nodes detect and resolve conflicts", async () => {
const loopbackIp = await getOptimalLoopbackIp(); const loopbackIp = await getOptimalLoopbackIp();
const loopbackHost = loopbackIp === "::1" ? "[::1]" : loopbackIp; const loopbackHost = loopbackIp === "::1" ? "[::1]" : loopbackIp;
const relay = Deno.env.get("RELAY") ?? `ws://${loopbackHost}:4000/`; const relay = Deno.env.get("RELAY") ?? `ws://${loopbackHost}:4000/`;
const roomId = Deno.env.get("ROOM_ID") ?? `room-${Date.now()}`; const roomId = Deno.env.get("ROOM_ID") ?? `room-${Date.now()}`;
const passphrase = Deno.env.get("PASSPHRASE") ?? "test"; const passphrase = Deno.env.get("PASSPHRASE") ?? "test";
@@ -61,11 +61,7 @@ Deno.test("remote management commands", async () => {
// 1. remote-status outputs valid JSON with CouchDB details // 1. remote-status outputs valid JSON with CouchDB details
console.log("[CASE] remote-status outputs valid JSON with CouchDB details"); console.log("[CASE] remote-status outputs valid JSON with CouchDB details");
const statusOutput = await runCliCombinedOrFail(vaultDir, "--settings", settingsFile, "remote-status"); const statusOutput = await runCliCombinedOrFail(vaultDir, "--settings", settingsFile, "remote-status");
assertContains( assertContains(statusOutput, `"db_name": "${dbname}"`, "remote-status should return JSON containing db_name");
statusOutput,
`"db_name": "${dbname}"`,
"remote-status should return JSON containing db_name"
);
console.log("[PASS] remote-status verified"); console.log("[PASS] remote-status verified");
// 2. lock-remote locks and verifies state // 2. lock-remote locks and verifies state
+2 -2
View File
@@ -2,7 +2,7 @@ import { deleteDB, type IDBPDatabase, openDB } from "idb";
import type { KeyValueDatabase } from "../lib/src/interfaces/KeyValueDatabase.ts"; import type { KeyValueDatabase } from "../lib/src/interfaces/KeyValueDatabase.ts";
import { serialized } from "octagonal-wheels/concurrency/lock"; import { serialized } from "octagonal-wheels/concurrency/lock";
import { Logger } from "octagonal-wheels/common/logger"; import { Logger } from "octagonal-wheels/common/logger";
const databaseCache: { [key: string]: IDBPDatabase<any> } = {}; const databaseCache: { [key: string]: IDBPDatabase<unknown> } = {};
export { OpenKeyValueDatabase } from "./KeyValueDBv2.ts"; export { OpenKeyValueDatabase } from "./KeyValueDBv2.ts";
export const _OpenKeyValueDatabase = async (dbKey: string): Promise<KeyValueDatabase> => { export const _OpenKeyValueDatabase = async (dbKey: string): Promise<KeyValueDatabase> => {
@@ -11,7 +11,7 @@ export const _OpenKeyValueDatabase = async (dbKey: string): Promise<KeyValueData
delete databaseCache[dbKey]; delete databaseCache[dbKey];
} }
const storeKey = dbKey; const storeKey = dbKey;
let db: IDBPDatabase<any> | null = null; let db: IDBPDatabase<unknown> | null = null;
const _openDB = () => { const _openDB = () => {
return serialized("keyvaluedb-" + dbKey, async () => { return serialized("keyvaluedb-" + dbKey, async () => {
const dbInstance = await openDB(dbKey, 1, { const dbInstance = await openDB(dbKey, 1, {
+2 -2
View File
@@ -28,7 +28,7 @@ export async function OpenKeyValueDatabase(dbKey: string): Promise<KeyValueDatab
} }
export class IDBKeyValueDatabase implements KeyValueDatabase { export class IDBKeyValueDatabase implements KeyValueDatabase {
protected _dbPromise: Promise<IDBPDatabase<any>> | null = null; protected _dbPromise: Promise<IDBPDatabase<unknown>> | null = null;
protected dbKey: string; protected dbKey: string;
protected storeKey: string; protected storeKey: string;
protected _isDestroyed: boolean = false; protected _isDestroyed: boolean = false;
@@ -104,7 +104,7 @@ export class IDBKeyValueDatabase implements KeyValueDatabase {
this.destroyedPromise = Promise.resolve(); this.destroyedPromise = Promise.resolve();
} }
} }
get DB(): Promise<IDBPDatabase<any>> { get DB(): Promise<IDBPDatabase<unknown>> {
if (this._isDestroyed) { if (this._isDestroyed) {
return Promise.reject(new Error("Database is destroyed")); return Promise.reject(new Error("Database is destroyed"));
} }
+2 -2
View File
@@ -4,10 +4,10 @@ import { eventHub, EVENT_PLUGIN_UNLOADED } from "./events";
import type { NecessaryServices } from "@lib/interfaces/ServiceModule"; import type { NecessaryServices } from "@lib/interfaces/ServiceModule";
type PeriodicProcessorHost = NecessaryServices<"API" | "control", never>; type PeriodicProcessorHost = NecessaryServices<"API" | "control", never>;
export class PeriodicProcessor { export class PeriodicProcessor {
_process: () => Promise<any>; _process: () => Promise<unknown>;
_timer?: number = undefined; _timer?: number = undefined;
_core: PeriodicProcessorHost; _core: PeriodicProcessorHost;
constructor(core: PeriodicProcessorHost, process: () => Promise<any>) { constructor(core: PeriodicProcessorHost, process: () => Promise<unknown>) {
// this._plugin = plugin; // this._plugin = plugin;
this._core = core; this._core = core;
this._process = process; this._process = process;
+5 -6
View File
@@ -9,16 +9,15 @@ import { isCloudantURI } from "@lib/pouchdb/utils_couchdb";
import { compatGlobal } from "@lib/common/coreEnvFunctions"; import { compatGlobal } from "@lib/common/coreEnvFunctions";
import { manifestVersion, packageVersion } from "@lib/common/coreEnvVars"; import { manifestVersion, packageVersion } from "@lib/common/coreEnvVars";
import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore"; import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore";
function redactObject(obj: Record<string, any>, dotted: string, redactedValue = "REDACTED") { function redactObject(obj: Record<string, unknown>, dotted: string, redactedValue = "REDACTED") {
const keys = dotted.split("."); const keys = dotted.split(".");
let current = obj; let current = obj;
for (let i = 0; i < keys.length - 1; i++) { for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i]; const key = keys[i];
if (!(key in current)) { if (!(key in current)) {
current[key] = {} as Record<string, any>; current[key] = {};
} }
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment current = current[key] as Record<string, unknown>;
current = current[key];
} }
const lastKey = keys[keys.length - 1]; const lastKey = keys[keys.length - 1];
if (lastKey in current) { if (lastKey in current) {
@@ -27,7 +26,7 @@ function redactObject(obj: Record<string, any>, dotted: string, redactedValue =
return obj; return obj;
} }
export async function generateReport(settings: ObsidianLiveSyncSettings, core: LiveSyncBaseCore) { export async function generateReport(settings: ObsidianLiveSyncSettings, core: LiveSyncBaseCore) {
let responseConfig: Record<string, any> = {}; let responseConfig: Record<string, unknown> = {};
const REDACTED = "𝑅𝐸𝐷𝐴𝐶𝑇𝐸𝐷"; const REDACTED = "𝑅𝐸𝐷𝐴𝐶𝑇𝐸𝐷";
if (settings.remoteType == REMOTE_COUCHDB) { if (settings.remoteType == REMOTE_COUCHDB) {
try { try {
@@ -42,7 +41,7 @@ export async function generateReport(settings: ObsidianLiveSyncSettings, core: L
undefined, undefined,
customHeaders customHeaders
); );
responseConfig = r.json as Record<string, any>; responseConfig = r.json as Record<string, unknown>;
redactObject(responseConfig, "couch_httpd_auth.secret"); redactObject(responseConfig, "couch_httpd_auth.secret");
redactObject(responseConfig, "couch_httpd_auth.authentication_db"); redactObject(responseConfig, "couch_httpd_auth.authentication_db");
redactObject(responseConfig, "couch_httpd_auth.authentication_redirect"); redactObject(responseConfig, "couch_httpd_auth.authentication_redirect");
+14 -14
View File
@@ -72,7 +72,7 @@ import {
} from "@lib/common/typeUtils.ts"; } from "@lib/common/typeUtils.ts";
export { isInternalFile, getPathFromUXFileInfo, getStoragePathFromUXFileInfo, getDatabasePathFromUXFileInfo }; export { isInternalFile, getPathFromUXFileInfo, getStoragePathFromUXFileInfo, getDatabasePathFromUXFileInfo };
const memos: { [key: string]: any } = {}; const memos: Record<string, unknown> = {};
export function memoObject<T>(key: string, obj: T): T { export function memoObject<T>(key: string, obj: T): T {
memos[key] = obj; memos[key] = obj;
return memos[key] as T; return memos[key] as T;
@@ -87,7 +87,7 @@ export async function memoIfNotExist<T>(key: string, func: () => T | Promise<T>)
} }
export function retrieveMemoObject<T>(key: string): T | false { export function retrieveMemoObject<T>(key: string): T | false {
if (key in memos) { if (key in memos) {
return memos[key]; return memos[key] as T;
} else { } else {
return false; return false;
} }
@@ -128,7 +128,7 @@ export const _requestToCouchDBFetch = async (
username: string, username: string,
password: string, password: string,
path?: string, path?: string,
body?: any, body?: unknown,
method?: string method?: string
) => { ) => {
const utf8str = String.fromCharCode.apply(null, [...writeString(`${username}:${password}`)]); const utf8str = String.fromCharCode.apply(null, [...writeString(`${username}:${password}`)]);
@@ -154,7 +154,7 @@ export const _requestToCouchDB = async (
credentials: CouchDBCredentials, credentials: CouchDBCredentials,
origin: string, origin: string,
path?: string, path?: string,
body?: any, body?: unknown,
method?: string, method?: string,
customHeaders?: Record<string, string> customHeaders?: Record<string, string>
) => { ) => {
@@ -263,27 +263,27 @@ export function compareFileFreshness(
const _cached = new Map< const _cached = new Map<
string, string,
{ {
value: any; value: unknown;
context: Map<string, any>; context: Map<string, unknown>;
} }
>(); >();
export type MemoOption = { export type MemoOption = {
key: string; key: string;
forceUpdate?: boolean; forceUpdate?: boolean;
validator?: (context: Map<string, any>) => boolean; validator?: (context: Map<string, unknown>) => boolean;
}; };
export function useMemo<T>( export function useMemo<T>(
{ key, forceUpdate, validator }: MemoOption, { key, forceUpdate, validator }: MemoOption,
updateFunc: (context: Map<string, any>, prev: T) => T updateFunc: (context: Map<string, unknown>, prev: T) => T
): T { ): T {
const cached = _cached.get(key); const cached = _cached.get(key);
const context = cached?.context || new Map<string, any>(); const context = cached?.context || new Map<string, unknown>();
if (cached && !forceUpdate && (!validator || (validator && !validator(context)))) { if (cached && !forceUpdate && (!validator || (validator && !validator(context)))) {
return cached.value; return cached.value as T;
} }
const value = updateFunc(context, cached?.value); const value = updateFunc(context, cached?.value as T);
if (value !== cached?.value) { if (value !== cached?.value) {
_cached.set(key, { value, context }); _cached.set(key, { value, context });
} }
@@ -294,7 +294,7 @@ export function useMemo<T>(
const _staticObj = new Map< const _staticObj = new Map<
string, string,
{ {
value: any; value: unknown;
} }
>(); >();
@@ -306,7 +306,7 @@ export function useStatic<T>(key: string, initial?: T) {
// } // }
const obj = _staticObj.get(key); const obj = _staticObj.get(key);
if (obj !== undefined) { if (obj !== undefined) {
return obj; return obj as { value: T };
} else { } else {
// let buf = initial; // let buf = initial;
const obj = { const obj = {
@@ -390,7 +390,7 @@ export async function autosaveCache<K, V>(db: KeyValueDatabase, mapKey: string):
}; };
} }
export function onlyInNTimes(n: number, proc: (progress: number) => any) { export function onlyInNTimes(n: number, proc: (progress: number) => unknown) {
let counter = 0; let counter = 0;
return function () { return function () {
if (counter++ % n == 0) { if (counter++ % n == 0) {
+12 -8
View File
@@ -1100,10 +1100,16 @@ export class ConfigSync extends LiveSyncCommands {
await delay(100); await delay(100);
this._log(`Config ${data.displayName || data.name} has been applied`, LOG_LEVEL_NOTICE); this._log(`Config ${data.displayName || data.name} has been applied`, LOG_LEVEL_NOTICE);
if (data.category == "PLUGIN_DATA" || data.category == "PLUGIN_MAIN") { if (data.category == "PLUGIN_DATA" || data.category == "PLUGIN_MAIN") {
//@ts-ignore const appWithPlugins = this.app as unknown as {
const manifests = Object.values(this.app.plugins.manifests) as any as PluginManifest[]; plugins: {
//@ts-ignore manifests: Record<string, PluginManifest>;
const enabledPlugins = this.app.plugins.enabledPlugins as Set<string>; enabledPlugins: Set<string>;
unloadPlugin(id: string): Promise<void>;
loadPlugin(id: string): Promise<void>;
};
};
const manifests = Object.values(appWithPlugins.plugins.manifests);
const enabledPlugins = appWithPlugins.plugins.enabledPlugins;
const pluginManifest = manifests.find( const pluginManifest = manifests.find(
(manifest) => enabledPlugins.has(manifest.id) && manifest.dir == `${baseDir}/plugins/${data.name}` (manifest) => enabledPlugins.has(manifest.id) && manifest.dir == `${baseDir}/plugins/${data.name}`
); );
@@ -1113,10 +1119,8 @@ export class ConfigSync extends LiveSyncCommands {
LOG_LEVEL_NOTICE, LOG_LEVEL_NOTICE,
"plugin-reload-" + pluginManifest.id "plugin-reload-" + pluginManifest.id
); );
// @ts-ignore await appWithPlugins.plugins.unloadPlugin(pluginManifest.id);
await this.app.plugins.unloadPlugin(pluginManifest.id); await appWithPlugins.plugins.loadPlugin(pluginManifest.id);
// @ts-ignore
await this.app.plugins.loadPlugin(pluginManifest.id);
this._log( this._log(
`Plugin reloaded: ${pluginManifest.name}`, `Plugin reloaded: ${pluginManifest.name}`,
LOG_LEVEL_NOTICE, LOG_LEVEL_NOTICE,
@@ -1224,10 +1224,16 @@ Offline Changed files: ${files.length}`;
const updatedFolders = [...this.queuedNotificationFiles]; const updatedFolders = [...this.queuedNotificationFiles];
this.queuedNotificationFiles.clear(); this.queuedNotificationFiles.clear();
try { try {
//@ts-ignore const appWithPlugins = this.app as unknown as {
const manifests = Object.values(this.app.plugins.manifests) as any as PluginManifest[]; plugins: {
//@ts-ignore manifests: Record<string, PluginManifest>;
const enabledPlugins = this.app.plugins.enabledPlugins as Set<string>; enabledPlugins: Set<string>;
unloadPlugin(id: string): Promise<void>;
loadPlugin(id: string): Promise<void>;
};
};
const manifests = Object.values(appWithPlugins.plugins.manifests);
const enabledPlugins = appWithPlugins.plugins.enabledPlugins;
const enabledPluginManifests = manifests.filter((e) => enabledPlugins.has(e.id)); const enabledPluginManifests = manifests.filter((e) => enabledPlugins.has(e.id));
const modifiedManifests = enabledPluginManifests.filter((e) => updatedFolders.indexOf(e?.dir ?? "") >= 0); const modifiedManifests = enabledPluginManifests.filter((e) => updatedFolders.indexOf(e?.dir ?? "") >= 0);
for (const manifest of modifiedManifests) { for (const manifest of modifiedManifests) {
@@ -1246,10 +1252,8 @@ Offline Changed files: ${files.length}`;
LOG_LEVEL_NOTICE, LOG_LEVEL_NOTICE,
"plugin-reload-" + updatePluginId "plugin-reload-" + updatePluginId
); );
// @ts-ignore await appWithPlugins.plugins.unloadPlugin(updatePluginId);
await this.app.plugins.unloadPlugin(updatePluginId); await appWithPlugins.plugins.loadPlugin(updatePluginId);
// @ts-ignore
await this.app.plugins.loadPlugin(updatePluginId);
this._log( this._log(
`Plugin reloaded: ${updatePluginName}`, `Plugin reloaded: ${updatePluginName}`,
LOG_LEVEL_NOTICE, LOG_LEVEL_NOTICE,
+8 -8
View File
@@ -67,25 +67,25 @@ export abstract class LiveSyncCommands {
_log: ReturnType<typeof createInstanceLogFunction>; _log: ReturnType<typeof createInstanceLogFunction>;
_verbose = (msg: any, key?: string) => { _verbose = (msg: unknown, key?: string) => {
this._log(msg, LOG_LEVEL_VERBOSE, key); this._log(msg, LOG_LEVEL_VERBOSE, key);
}; };
_info = (msg: any, key?: string) => { _info = (msg: unknown, key?: string) => {
this._log(msg, LOG_LEVEL_INFO, key); this._log(msg, LOG_LEVEL_INFO, key);
}; };
_notice = (msg: any, key?: string) => { _notice = (msg: unknown, key?: string) => {
this._log(msg, LOG_LEVEL_NOTICE, key); this._log(msg, LOG_LEVEL_NOTICE, key);
}; };
_progress = (prefix: string = "", level: LOG_LEVEL = LOG_LEVEL_NOTICE) => { _progress = (prefix: string = "", level: LOG_LEVEL = LOG_LEVEL_NOTICE) => {
const key = `keepalive-progress-${noticeIndex++}`; const key = `keepalive-progress-${noticeIndex++}`;
return { return {
log: (msg: any) => { log: (msg: unknown) => {
this._log(prefix + msg, level, key); this._log(prefix + String(msg), level, key);
}, },
once: (msg: any) => { once: (msg: unknown) => {
this._log(prefix + msg, level); this._log(prefix + String(msg), level);
}, },
done: (msg: string = "Done") => { done: (msg: string = "Done") => {
this._log(prefix + msg + MARK_DONE, level, key); this._log(prefix + msg + MARK_DONE, level, key);
@@ -93,7 +93,7 @@ export abstract class LiveSyncCommands {
}; };
}; };
_debug = (msg: any, key?: string) => { _debug = (msg: unknown, key?: string) => {
this._log(msg, LOG_LEVEL_VERBOSE, key); this._log(msg, LOG_LEVEL_VERBOSE, key);
}; };
@@ -17,6 +17,7 @@ import { arrayToChunkedArray } from "octagonal-wheels/collection";
import { EVENT_ANALYSE_DB_USAGE, EVENT_REQUEST_PERFORM_GC_V3, eventHub } from "@/common/events"; import { EVENT_ANALYSE_DB_USAGE, EVENT_REQUEST_PERFORM_GC_V3, eventHub } from "@/common/events";
import type { LiveSyncCouchDBReplicator } from "@/lib/src/replication/couchdb/LiveSyncReplicator"; import type { LiveSyncCouchDBReplicator } from "@/lib/src/replication/couchdb/LiveSyncReplicator";
import { delay } from "@/lib/src/common/utils"; import { delay } from "@/lib/src/common/utils";
import { isNotFoundError } from "@lib/common/utils.doc.ts";
// import { _requestToCouchDB } from "@/common/utils"; // import { _requestToCouchDB } from "@/common/utils";
const DB_KEY_SEQ = "gc-seq"; const DB_KEY_SEQ = "gc-seq";
const DB_KEY_CHUNK_SET = "chunk-set"; const DB_KEY_CHUNK_SET = "chunk-set";
@@ -393,8 +394,8 @@ Note: **Make sure to synchronise all devices before deletion.**
await processDoc(oldDoc, false); await processDoc(oldDoc, false);
} }
} }
} catch (ex) { } catch (ex: unknown) {
if ((ex as any)?.status == 404) { if (ex && typeof ex === "object" && isNotFoundError(ex)) {
this._log(`No revisions found for ${doc._id}`, LOG_LEVEL_VERBOSE); this._log(`No revisions found for ${doc._id}`, LOG_LEVEL_VERBOSE);
} else { } else {
this._log(`Error finding revisions for ${doc._id}`); this._log(`Error finding revisions for ${doc._id}`);
@@ -473,15 +474,23 @@ Are you ready to delete unused chunks?`;
keys: [...unusedSet], keys: [...unusedSet],
include_docs: true, include_docs: true,
}); });
interface PouchDBRow {
id: string;
key: string;
value: { rev: string; deleted?: boolean };
doc?: EntryDoc;
}
for (const chunk of deleteChunks.rows) { for (const chunk of deleteChunks.rows) {
if ((chunk as any)?.value?.deleted) { const c = chunk as unknown as PouchDBRow;
chunkSet.delete(chunk.key as DocumentID); if (c.value?.deleted) {
chunkSet.delete(c.key as DocumentID);
} }
} }
const deleteDocs = deleteChunks.rows const deleteDocs = deleteChunks.rows
.filter((e) => "doc" in e) .map((e) => e as unknown as PouchDBRow)
.filter((e) => e.doc != null)
.map((e) => ({ .map((e) => ({
...(e as any).doc!, ...e.doc!,
_deleted: true, _deleted: true,
})); }));
@@ -625,8 +634,19 @@ Success: ${successCount}, Errored: ${errored}`;
} }
} }
} }
interface DatabaseAnalysisResultItem {
title: string;
path: string;
rev: string;
revHash: string;
id?: string;
uniqueChunkCount: number;
sharedChunkCount: number;
uniqueChunkSize: number;
sharedChunkSize: number;
}
// Prepare results // Prepare results
const result = []; const result: DatabaseAnalysisResultItem[] = [];
// Calculate total size of chunks in the given set. // Calculate total size of chunks in the given set.
const getTotalSize = (ids: Set<DocumentID>) => { const getTotalSize = (ids: Set<DocumentID>) => {
return [...ids].reduce((acc, chunkId) => { return [...ids].reduce((acc, chunkId) => {
@@ -698,7 +718,7 @@ Success: ${successCount}, Errored: ${errored}`;
sharedChunkCount: 0, sharedChunkCount: 0,
uniqueChunkSize: orphanChunkSize, uniqueChunkSize: orphanChunkSize,
sharedChunkSize: 0, sharedChunkSize: 0,
} as any); });
const csvSrc = result.map((e) => { const csvSrc = result.map((e) => {
return [ return [
+1 -1
Submodule src/lib updated: 53804cbaec...7c43d69c65
@@ -20,7 +20,7 @@ import { InternalFileToUXFileInfoStub, TFileToUXFileInfoStub } from "@/modules/c
* Obsidian-specific type guard adapter * Obsidian-specific type guard adapter
*/ */
class ObsidianTypeGuardAdapter implements IStorageEventTypeGuardAdapter<TFile, TFolder> { class ObsidianTypeGuardAdapter implements IStorageEventTypeGuardAdapter<TFile, TFolder> {
isFile(file: any): file is TFile { isFile(file: unknown): file is TFile {
if (file instanceof TFile) { if (file instanceof TFile) {
return true; return true;
} }
@@ -30,7 +30,7 @@ class ObsidianTypeGuardAdapter implements IStorageEventTypeGuardAdapter<TFile, T
return false; return false;
} }
isFolder(item: any): item is TFolder { isFolder(item: unknown): item is TFolder {
if (item instanceof TFolder) { if (item instanceof TFolder) {
return true; return true;
} }
+7 -6
View File
@@ -61,18 +61,19 @@ export abstract class AbstractModule<
return this.testDone(false); return this.testDone(false);
} }
async _test(key: string, process: () => Promise<any>) { async _test(key: string, process: () => Promise<unknown>) {
this._log(`Testing ${key}`, LOG_LEVEL_VERBOSE); this._log(`Testing ${key}`, LOG_LEVEL_VERBOSE);
try { try {
const ret = await process(); const ret = await process();
if (ret !== true) { if (ret !== true) {
this.addTestResult(key, false, ret.toString()); this.addTestResult(key, false, String(ret));
return this.testFail(`${key} failed: ${ret}`); return this.testFail(`${key} failed: ${String(ret)}`);
} }
this.addTestResult(key, true, ""); this.addTestResult(key, true, "");
} catch (ex: any) { } catch (ex) {
this.addTestResult(key, false, "Failed by Exception", ex.toString()); const exStr = String(ex);
return this.testFail(`${key} failed: ${ex}`); this.addTestResult(key, false, "Failed by Exception", exStr);
return this.testFail(`${key} failed: ${exStr}`);
} }
return this.testDone(); return this.testDone();
} }
+9 -4
View File
@@ -7,7 +7,8 @@ export type OverridableFunctionsKeys<T> = {
export type ChainableExecuteFunction<T> = { export type ChainableExecuteFunction<T> = {
[K in keyof T as K extends `$${string}` [K in keyof T as K extends `$${string}`
? T[K] extends (...args: any) => ChainableFunctionResult ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
T[K] extends (...args: any) => ChainableFunctionResult
? K ? K
: never : never
: never]: T[K]; : never]: T[K];
@@ -26,26 +27,30 @@ export type ChainableFunctionResultOrAll = Promise<boolean | undefined | string
type AllExecuteFunction<T> = { type AllExecuteFunction<T> = {
[K in keyof T as K extends `$all${string}` [K in keyof T as K extends `$all${string}`
? T[K] extends (...args: any[]) => ChainableFunctionResultOrAll ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
T[K] extends (...args: any[]) => ChainableFunctionResultOrAll
? K ? K
: never : never
: never]: T[K]; : never]: T[K];
}; };
type EveryExecuteFunction<T> = { type EveryExecuteFunction<T> = {
[K in keyof T as K extends `$every${string}` [K in keyof T as K extends `$every${string}`
? T[K] extends (...args: any[]) => ChainableFunctionResult ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
T[K] extends (...args: any[]) => ChainableFunctionResult
? K ? K
: never : never
: never]: T[K]; : never]: T[K];
}; };
type AnyExecuteFunction<T> = { type AnyExecuteFunction<T> = {
[K in keyof T as K extends `$any${string}` [K in keyof T as K extends `$any${string}`
? T[K] extends (...args: any[]) => ChainableFunctionResult ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
T[K] extends (...args: any[]) => ChainableFunctionResult
? K ? K
: never : never
: never]: T[K]; : never]: T[K];
}; };
type InjectableFunction<T> = { type InjectableFunction<T> = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[K in keyof T as K extends `$$${string}` ? (T[K] extends (...args: any[]) => any ? K : never) : never]: T[K]; [K in keyof T as K extends `$$${string}` ? (T[K] extends (...args: any[]) => any ? K : never) : never]: T[K];
}; };
export type AllExecuteProps = AllExecuteFunction<LiveSyncCore>; export type AllExecuteProps = AllExecuteFunction<LiveSyncCore>;
+2 -2
View File
@@ -21,7 +21,7 @@ import { MARK_LOG_NETWORK_ERROR } from "@lib/services/lib/logUtils";
function isOnlineAndCanReplicate( function isOnlineAndCanReplicate(
errorManager: UnresolvedErrorManager, errorManager: UnresolvedErrorManager,
host: NecessaryServices<"API", any>, host: NecessaryServices<"API", never>,
showMessage: boolean showMessage: boolean
): Promise<boolean> { ): Promise<boolean> {
const errorMessage = "Network is offline"; const errorMessage = "Network is offline";
@@ -34,7 +34,7 @@ function isOnlineAndCanReplicate(
} }
async function canReplicateWithPBKDF2( async function canReplicateWithPBKDF2(
errorManager: UnresolvedErrorManager, errorManager: UnresolvedErrorManager,
host: NecessaryServices<"replicator" | "setting", any>, host: NecessaryServices<"replicator" | "setting", never>,
showMessage: boolean showMessage: boolean
): Promise<boolean> { ): Promise<boolean> {
const currentSettings = host.services.setting.currentSettings(); const currentSettings = host.services.setting.currentSettings();
+4 -3
View File
@@ -18,6 +18,7 @@ import {
type LOG_LEVEL, type LOG_LEVEL,
} from "@lib/common/logger"; } from "@lib/common/logger";
import { fireAndForget, isAnyNote, throttle } from "@lib/common/utils"; import { fireAndForget, isAnyNote, throttle } from "@lib/common/utils";
import { isNotFoundError } from "@lib/common/utils.doc.ts";
import { Semaphore } from "octagonal-wheels/concurrency/semaphore_v2"; import { Semaphore } from "octagonal-wheels/concurrency/semaphore_v2";
import { serialized } from "octagonal-wheels/concurrency/lock"; import { serialized } from "octagonal-wheels/concurrency/lock";
import type { ReactiveSource } from "octagonal-wheels/dataobject/reactive_v2"; import type { ReactiveSource } from "octagonal-wheels/dataobject/reactive_v2";
@@ -39,7 +40,7 @@ export class ReplicateResultProcessor {
private log(message: string, level: LOG_LEVEL = LOG_LEVEL_INFO) { private log(message: string, level: LOG_LEVEL = LOG_LEVEL_INFO) {
Logger(`[ReplicateResultProcessor] ${message}`, level); Logger(`[ReplicateResultProcessor] ${message}`, level);
} }
private logError(e: any) { private logError(e: unknown) {
Logger(e, LOG_LEVEL_VERBOSE); Logger(e, LOG_LEVEL_VERBOSE);
} }
private replicator: ModuleReplicator; private replicator: ModuleReplicator;
@@ -466,8 +467,8 @@ export class ReplicateResultProcessor {
return false; // This means that the document already processed (While no conflict existed). return false; // This means that the document already processed (While no conflict existed).
} }
return true; // This mostly should not happen, but we have to process it just in case. return true; // This mostly should not happen, but we have to process it just in case.
} catch (e: any) { } catch (e: unknown) {
if ("status" in e && e.status == 404) { if (e && typeof e === "object" && isNotFoundError(e)) {
// getRaw failed due to not existing, it may not be happened normally especially on replication. // getRaw failed due to not existing, it may not be happened normally especially on replication.
// If the process caused by some other reason, we **probably** have to process it. // If the process caused by some other reason, we **probably** have to process it.
// Note that this is not a common case. // Note that this is not a common case.
@@ -18,14 +18,14 @@ import type { InjectableServiceHub } from "../../lib/src/services/InjectableServ
import type { LiveSyncCore } from "../../main.ts"; import type { LiveSyncCore } from "../../main.ts";
import { REMOTE_P2P } from "@lib/common/models/setting.const.ts"; import { REMOTE_P2P } from "@lib/common/models/setting.const.ts";
function valueToString(value: any) { function valueToString(value: unknown) {
if (typeof value === "boolean") { if (typeof value === "boolean") {
return value ? "true" : "false"; return value ? "true" : "false";
} }
if (typeof value === "object") { if (typeof value === "object" && value !== null) {
return JSON.stringify(value); return JSON.stringify(value);
} }
return `${value}`; return String(value);
} }
export class ModuleResolvingMismatchedTweaks extends AbstractModule { export class ModuleResolvingMismatchedTweaks extends AbstractModule {
@@ -68,9 +68,13 @@ export class ObsHttpHandler extends FetchHttpHandler {
contentType = transformedHeaders["content-type"]; contentType = transformedHeaders["content-type"];
} }
let transformedBody: any = body; let transformedBody: string | ArrayBuffer | undefined = undefined;
if (ArrayBuffer.isView(body)) { if (typeof body === "string" || body instanceof ArrayBuffer) {
transformedBody = new Uint8Array(body.buffer).buffer; transformedBody = body;
} else if (ArrayBuffer.isView(body)) {
transformedBody = body.buffer as ArrayBuffer;
} else if (body != null) {
transformedBody = body as string | ArrayBuffer;
} }
const param: RequestUrlParam = { const param: RequestUrlParam = {
@@ -36,13 +36,14 @@ export class ModuleObsidianEvents extends AbstractObsidianModule {
this.services.appLifecycle.performRestart(); this.services.appLifecycle.performRestart();
} }
initialCallback: any; initialCallback: (() => unknown) | undefined;
swapSaveCommand() { swapSaveCommand() {
this._log("Modifying callback of the save command", LOG_LEVEL_VERBOSE); this._log("Modifying callback of the save command", LOG_LEVEL_VERBOSE);
const saveCommandDefinition = (this.app as any).commands?.commands?.["editor:save-file"]; const app = this.app as unknown as { commands?: { commands?: Record<string, { callback?: () => unknown }> } };
const saveCommandDefinition = app.commands?.commands?.["editor:save-file"];
const save = saveCommandDefinition?.callback; const save = saveCommandDefinition?.callback;
if (typeof save === "function") { if (typeof save === "function" && saveCommandDefinition) {
this.initialCallback = save; this.initialCallback = save;
saveCommandDefinition.callback = () => { saveCommandDefinition.callback = () => {
scheduleTask("syncOnEditorSave", 250, () => { scheduleTask("syncOnEditorSave", 250, () => {
+2 -2
View File
@@ -6,7 +6,7 @@ let plugin: ObsidianLiveSyncPlugin;
export function enableTestFunction(plugin_: ObsidianLiveSyncPlugin) { export function enableTestFunction(plugin_: ObsidianLiveSyncPlugin) {
plugin = plugin_; plugin = plugin_;
} }
export function addDebugFileLog(message: any, stackLog = false) { export function addDebugFileLog(message: unknown, stackLog = false) {
fireAndForget( fireAndForget(
serialized("debug-log", async () => { serialized("debug-log", async () => {
const now = new Date(); const now = new Date();
@@ -16,7 +16,7 @@ export function addDebugFileLog(message: any, stackLog = false) {
// const messageContent = typeof message == "string" ? message : message instanceof Error ? `${message.name}:${message.message}` : JSON.stringify(message, null, 2); // const messageContent = typeof message == "string" ? message : message instanceof Error ? `${message.name}:${message.message}` : JSON.stringify(message, null, 2);
const timestamp = now.toLocaleString(); const timestamp = now.toLocaleString();
const timestampEpoch = now; const timestampEpoch = now;
let out = { timestamp: timestamp, epoch: timestampEpoch } as Record<string, any>; let out = { timestamp: timestamp, epoch: timestampEpoch } as Record<string, unknown>;
if (message instanceof Error) { if (message instanceof Error) {
// debugger; // debugger;
// console.dir(message.stack); // console.dir(message.stack);
@@ -139,7 +139,7 @@ export class DocumentHistoryModal extends Modal {
this.range.value = `${this.revs_info.length - 1 - rIndex}`; this.range.value = `${this.revs_info.length - 1 - rIndex}`;
} }
} }
const index = this.revs_info.length - 1 - (this.range.value as any) / 1; const index = this.revs_info.length - 1 - Number(this.range.value);
const rev = this.revs_info[index]; const rev = this.revs_info[index];
await this.showExactRev(rev.rev); await this.showExactRev(rev.rev);
} }
@@ -251,7 +251,7 @@ export class DocumentHistoryModal extends Modal {
} }
let rendered = false; let rendered = false;
if (this.showDiff) { if (this.showDiff) {
const prevRevIdx = this.revs_info.length - 1 - ((this.range.value as any) / 1 - 1); const prevRevIdx = this.revs_info.length - 1 - (Number(this.range.value) - 1);
if (prevRevIdx >= 0 && prevRevIdx < this.revs_info.length) { if (prevRevIdx >= 0 && prevRevIdx < this.revs_info.length) {
const oldRev = this.revs_info[prevRevIdx].rev; const oldRev = this.revs_info[prevRevIdx].rev;
const w2 = await db.getDBEntry(this.file, { rev: oldRev }, false, false, true); const w2 = await db.getDBEntry(this.file, { rev: oldRev }, false, false, true);
@@ -550,7 +550,7 @@ export class DocumentHistoryModal extends Modal {
if (this.showDiff) { if (this.showDiff) {
checkbox.checked = true; checkbox.checked = true;
} }
checkbox.addEventListener("input", (evt: any) => { checkbox.addEventListener("input", (evt) => {
this.showDiff = checkbox.checked; this.showDiff = checkbox.checked;
this.app.saveLocalStorage("ols-history-highlightdiff", this.showDiff == true ? "1" : null); this.app.saveLocalStorage("ols-history-highlightdiff", this.showDiff == true ? "1" : null);
this.updateDiffNavVisibility(); this.updateDiffNavVisibility();
@@ -565,7 +565,7 @@ export class DocumentHistoryModal extends Modal {
if (this.diffOnly) { if (this.diffOnly) {
checkbox.checked = true; checkbox.checked = true;
} }
checkbox.addEventListener("input", (evt: any) => { checkbox.addEventListener("input", (evt) => {
this.diffOnly = checkbox.checked; this.diffOnly = checkbox.checked;
this.app.saveLocalStorage("ols-history-diffonly", this.diffOnly == true ? "1" : null); this.app.saveLocalStorage("ols-history-diffonly", this.diffOnly == true ? "1" : null);
void scheduleOnceIfDuplicated("loadRevs", () => this.loadRevs()); void scheduleOnceIfDuplicated("loadRevs", () => this.loadRevs());
+2 -2
View File
@@ -48,7 +48,7 @@ import { generateReport } from "@/common/reportTool.ts";
// DI the log again. // DI the log again.
const recentLogEntries = reactiveSource<LogEntry[]>([]); const recentLogEntries = reactiveSource<LogEntry[]>([]);
const globalLogFunction = (message: any, level?: number, key?: string) => { const globalLogFunction = (message: unknown, level?: number, key?: string) => {
const messageX = const messageX =
message instanceof Error message instanceof Error
? new LiveSyncError("[Error Logged]: " + message.message, { cause: message }) ? new LiveSyncError("[Error Logged]: " + message.message, { cause: message })
@@ -501,7 +501,7 @@ ${stringifyYaml(info)}
}) })
); );
} }
__addLog(message: any, level: LOG_LEVEL = LOG_LEVEL_INFO, key = ""): void { __addLog(message: unknown, level: LOG_LEVEL = LOG_LEVEL_INFO, key = ""): void {
if (level == LOG_LEVEL_DEBUG && !showDebugLog) { if (level == LOG_LEVEL_DEBUG && !showDebugLog) {
return; return;
} }
@@ -35,7 +35,7 @@ export class LiveSyncSetting extends Setting {
hasPassword: boolean = false; hasPassword: boolean = false;
invalidateValue?: () => void; invalidateValue?: () => void;
setValue?: (value: any) => void; setValue?: (value: unknown) => void;
constructor(containerEl: HTMLElement) { constructor(containerEl: HTMLElement) {
super(containerEl); super(containerEl);
LiveSyncSetting.env.settingComponents.push(this); LiveSyncSetting.env.settingComponents.push(this);
@@ -102,6 +102,7 @@ export class LiveSyncSetting extends Setting {
} }
return conf; return conf;
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any
autoWireComponent(component: ValueComponent<any>, conf?: ConfigurationItem, opt?: AutoWireOption) { autoWireComponent(component: ValueComponent<any>, conf?: ConfigurationItem, opt?: AutoWireOption) {
this.placeHolderBuf = conf?.placeHolder || opt?.placeHolder || ""; this.placeHolderBuf = conf?.placeHolder || opt?.placeHolder || "";
if (conf?.level == LEVEL_ADVANCED) { if (conf?.level == LEVEL_ADVANCED) {
@@ -287,6 +287,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab {
// UI Element Wrapper --> // UI Element Wrapper -->
settingComponents = [] as Setting[]; settingComponents = [] as Setting[];
controlledElementFunc = [] as UpdateFunction[]; controlledElementFunc = [] as UpdateFunction[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onSavedHandlers = [] as OnSavedHandler<any>[]; onSavedHandlers = [] as OnSavedHandler<any>[];
inWizard: boolean = false; inWizard: boolean = false;
@@ -442,7 +442,9 @@ export function paneHatch(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElement,
...e.doc, ...e.doc,
_deleted: true, _deleted: true,
})); }));
const r = await this.core.localDatabase.bulkDocsRaw(newData as any[]); const r = await this.core.localDatabase.bulkDocsRaw(
newData as Parameters<typeof this.core.localDatabase.bulkDocsRaw>[0]
);
// Do not care about the result. // Do not care about the result.
Logger( Logger(
`${r.length} items have been removed, to confirm how many items are left, please perform it again.`, `${r.length} items have been removed, to confirm how many items are left, please perform it again.`,
@@ -7,7 +7,7 @@ import {
type ObsidianLiveSyncSettings, type ObsidianLiveSyncSettings,
LOG_LEVEL_VERBOSE, LOG_LEVEL_VERBOSE,
} from "../../../lib/src/common/types.ts"; } from "../../../lib/src/common/types.ts";
import { Menu } from "@/deps.ts"; import { Menu, ButtonComponent } from "@/deps.ts";
import { $msg } from "../../../lib/src/common/i18n.ts"; import { $msg } from "../../../lib/src/common/i18n.ts";
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts"; import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts"; import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
@@ -39,7 +39,7 @@ function getSettingsFromEditingSettings(editingSettings: AllSettings): ObsidianL
const workObj = { ...editingSettings } as ObsidianLiveSyncSettings; const workObj = { ...editingSettings } as ObsidianLiveSyncSettings;
const keys = Object.keys(OnDialogSettingsDefault); const keys = Object.keys(OnDialogSettingsDefault);
for (const k of keys) { for (const k of keys) {
delete (workObj as any)[k]; delete (workObj as unknown as Record<string, unknown>)[k];
} }
return workObj; return workObj;
} }
@@ -72,7 +72,7 @@ function serializeRemoteConfiguration(settings: ObsidianLiveSyncSettings): strin
return ConnectionStringParser.serialize({ type: "couchdb", settings }); return ConnectionStringParser.serialize({ type: "couchdb", settings });
} }
function setEmojiButton(button: any, emoji: string, tooltip: string) { function setEmojiButton(button: ButtonComponent, emoji: string, tooltip: string) {
button.setButtonText(emoji); button.setButtonText(emoji);
button.setTooltip(tooltip, { delay: 10, placement: "top" }); button.setTooltip(tooltip, { delay: 10, placement: "top" });
// button.buttonEl.addClass("clickable-icon"); // button.buttonEl.addClass("clickable-icon");
@@ -145,8 +145,8 @@ export function paneSetup(
let remoteTroubleShootMDSrc = ""; let remoteTroubleShootMDSrc = "";
try { try {
remoteTroubleShootMDSrc = await request(`${rawRepoURI}${basePath}/${filename}`); remoteTroubleShootMDSrc = await request(`${rawRepoURI}${basePath}/${filename}`);
} catch (ex: any) { } catch (ex) {
remoteTroubleShootMDSrc = `${$msg("obsidianLiveSyncSettingTab.logErrorOccurred")}\n${ex.toString()}`; remoteTroubleShootMDSrc = `${$msg("obsidianLiveSyncSettingTab.logErrorOccurred")}\n${String(ex)}`;
} }
const remoteTroubleShootMD = remoteTroubleShootMDSrc.replace( const remoteTroubleShootMD = remoteTroubleShootMDSrc.replace(
/\((.*?(.png)|(.jpg))\)/g, /\((.*?(.png)|(.jpg))\)/g,
@@ -5,7 +5,7 @@ import { type Writable, writable, get } from "svelte/store";
* Props passed to Svelte panels, containing a writable port * Props passed to Svelte panels, containing a writable port
* to communicate with the panel * to communicate with the panel
*/ */
export type SveltePanelProps<T = any> = { export type SveltePanelProps<T = unknown> = {
port: Writable<T | undefined>; port: Writable<T | undefined>;
}; };
@@ -13,7 +13,7 @@ export type SveltePanelProps<T = any> = {
* A class to manage a Svelte panel within Obsidian * A class to manage a Svelte panel within Obsidian
* Especially useful for settings panels * Especially useful for settings panels
*/ */
export class SveltePanel<T = any> { export class SveltePanel<T = unknown> {
private _mountedComponent: ReturnType<typeof mount>; private _mountedComponent: ReturnType<typeof mount>;
private _componentValue = writable<T | undefined>(undefined); private _componentValue = writable<T | undefined>(undefined);
/** /**
@@ -13,6 +13,8 @@ import {
} from "../../../lib/src/common/utils"; } from "../../../lib/src/common/utils";
import { getConfig, type AllSettingItemKey } from "./settingConstants"; import { getConfig, type AllSettingItemKey } from "./settingConstants";
import { LOG_LEVEL_NOTICE, Logger } from "octagonal-wheels/common/logger"; import { LOG_LEVEL_NOTICE, Logger } from "octagonal-wheels/common/logger";
import { isNotFoundError } from "@lib/common/utils.doc.ts";
import { LiveSyncError } from "@lib/common/LSError.ts";
/** /**
* Generates a summary of P2P configuration settings * Generates a summary of P2P configuration settings
@@ -95,13 +97,13 @@ export function getSummaryFromPartialSettings(setting: Partial<ObsidianLiveSyncS
export async function copyMigrationDocs(docName: string, dbFrom: PouchDB.Database, dbTo: PouchDB.Database) { export async function copyMigrationDocs(docName: string, dbFrom: PouchDB.Database, dbTo: PouchDB.Database) {
try { try {
const doc = await dbFrom.get(docName); const doc = await dbFrom.get(docName);
delete (doc as any)._rev; delete (doc as { _rev?: string })._rev;
await dbTo.put(doc); await dbTo.put(doc);
} catch (e) { } catch (e: unknown) {
if ((e as any).status === 404) { if (e && typeof e === "object" && isNotFoundError(e)) {
return; return;
} }
throw e; throw LiveSyncError.fromError(e);
} }
} }
@@ -259,8 +259,8 @@ export const checkConfig = async (
addResult($msg("obsidianLiveSyncSettingTab.msgDone"), ["ob-btn-config-head"]); addResult($msg("obsidianLiveSyncSettingTab.msgDone"), ["ob-btn-config-head"]);
addResult($msg("obsidianLiveSyncSettingTab.msgConnectionProxyNote"), ["ob-btn-config-info"]); addResult($msg("obsidianLiveSyncSettingTab.msgConnectionProxyNote"), ["ob-btn-config-info"]);
Logger($msg("obsidianLiveSyncSettingTab.logCheckingConfigDone"), LOG_LEVEL_INFO); Logger($msg("obsidianLiveSyncSettingTab.logCheckingConfigDone"), LOG_LEVEL_INFO);
} catch (ex: any) { } catch (ex) {
if (ex?.status == 401) { if (ex && typeof ex === "object" && "status" in ex && ex.status == 401) {
isSuccessful = false; isSuccessful = false;
addResult($msg("obsidianLiveSyncSettingTab.errAccessForbidden")); addResult($msg("obsidianLiveSyncSettingTab.errAccessForbidden"));
addResult($msg("obsidianLiveSyncSettingTab.errCannotContinueTest")); addResult($msg("obsidianLiveSyncSettingTab.errCannotContinueTest"));
@@ -7,8 +7,14 @@ import { isCloudantURI } from "../../../../lib/src/pouchdb/utils_couchdb";
import { generateCredentialObject } from "../../../../lib/src/replication/httplib"; import { generateCredentialObject } from "../../../../lib/src/replication/httplib";
export type ResultMessage = { message: string; classes: string[] }; export type ResultMessage = { message: string; classes: string[] };
export type ResultErrorMessage = { message: string; result: "error"; classes: string[] }; export type ResultErrorMessage = { message: string; result: "error"; classes: string[] };
export type ResultOk = { message: string; result: "ok"; value?: any }; export type ResultOk = { message: string; result: "ok"; value?: unknown };
export type ResultError = { message: string; result: "error"; value: any; fixMessage: string; fix(): Promise<void> }; export type ResultError = {
message: string;
result: "error";
value?: string;
fixMessage: string;
fix(): Promise<void>;
};
export type ConfigCheckResult = ResultOk | ResultError | ResultMessage | ResultErrorMessage; export type ConfigCheckResult = ResultOk | ResultError | ResultMessage | ResultErrorMessage;
/** /**
* Compares two version strings to determine if the baseVersion is greater than or equal to the version. * Compares two version strings to determine if the baseVersion is greater than or equal to the version.
@@ -35,7 +41,7 @@ function isGreaterThanOrEqual(baseVersion: string, version: string) {
* @param value setting value to update * @param value setting value to update
* @returns true if the update was successful, false otherwise * @returns true if the update was successful, false otherwise
*/ */
async function updateRemoteSetting(setting: ObsidianLiveSyncSettings, key: string, value: any) { async function updateRemoteSetting(setting: ObsidianLiveSyncSettings, key: string, value: string) {
const customHeaders = parseHeaderValues(setting.couchDB_CustomHeaders); const customHeaders = parseHeaderValues(setting.couchDB_CustomHeaders);
const credential = generateCredentialObject(setting); const credential = generateCredentialObject(setting);
const res = await requestToCouchDBWithCredentials( const res = await requestToCouchDBWithCredentials(
@@ -64,17 +70,17 @@ export const checkConfig = async (editingSettings: ObsidianLiveSyncSettings) =>
const addMessage = (msg: string, classes: string[] = []) => { const addMessage = (msg: string, classes: string[] = []) => {
result.push({ message: msg, classes }); result.push({ message: msg, classes });
}; };
const addSuccess = (msg: string, value?: any) => { const addSuccess = (msg: string, value?: unknown) => {
result.push({ message: msg, result: "ok", value }); result.push({ message: msg, result: "ok", value });
}; };
const _addError = (message: string, fixMessage: string, fix: () => Promise<void>, value?: any) => { const _addError = (message: string, fixMessage: string, fix: () => Promise<void>, value?: string) => {
result.push({ message, result: "error", fixMessage, fix, value }); result.push({ message, result: "error", fixMessage, fix, value });
}; };
const addErrorMessage = (msg: string, classes: string[] = []) => { const addErrorMessage = (msg: string, classes: string[] = []) => {
result.push({ message: msg, result: "error", classes }); result.push({ message: msg, result: "error", classes });
}; };
const addError = (message: string, fixMessage: string, key: string, expected: any) => { const addError = (message: string, fixMessage: string, key: string, expected: string) => {
_addError(message, fixMessage, async () => { _addError(message, fixMessage, async () => {
await updateRemoteSetting(editingSettings, key, expected); await updateRemoteSetting(editingSettings, key, expected);
}); });
@@ -279,8 +285,8 @@ export const checkConfig = async (editingSettings: ObsidianLiveSyncSettings) =>
addMessage($msg("obsidianLiveSyncSettingTab.msgDone"), ["ob-btn-config-head"]); addMessage($msg("obsidianLiveSyncSettingTab.msgDone"), ["ob-btn-config-head"]);
addMessage($msg("obsidianLiveSyncSettingTab.msgConnectionProxyNote"), ["ob-btn-config-info"]); addMessage($msg("obsidianLiveSyncSettingTab.msgConnectionProxyNote"), ["ob-btn-config-info"]);
addMessage($msg("obsidianLiveSyncSettingTab.logCheckingConfigDone")); addMessage($msg("obsidianLiveSyncSettingTab.logCheckingConfigDone"));
} catch (ex: any) { } catch (ex) {
if (ex?.status == 401) { if (ex && typeof ex === "object" && "status" in ex && ex.status == 401) {
addErrorMessage($msg("obsidianLiveSyncSettingTab.errAccessForbidden")); addErrorMessage($msg("obsidianLiveSyncSettingTab.errAccessForbidden"));
addErrorMessage($msg("obsidianLiveSyncSettingTab.errCannotContinueTest")); addErrorMessage($msg("obsidianLiveSyncSettingTab.errCannotContinueTest"));
addMessage($msg("obsidianLiveSyncSettingTab.logCheckingConfigDone")); addMessage($msg("obsidianLiveSyncSettingTab.logCheckingConfigDone"));
+2 -2
View File
@@ -125,11 +125,11 @@ export class ObsidianAPIService extends InjectableAPIService<ObsidianServiceCont
registerWindow(type: string, factory: ViewCreator): void { registerWindow(type: string, factory: ViewCreator): void {
return this.context.plugin.registerView(type, factory); return this.context.plugin.registerView(type, factory);
} }
addRibbonIcon(icon: string, title: string, callback: (evt: MouseEvent) => any): HTMLElement { addRibbonIcon(icon: string, title: string, callback: (evt: MouseEvent) => void): HTMLElement {
return this.context.plugin.addRibbonIcon(icon, title, callback); return this.context.plugin.addRibbonIcon(icon, title, callback);
} }
registerProtocolHandler(action: string, handler: (params: Record<string, string>) => any): void { registerProtocolHandler(action: string, handler: (params: Record<string, string>) => void): void {
return this.context.plugin.registerObsidianProtocolHandler(action, handler); return this.context.plugin.registerObsidianProtocolHandler(action, handler);
} }
+7 -7
View File
@@ -50,7 +50,7 @@ export async function deleteFlagFile(host: NecessaryServices<never, "storageAcce
} }
const REMOTE_KEEP_CURRENT = "Use active remote"; const REMOTE_KEEP_CURRENT = "Use active remote";
const REMOTE_CANCEL = "Cancel"; const REMOTE_CANCEL = "Cancel";
async function askAndActivateRemoteDatabase(host: NecessaryServices<"UI" | "setting", any>, log: LogFunction) { async function askAndActivateRemoteDatabase(host: NecessaryServices<"UI" | "setting", never>, log: LogFunction) {
const settings = host.services.setting.currentSettings(); const settings = host.services.setting.currentSettings();
if (settings.remoteConfigurations && Object.keys(settings.remoteConfigurations).length > 1) { if (settings.remoteConfigurations && Object.keys(settings.remoteConfigurations).length > 1) {
const message = const message =
@@ -216,7 +216,7 @@ export function createFetchAllFlagHandler(
* @returns updated configuration if applied, otherwise null. * @returns updated configuration if applied, otherwise null.
*/ */
export async function adjustSettingToRemote( export async function adjustSettingToRemote(
host: NecessaryServices<"tweakValue" | "UI" | "setting", any>, host: NecessaryServices<"tweakValue" | "UI" | "setting", never>,
log: LogFunction, log: LogFunction,
config: ObsidianLiveSyncSettings config: ObsidianLiveSyncSettings
) { ) {
@@ -243,7 +243,7 @@ export async function adjustSettingToRemote(
const necessary = extractObject(TweakValuesShouldMatchedTemplate, remoteTweaks); const necessary = extractObject(TweakValuesShouldMatchedTemplate, remoteTweaks);
// Check if any necessary tweak value is different from current config. // Check if any necessary tweak value is different from current config.
const differentItems = Object.entries(necessary).filter(([key, value]) => { const differentItems = Object.entries(necessary).filter(([key, value]) => {
return (config as any)[key] !== value; return config[key as keyof ObsidianLiveSyncSettings] !== value;
}); });
if (differentItems.length === 0) { if (differentItems.length === 0) {
log("Remote configuration matches local configuration. No changes applied.", LOG_LEVEL_NOTICE); log("Remote configuration matches local configuration. No changes applied.", LOG_LEVEL_NOTICE);
@@ -261,7 +261,7 @@ export async function adjustSettingToRemote(
config = { config = {
...config, ...config,
...Object.fromEntries(differentItems), ...Object.fromEntries(differentItems),
} satisfies ObsidianLiveSyncSettings; };
await host.services.setting.applyExternalSettings(config, true); await host.services.setting.applyExternalSettings(config, true);
log("Remote configuration applied.", LOG_LEVEL_NOTICE); log("Remote configuration applied.", LOG_LEVEL_NOTICE);
canProceed = true; canProceed = true;
@@ -277,7 +277,7 @@ export async function adjustSettingToRemote(
* @param config current configuration to retrieve remote preferred config * @param config current configuration to retrieve remote preferred config
*/ */
export async function adjustSettingToRemoteIfNeeded( export async function adjustSettingToRemoteIfNeeded(
host: NecessaryServices<"tweakValue" | "UI" | "setting", any>, host: NecessaryServices<"tweakValue" | "UI" | "setting", never>,
log: LogFunction, log: LogFunction,
extra: { preventFetchingConfig: boolean }, extra: { preventFetchingConfig: boolean },
config: ObsidianLiveSyncSettings config: ObsidianLiveSyncSettings
@@ -309,7 +309,7 @@ export async function adjustSettingToRemoteIfNeeded(
* @returns result of the process, or false if error occurs. * @returns result of the process, or false if error occurs.
*/ */
export async function processVaultInitialisation( export async function processVaultInitialisation(
host: NecessaryServices<"setting", any>, host: NecessaryServices<"setting", never>,
log: LogFunction, log: LogFunction,
proc: () => Promise<boolean>, proc: () => Promise<boolean>,
keepSuspending = false keepSuspending = false
@@ -341,7 +341,7 @@ export async function processVaultInitialisation(
} }
export async function verifyAndUnlockSuspension( export async function verifyAndUnlockSuspension(
host: NecessaryServices<"setting" | "appLifecycle" | "UI", any>, host: NecessaryServices<"setting" | "appLifecycle" | "UI", never>,
log: LogFunction log: LogFunction
) { ) {
if (!host.services.setting.currentSettings().suspendFileWatching) { if (!host.services.setting.currentSettings().suspendFileWatching) {
@@ -6,11 +6,11 @@ import { TFile, TFolder } from "obsidian";
*/ */
export class ObsidianTypeGuardAdapter implements ITypeGuardAdapter<TFile, TFolder> { export class ObsidianTypeGuardAdapter implements ITypeGuardAdapter<TFile, TFolder> {
isFile(file: any): file is TFile { isFile(file: unknown): file is TFile {
return file instanceof TFile; return file instanceof TFile;
} }
isFolder(item: any): item is TFolder { isFolder(item: unknown): item is TFolder {
return item instanceof TFolder; return item instanceof TFolder;
} }
} }
@@ -55,6 +55,7 @@ export class ObsidianVaultAdapter implements IVaultAdapter<TFile> {
return await this.app.vault.trash(file, force); return await this.app.vault.trash(file, force);
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any
trigger(name: string, ...data: any[]): any { trigger(name: string, ...data: any[]): any {
return this.app.vault.trigger(name, ...data); return this.app.vault.trigger(name, ...data);
} }