mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-06-18 04:10:13 +00:00
for automatic review
This commit is contained in:
@@ -92,7 +92,7 @@ class LiveSyncWebApp {
|
||||
console.log("[Settings] Loaded from .livesync/settings.json");
|
||||
return { ...DEFAULT_SETTINGS, ...data } as ObsidianLiveSyncSettings;
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
console.log("[Settings] Failed to load, using defaults");
|
||||
}
|
||||
return DEFAULT_SETTINGS as ObsidianLiveSyncSettings;
|
||||
@@ -170,7 +170,7 @@ class LiveSyncWebApp {
|
||||
const file = await fileHandle.getFile();
|
||||
const text = await file.text();
|
||||
return JSON.parse(text);
|
||||
} catch (error) {
|
||||
} catch {
|
||||
// File doesn't exist yet
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ class FSAPIWatchAdapter implements IStorageEventWatchAdapter {
|
||||
if (changedHandle && changedHandle.kind === "file") {
|
||||
const file = await changedHandle.getFile();
|
||||
const fileInfo = {
|
||||
path: relativePath as any,
|
||||
path: relativePath,
|
||||
stat: {
|
||||
size: file.size,
|
||||
mtime: file.lastModified,
|
||||
@@ -200,7 +200,7 @@ class FSAPIWatchAdapter implements IStorageEventWatchAdapter {
|
||||
}
|
||||
} else if (type === "disappeared") {
|
||||
const fileInfo = {
|
||||
path: relativePath as any,
|
||||
path: relativePath,
|
||||
stat: {
|
||||
size: 0,
|
||||
mtime: Date.now(),
|
||||
@@ -217,7 +217,7 @@ class FSAPIWatchAdapter implements IStorageEventWatchAdapter {
|
||||
if (changedHandle && changedHandle.kind === "file") {
|
||||
const file = await changedHandle.getFile();
|
||||
const fileInfo = {
|
||||
path: relativePath as any,
|
||||
path: relativePath,
|
||||
stat: {
|
||||
size: file.size,
|
||||
mtime: file.lastModified,
|
||||
|
||||
@@ -91,7 +91,7 @@ export class VaultHistoryStore {
|
||||
|
||||
async getVaultHistory(): Promise<VaultHistoryItem[]> {
|
||||
return this.withStore("readonly", async (store) => {
|
||||
const keys = (await this.requestAsPromise(store.getAllKeys())) as IDBValidKey[];
|
||||
const keys = (await this.requestAsPromise(store.getAllKeys()));
|
||||
const values = (await this.requestAsPromise(store.getAll())) as unknown[];
|
||||
const items: VaultHistoryItem[] = [];
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
|
||||
+1
-1
Submodule src/lib updated: 7157dbc62c...c926417f82
@@ -182,9 +182,9 @@ export class ModuleConflictResolver extends AbstractModule {
|
||||
revs.map(async (rev) => {
|
||||
const leaf = await this.core.databaseFileAccess.fetchEntryMeta(filename, rev);
|
||||
if (leaf == false) {
|
||||
return [0, rev] as [number, string];
|
||||
return [0, rev];
|
||||
}
|
||||
return [leaf.mtime, rev] as [number, string];
|
||||
return [leaf.mtime, rev];
|
||||
})
|
||||
)),
|
||||
] as [number, string][]
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
# Refactoring and Code Quality Utilities
|
||||
|
||||
This directory contains Deno-based scripts that utilise `ts-morph` to perform codebase-wide refactoring, code quality clean-up, and static analysis.
|
||||
|
||||
These utilities are designed to help maintain code quality, resolve compiler warnings, and ensure popout window compatibility in the Obsidian plug-in environment.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
To execute these scripts, you must have Deno installed on your system.
|
||||
|
||||
---
|
||||
|
||||
## General Usage
|
||||
|
||||
By default, all refactoring scripts run in **dry-run mode**. They will output the proposed changes to the console without modifying any files.
|
||||
|
||||
To apply the changes to the files, append the `'--run'` flag:
|
||||
|
||||
```bash
|
||||
deno run --allow-read --allow-write --allow-env <script_name>.ts --run
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Utilities Reference
|
||||
|
||||
### 1. Global Wrapper Refactoring (`refactor-globals.ts`)
|
||||
Converts standard global variable usages to compatibility wrappers to ensure safe operation when running in Obsidian popout windows (which run in separate window contexts).
|
||||
|
||||
* **Targets**: `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval`, `requestAnimationFrame`, `cancelAnimationFrame`, `localStorage`, `navigator`, `location`, `window`, `globalThis`, and `document`.
|
||||
* **Actions**:
|
||||
* Replaces global namespace references (like `window` and `globalThis`) with `compatGlobal`.
|
||||
* Replaces `document` with `_activeDocument` (from `@lib/common/coreEnvFunctions.ts`).
|
||||
* Injects or updates the necessary imports in modified files.
|
||||
* **Command**:
|
||||
```bash
|
||||
deno run --allow-read --allow-write --allow-env refactor-globals.ts
|
||||
```
|
||||
|
||||
### 2. Element Style Normalisation (`refactor-styles.ts`)
|
||||
Converts direct style assignments on HTML/SVG elements to use the plug-in's `setCssStyles` helper.
|
||||
|
||||
* **Actions**:
|
||||
* Replaces statements like `element.style.color = 'red';` with `element.setCssStyles({ color: 'red' });`.
|
||||
* Groups multiple consecutive style assignments on the same element into a single call.
|
||||
* Supports both static keys and computed bracket properties.
|
||||
* **Command**:
|
||||
```bash
|
||||
deno run --allow-read --allow-write --allow-env refactor-styles.ts
|
||||
```
|
||||
|
||||
### 3. Redundant Assertions Cleanup (`refactor-assertions.ts`)
|
||||
Finds and removes type assertions that are redundant because the expression already evaluates to the asserted type.
|
||||
|
||||
* **Actions**:
|
||||
* Removes redundant `as Type` or `<Type>` assertions.
|
||||
* Preserves critical literal assertions such as `as const` and `<const>`.
|
||||
* **Command**:
|
||||
```bash
|
||||
deno run --allow-read --allow-write --allow-env refactor-assertions.ts
|
||||
```
|
||||
|
||||
### 4. Unused Code Refactoring (`refactor-unused.ts`)
|
||||
Cleans up unused imports and catch variables to reduce bundle size and warnings.
|
||||
|
||||
* **Actions**:
|
||||
* Converts unused catch variables to simple catch statements (e.g. `catch (error)` -> `catch`).
|
||||
* Removes unused items in named imports, handling alias bindings (e.g. `import { A as B }`) correctly.
|
||||
* Deletes empty import declarations resulting from the named import clean-up.
|
||||
* **Command**:
|
||||
```bash
|
||||
deno run --allow-read --allow-write --allow-env refactor-unused.ts
|
||||
```
|
||||
|
||||
### 5. Explicit Any Detection (`detect-any.ts`)
|
||||
Scans the codebase and logs all occurrences of explicit `any` types.
|
||||
|
||||
* **Actions**:
|
||||
* Identifies uses of the `any` keyword in TypeScript and Svelte files.
|
||||
* Logs the filename, line number, and matching code line for audit purposes.
|
||||
* **Command**:
|
||||
```bash
|
||||
deno run --allow-read --allow-env detect-any.ts
|
||||
```
|
||||
|
||||
### 6. Import Normalisation (`normalise-imports.ts`)
|
||||
Ensures that all import statements are standardised across the codebase, resolving paths to aliases such as `@lib/` and `@/` where applicable.
|
||||
|
||||
* **Command**:
|
||||
```bash
|
||||
deno run --allow-read --allow-write --allow-env normalise-imports.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Safety and Exclusions
|
||||
|
||||
* **Tests Excluded**: All scripts automatically skip files located in `_test/` or `testdeno/` folders, as well as files ending with `.spec.ts` or `.test.ts`.
|
||||
* **Submodule Caution**: Some tools will run against the `src/lib/` submodule. Ensure you verify changes inside the submodule prior to committing.
|
||||
* **Verification**: Always run `npm run check` and `npm run test:unit` after performing refactoring tasks to verify that type safety and tests remain intact.
|
||||
@@ -0,0 +1,49 @@
|
||||
// Detect explicit usage of 'any' type in the codebase.
|
||||
// Use this script by running `deno run --allow-read --allow-env detect-any.ts` from the utilsdeno directory.
|
||||
import { Project, SyntaxKind } from "npm:ts-morph";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const project = new Project({ tsConfigFilePath: "../tsconfig.json" });
|
||||
project.addSourceFilesAtPaths("../src/**/*.ts");
|
||||
project.addSourceFilesAtPaths("../src/**/*.svelte");
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const projectRoot = path.resolve(__dirname, "..");
|
||||
|
||||
function toPosixPath(filePath: string): string {
|
||||
return filePath.replace(/\\/g, "/");
|
||||
}
|
||||
|
||||
const posixProjectRoot = toPosixPath(projectRoot);
|
||||
const posixSrc = `${posixProjectRoot}/src`;
|
||||
|
||||
let anyCount = 0;
|
||||
|
||||
for (const sourceFile of project.getSourceFiles()) {
|
||||
const filePath = sourceFile.getFilePath();
|
||||
const posixFilePath = toPosixPath(filePath);
|
||||
|
||||
if (!posixFilePath.startsWith(posixSrc)) continue;
|
||||
if (
|
||||
posixFilePath.includes("/_test/") ||
|
||||
posixFilePath.endsWith(".spec.ts") ||
|
||||
posixFilePath.endsWith(".test.ts")
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const anyNodes = sourceFile.getDescendantsOfKind(SyntaxKind.AnyKeyword);
|
||||
if (anyNodes.length > 0) {
|
||||
console.log(`File: ${posixFilePath.slice(posixProjectRoot.length + 1)}`);
|
||||
for (const anyNode of anyNodes) {
|
||||
const { line } = sourceFile.getLineAndColumnAtPos(anyNode.getStart());
|
||||
const lineText = sourceFile.getFullText().split(/\r?\n/)[line - 1];
|
||||
console.log(` Line ${line}: ${lineText.trim()}`);
|
||||
anyCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nTotal explicit 'any' usages found: ${anyCount}`);
|
||||
@@ -0,0 +1,96 @@
|
||||
// Refactor unnecessary type assertions (e.g. `expr as Type` where type of `expr` is already `Type`).
|
||||
// Use this script by running `deno run --allow-read --allow-write --allow-env refactor-assertions.ts` from the utilsdeno directory.
|
||||
// Run with --run flag to apply changes.
|
||||
import { Project, SyntaxKind, Node } from "npm:ts-morph";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const isDryRun = !Deno.args.includes("--run");
|
||||
|
||||
if (isDryRun) {
|
||||
console.log("=== DRY RUN MODE ===");
|
||||
console.log(
|
||||
"To apply changes, run with: deno run --allow-read --allow-write --allow-env refactor-assertions.ts --run\n"
|
||||
);
|
||||
} else {
|
||||
console.log("=== RUN MODE: WILL MODIFY FILES ===");
|
||||
}
|
||||
|
||||
const project = new Project({ tsConfigFilePath: "../tsconfig.json" });
|
||||
project.addSourceFilesAtPaths("../src/**/*.ts");
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const projectRoot = path.resolve(__dirname, "..");
|
||||
|
||||
function toPosixPath(filePath: string): string {
|
||||
return filePath.replace(/\\/g, "/");
|
||||
}
|
||||
|
||||
const posixProjectRoot = toPosixPath(projectRoot);
|
||||
const posixSrc = `${posixProjectRoot}/src`;
|
||||
|
||||
let modifiedFilesCount = 0;
|
||||
|
||||
for (const sourceFile of project.getSourceFiles()) {
|
||||
const filePath = sourceFile.getFilePath();
|
||||
const posixFilePath = toPosixPath(filePath);
|
||||
|
||||
if (!posixFilePath.startsWith(posixSrc)) continue;
|
||||
if (posixFilePath.includes("/_test/") || posixFilePath.endsWith(".spec.ts") || posixFilePath.endsWith(".test.ts")) continue;
|
||||
|
||||
// Find AsExpression (expr as Type) and TypeAssertion (<Type>expr)
|
||||
const asExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.AsExpression);
|
||||
const typeAssertions = sourceFile.getDescendantsOfKind(SyntaxKind.TypeAssertion);
|
||||
const allAssertions = [...asExpressions, ...typeAssertions];
|
||||
|
||||
const nodesToRemove: Node[] = [];
|
||||
|
||||
for (const node of allAssertions) {
|
||||
const expr = node.getExpression();
|
||||
const exprType = expr.getType();
|
||||
const assertType = node.getType();
|
||||
|
||||
// Skip `as const` or `<const>` assertions
|
||||
const typeNode = (node as any).getTypeNode?.();
|
||||
if (typeNode && typeNode.getText() === "const") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compare type texts to find redundant assertions
|
||||
const exprTypeText = exprType.getText();
|
||||
const assertTypeText = assertType.getText();
|
||||
|
||||
if (exprTypeText === assertTypeText) {
|
||||
nodesToRemove.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (nodesToRemove.length > 0) {
|
||||
console.log(`File: ${posixFilePath.slice(posixProjectRoot.length + 1)}`);
|
||||
|
||||
// Reverse nodes order to keep indices/references valid when modifying
|
||||
const sortedNodes = [...nodesToRemove].sort((a, b) => b.getStart() - a.getStart());
|
||||
|
||||
for (const node of sortedNodes) {
|
||||
const { line } = sourceFile.getLineAndColumnAtPos(node.getStart());
|
||||
const exprText = node.getExpression().getText();
|
||||
console.log(` Line ${line}: "${node.getText()}" -> "${exprText}"`);
|
||||
|
||||
if (!isDryRun) {
|
||||
node.replaceWithText(exprText);
|
||||
}
|
||||
}
|
||||
|
||||
modifiedFilesCount++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nTotal files to modify: ${modifiedFilesCount}`);
|
||||
|
||||
if (!isDryRun) {
|
||||
project.saveSync();
|
||||
console.log("All changes successfully saved.");
|
||||
} else {
|
||||
console.log("Dry run complete. No changes were written to files.");
|
||||
}
|
||||
@@ -65,7 +65,12 @@ for (const sourceFile of project.getSourceFiles()) {
|
||||
}
|
||||
|
||||
// Exclude unit and integration test files
|
||||
if (posixFilePath.endsWith(".spec.ts") || posixFilePath.endsWith(".test.ts") || posixFilePath.includes("/_test/")) {
|
||||
if (
|
||||
posixFilePath.endsWith(".spec.ts") ||
|
||||
posixFilePath.endsWith(".test.ts") ||
|
||||
posixFilePath.includes("/_test/") ||
|
||||
posixFilePath.includes("/testdeno/")
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,12 @@ for (const sourceFile of project.getSourceFiles()) {
|
||||
}
|
||||
|
||||
// Exclude unit and integration test files
|
||||
if (posixFilePath.endsWith(".spec.ts") || posixFilePath.endsWith(".test.ts") || posixFilePath.includes("/_test/")) {
|
||||
if (
|
||||
posixFilePath.endsWith(".spec.ts") ||
|
||||
posixFilePath.endsWith(".test.ts") ||
|
||||
posixFilePath.includes("/_test/") ||
|
||||
posixFilePath.includes("/testdeno/")
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
// Refactor unused catch variables and unused imports in the codebase.
|
||||
// Use this script by running `deno run --allow-read --allow-write --allow-env refactor-unused.ts` from the utilsdeno directory.
|
||||
// Run with --run flag to apply changes.
|
||||
import { Project, SyntaxKind, Node } from "npm:ts-morph";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const isDryRun = !Deno.args.includes("--run");
|
||||
|
||||
if (isDryRun) {
|
||||
console.log("=== DRY RUN MODE ===");
|
||||
console.log(
|
||||
"To apply changes, run with: deno run --allow-read --allow-write --allow-env refactor-unused.ts --run\n"
|
||||
);
|
||||
} else {
|
||||
console.log("=== RUN MODE: WILL MODIFY FILES ===");
|
||||
}
|
||||
|
||||
const project = new Project({ tsConfigFilePath: "../tsconfig.json" });
|
||||
// Only add .ts files to avoid Svelte-markup-blindness references
|
||||
project.addSourceFilesAtPaths("../src/**/*.ts");
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const projectRoot = path.resolve(__dirname, "..");
|
||||
|
||||
function toPosixPath(filePath: string): string {
|
||||
return filePath.replace(/\\/g, "/");
|
||||
}
|
||||
|
||||
const posixProjectRoot = toPosixPath(projectRoot);
|
||||
const posixSrc = `${posixProjectRoot}/src`;
|
||||
|
||||
let modifiedFilesCount = 0;
|
||||
|
||||
for (const sourceFile of project.getSourceFiles()) {
|
||||
const filePath = sourceFile.getFilePath();
|
||||
const posixFilePath = toPosixPath(filePath);
|
||||
|
||||
if (!posixFilePath.startsWith(posixSrc)) continue;
|
||||
if (posixFilePath.includes("/_test/") || posixFilePath.endsWith(".spec.ts") || posixFilePath.endsWith(".test.ts")) continue;
|
||||
|
||||
let fileModified = false;
|
||||
|
||||
// 1. Find unused catch variables: catch (error) -> catch
|
||||
const catchClauses = sourceFile.getDescendantsOfKind(SyntaxKind.CatchClause);
|
||||
const catchVarsToRemove: Node[] = [];
|
||||
|
||||
for (const catchClause of catchClauses) {
|
||||
const varDec = catchClause.getVariableDeclaration();
|
||||
if (varDec) {
|
||||
const varName = varDec.getName();
|
||||
// Count references within the catch clause itself
|
||||
const count = catchClause.getDescendantsOfKind(SyntaxKind.Identifier)
|
||||
.filter((id) => id.getText() === varName)
|
||||
.length;
|
||||
if (count === 1) { // Only the declaration itself
|
||||
catchVarsToRemove.push(varDec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (catchVarsToRemove.length > 0) {
|
||||
if (!fileModified) {
|
||||
console.log(`File: ${posixFilePath.slice(posixProjectRoot.length + 1)}`);
|
||||
fileModified = true;
|
||||
}
|
||||
for (const varDec of catchVarsToRemove) {
|
||||
const { line } = sourceFile.getLineAndColumnAtPos(varDec.getStart());
|
||||
console.log(` Line ${line}: Unused catch variable "${varDec.getText()}" -> Remove it`);
|
||||
if (!isDryRun) {
|
||||
varDec.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Find unused named imports
|
||||
const importDeclarations = sourceFile.getImportDeclarations();
|
||||
const importsToRemove: { namedImport: any; impDecl: any }[] = [];
|
||||
const modifiedDecls = new Set<any>();
|
||||
|
||||
for (const impDecl of importDeclarations) {
|
||||
const namedImports = impDecl.getNamedImports();
|
||||
if (namedImports.length === 0) continue;
|
||||
|
||||
for (const namedImport of namedImports) {
|
||||
const importName = namedImport.getAliasNode()?.getText() ?? namedImport.getName();
|
||||
// Count references in the entire file
|
||||
const count = sourceFile.getDescendantsOfKind(SyntaxKind.Identifier)
|
||||
.filter((id) => id.getText() === importName)
|
||||
.length;
|
||||
if (count === 1) { // Only the import specifier itself
|
||||
importsToRemove.push({ namedImport, impDecl });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (importsToRemove.length > 0) {
|
||||
if (!fileModified) {
|
||||
console.log(`File: ${posixFilePath.slice(posixProjectRoot.length + 1)}`);
|
||||
fileModified = true;
|
||||
}
|
||||
for (const { namedImport, impDecl } of importsToRemove) {
|
||||
const { line } = sourceFile.getLineAndColumnAtPos(namedImport.getStart());
|
||||
console.log(` Line ${line}: Unused named import "${namedImport.getText()}" -> Remove it`);
|
||||
if (!isDryRun) {
|
||||
namedImport.remove();
|
||||
modifiedDecls.add(impDecl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Clean up empty import declarations (only those we actually modified)
|
||||
if (!isDryRun && fileModified && modifiedDecls.size > 0) {
|
||||
for (const impDecl of modifiedDecls) {
|
||||
if (
|
||||
impDecl.getNamedImports().length === 0 &&
|
||||
!impDecl.getDefaultImport() &&
|
||||
!impDecl.getNamespaceImport()
|
||||
) {
|
||||
impDecl.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fileModified) {
|
||||
modifiedFilesCount++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nTotal files to modify: ${modifiedFilesCount}`);
|
||||
|
||||
if (!isDryRun) {
|
||||
project.saveSync();
|
||||
console.log("All changes successfully saved.");
|
||||
} else {
|
||||
console.log("Dry run complete. No changes were written to files.");
|
||||
}
|
||||
Reference in New Issue
Block a user