mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-10-06 01:12:32 +00:00
for automatic review
This commit is contained in:
@@ -92,7 +92,7 @@ class LiveSyncWebApp {
|
|||||||
console.log("[Settings] Loaded from .livesync/settings.json");
|
console.log("[Settings] Loaded from .livesync/settings.json");
|
||||||
return { ...DEFAULT_SETTINGS, ...data } as ObsidianLiveSyncSettings;
|
return { ...DEFAULT_SETTINGS, ...data } as ObsidianLiveSyncSettings;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
console.log("[Settings] Failed to load, using defaults");
|
console.log("[Settings] Failed to load, using defaults");
|
||||||
}
|
}
|
||||||
return DEFAULT_SETTINGS as ObsidianLiveSyncSettings;
|
return DEFAULT_SETTINGS as ObsidianLiveSyncSettings;
|
||||||
@@ -170,7 +170,7 @@ class LiveSyncWebApp {
|
|||||||
const file = await fileHandle.getFile();
|
const file = await fileHandle.getFile();
|
||||||
const text = await file.text();
|
const text = await file.text();
|
||||||
return JSON.parse(text);
|
return JSON.parse(text);
|
||||||
} catch (error) {
|
} catch {
|
||||||
// File doesn't exist yet
|
// File doesn't exist yet
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ class FSAPIWatchAdapter implements IStorageEventWatchAdapter {
|
|||||||
if (changedHandle && changedHandle.kind === "file") {
|
if (changedHandle && changedHandle.kind === "file") {
|
||||||
const file = await changedHandle.getFile();
|
const file = await changedHandle.getFile();
|
||||||
const fileInfo = {
|
const fileInfo = {
|
||||||
path: relativePath as any,
|
path: relativePath,
|
||||||
stat: {
|
stat: {
|
||||||
size: file.size,
|
size: file.size,
|
||||||
mtime: file.lastModified,
|
mtime: file.lastModified,
|
||||||
@@ -200,7 +200,7 @@ class FSAPIWatchAdapter implements IStorageEventWatchAdapter {
|
|||||||
}
|
}
|
||||||
} else if (type === "disappeared") {
|
} else if (type === "disappeared") {
|
||||||
const fileInfo = {
|
const fileInfo = {
|
||||||
path: relativePath as any,
|
path: relativePath,
|
||||||
stat: {
|
stat: {
|
||||||
size: 0,
|
size: 0,
|
||||||
mtime: Date.now(),
|
mtime: Date.now(),
|
||||||
@@ -217,7 +217,7 @@ class FSAPIWatchAdapter implements IStorageEventWatchAdapter {
|
|||||||
if (changedHandle && changedHandle.kind === "file") {
|
if (changedHandle && changedHandle.kind === "file") {
|
||||||
const file = await changedHandle.getFile();
|
const file = await changedHandle.getFile();
|
||||||
const fileInfo = {
|
const fileInfo = {
|
||||||
path: relativePath as any,
|
path: relativePath,
|
||||||
stat: {
|
stat: {
|
||||||
size: file.size,
|
size: file.size,
|
||||||
mtime: file.lastModified,
|
mtime: file.lastModified,
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ export class VaultHistoryStore {
|
|||||||
|
|
||||||
async getVaultHistory(): Promise<VaultHistoryItem[]> {
|
async getVaultHistory(): Promise<VaultHistoryItem[]> {
|
||||||
return this.withStore("readonly", async (store) => {
|
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 values = (await this.requestAsPromise(store.getAll())) as unknown[];
|
||||||
const items: VaultHistoryItem[] = [];
|
const items: VaultHistoryItem[] = [];
|
||||||
for (let i = 0; i < keys.length; i++) {
|
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) => {
|
revs.map(async (rev) => {
|
||||||
const leaf = await this.core.databaseFileAccess.fetchEntryMeta(filename, rev);
|
const leaf = await this.core.databaseFileAccess.fetchEntryMeta(filename, rev);
|
||||||
if (leaf == false) {
|
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][]
|
] 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
|
// 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,12 @@ for (const sourceFile of project.getSourceFiles()) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Exclude unit and integration test files
|
// 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;
|
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