@line/ts-remove-unused
Advanced tools
Comparing version 0.3.0 to 0.3.1
@@ -182,2 +182,3 @@ #!/usr/bin/env node | ||
var isUsedFile = (languageService, sourceFile) => { | ||
const { fileName } = sourceFile; | ||
let isUsed = false; | ||
@@ -196,7 +197,5 @@ const visit = (node) => { | ||
} | ||
const count = references.flatMap((v) => v.references).length; | ||
if (ts.isExportSpecifier(node) && count > 2) { | ||
const count = references.filter((v) => v.definition.fileName !== fileName).flatMap((v) => v.references).length; | ||
if (count > 0) { | ||
isUsed = true; | ||
} else if (!ts.isExportSpecifier(node) && count > 1) { | ||
isUsed = true; | ||
} | ||
@@ -211,2 +210,3 @@ return; | ||
var getUnusedExports = (languageService, sourceFile) => { | ||
const { fileName } = sourceFile; | ||
const result = []; | ||
@@ -219,7 +219,5 @@ const visit = (node) => { | ||
} | ||
const count = references.flatMap((v) => v.references).length; | ||
if (ts.isExportSpecifier(node) && count === 2) { | ||
const count = references.filter((v) => v.definition.fileName !== fileName).flatMap((v) => v.references).length; | ||
if (count === 0) { | ||
result.push(node); | ||
} else if (!ts.isExportSpecifier(node) && count === 1) { | ||
result.push(node); | ||
} | ||
@@ -252,5 +250,13 @@ return; | ||
}; | ||
var getTextChanges = (languageService, sourceFile, editTracker) => { | ||
var getTextChanges = (languageService, file, editTracker) => { | ||
const sourceFile = languageService.getProgram()?.getSourceFile(file); | ||
if (!sourceFile) { | ||
throw new Error("source file not found"); | ||
} | ||
const changes = []; | ||
let aborted = false; | ||
for (const node of getUnusedExports(languageService, sourceFile)) { | ||
if (aborted === true) { | ||
break; | ||
} | ||
if (ts.isExportSpecifier(node)) { | ||
@@ -272,2 +278,3 @@ const specifierCount = Array.from(node.parent.elements).length; | ||
} | ||
aborted = true; | ||
changes.push({ | ||
@@ -321,4 +328,6 @@ newText: getUpdatedExportDeclaration(node.parent.parent, node), | ||
} | ||
const syntaxList = node.getChildren().find((n) => n.kind === ts.SyntaxKind.SyntaxList); | ||
if (!syntaxList) { | ||
const syntaxListIndex = node.getChildren().findIndex((n) => n.kind === ts.SyntaxKind.SyntaxList); | ||
const syntaxList = node.getChildren()[syntaxListIndex]; | ||
const syntaxListNextSibling = node.getChildren()[syntaxListIndex + 1]; | ||
if (!syntaxList || !syntaxListNextSibling) { | ||
throw new Error("syntax list not found"); | ||
@@ -329,4 +338,4 @@ } | ||
span: { | ||
start: syntaxList.getFullStart(), | ||
length: syntaxList.getFullWidth() | ||
start: syntaxList.getStart(), | ||
length: syntaxListNextSibling.getStart() - syntaxList.getStart() | ||
} | ||
@@ -339,3 +348,3 @@ }); | ||
} | ||
return changes; | ||
return { changes, done: !aborted }; | ||
}; | ||
@@ -378,9 +387,19 @@ var disabledEditTracker = { | ||
} | ||
const changes = getTextChanges(languageService, sourceFile, editTracker); | ||
let content = fileService.get(file); | ||
do { | ||
const { changes, done } = getTextChanges( | ||
languageService, | ||
file, | ||
editTracker | ||
); | ||
content = applyTextChanges(content, changes); | ||
fileService.set(file, content); | ||
if (done) { | ||
break; | ||
} | ||
} while (true); | ||
editTracker.end(file); | ||
const oldContent = fileService.get(file); | ||
let newContent = applyTextChanges(oldContent, changes); | ||
if (enableCodeFix) { | ||
while (true) { | ||
fileService.set(file, newContent); | ||
fileService.set(file, content); | ||
const result = applyCodeFix({ | ||
@@ -391,9 +410,9 @@ fixId: fixIdDelete, | ||
}); | ||
if (result === newContent) { | ||
if (result === content) { | ||
break; | ||
} | ||
newContent = result; | ||
content = result; | ||
} | ||
fileService.set(file, newContent); | ||
newContent = applyCodeFix({ | ||
fileService.set(file, content); | ||
content = applyCodeFix({ | ||
fixId: fixIdDeleteImports, | ||
@@ -404,3 +423,3 @@ fileName: file, | ||
} | ||
fileService.set(file, newContent); | ||
fileService.set(file, content); | ||
} | ||
@@ -407,0 +426,0 @@ }; |
@@ -177,2 +177,3 @@ // lib/remove.ts | ||
var isUsedFile = (languageService, sourceFile) => { | ||
const { fileName } = sourceFile; | ||
let isUsed = false; | ||
@@ -191,7 +192,5 @@ const visit = (node) => { | ||
} | ||
const count = references.flatMap((v) => v.references).length; | ||
if (ts.isExportSpecifier(node) && count > 2) { | ||
const count = references.filter((v) => v.definition.fileName !== fileName).flatMap((v) => v.references).length; | ||
if (count > 0) { | ||
isUsed = true; | ||
} else if (!ts.isExportSpecifier(node) && count > 1) { | ||
isUsed = true; | ||
} | ||
@@ -206,2 +205,3 @@ return; | ||
var getUnusedExports = (languageService, sourceFile) => { | ||
const { fileName } = sourceFile; | ||
const result = []; | ||
@@ -214,7 +214,5 @@ const visit = (node) => { | ||
} | ||
const count = references.flatMap((v) => v.references).length; | ||
if (ts.isExportSpecifier(node) && count === 2) { | ||
const count = references.filter((v) => v.definition.fileName !== fileName).flatMap((v) => v.references).length; | ||
if (count === 0) { | ||
result.push(node); | ||
} else if (!ts.isExportSpecifier(node) && count === 1) { | ||
result.push(node); | ||
} | ||
@@ -247,5 +245,13 @@ return; | ||
}; | ||
var getTextChanges = (languageService, sourceFile, editTracker) => { | ||
var getTextChanges = (languageService, file, editTracker) => { | ||
const sourceFile = languageService.getProgram()?.getSourceFile(file); | ||
if (!sourceFile) { | ||
throw new Error("source file not found"); | ||
} | ||
const changes = []; | ||
let aborted = false; | ||
for (const node of getUnusedExports(languageService, sourceFile)) { | ||
if (aborted === true) { | ||
break; | ||
} | ||
if (ts.isExportSpecifier(node)) { | ||
@@ -267,2 +273,3 @@ const specifierCount = Array.from(node.parent.elements).length; | ||
} | ||
aborted = true; | ||
changes.push({ | ||
@@ -316,4 +323,6 @@ newText: getUpdatedExportDeclaration(node.parent.parent, node), | ||
} | ||
const syntaxList = node.getChildren().find((n) => n.kind === ts.SyntaxKind.SyntaxList); | ||
if (!syntaxList) { | ||
const syntaxListIndex = node.getChildren().findIndex((n) => n.kind === ts.SyntaxKind.SyntaxList); | ||
const syntaxList = node.getChildren()[syntaxListIndex]; | ||
const syntaxListNextSibling = node.getChildren()[syntaxListIndex + 1]; | ||
if (!syntaxList || !syntaxListNextSibling) { | ||
throw new Error("syntax list not found"); | ||
@@ -324,4 +333,4 @@ } | ||
span: { | ||
start: syntaxList.getFullStart(), | ||
length: syntaxList.getFullWidth() | ||
start: syntaxList.getStart(), | ||
length: syntaxListNextSibling.getStart() - syntaxList.getStart() | ||
} | ||
@@ -334,3 +343,3 @@ }); | ||
} | ||
return changes; | ||
return { changes, done: !aborted }; | ||
}; | ||
@@ -373,9 +382,19 @@ var disabledEditTracker = { | ||
} | ||
const changes = getTextChanges(languageService, sourceFile, editTracker); | ||
let content = fileService.get(file); | ||
do { | ||
const { changes, done } = getTextChanges( | ||
languageService, | ||
file, | ||
editTracker | ||
); | ||
content = applyTextChanges(content, changes); | ||
fileService.set(file, content); | ||
if (done) { | ||
break; | ||
} | ||
} while (true); | ||
editTracker.end(file); | ||
const oldContent = fileService.get(file); | ||
let newContent = applyTextChanges(oldContent, changes); | ||
if (enableCodeFix) { | ||
while (true) { | ||
fileService.set(file, newContent); | ||
fileService.set(file, content); | ||
const result = applyCodeFix({ | ||
@@ -386,9 +405,9 @@ fixId: fixIdDelete, | ||
}); | ||
if (result === newContent) { | ||
if (result === content) { | ||
break; | ||
} | ||
newContent = result; | ||
content = result; | ||
} | ||
fileService.set(file, newContent); | ||
newContent = applyCodeFix({ | ||
fileService.set(file, content); | ||
content = applyCodeFix({ | ||
fixId: fixIdDeleteImports, | ||
@@ -399,3 +418,3 @@ fileName: file, | ||
} | ||
fileService.set(file, newContent); | ||
fileService.set(file, content); | ||
} | ||
@@ -402,0 +421,0 @@ }; |
@@ -44,3 +44,3 @@ { | ||
}, | ||
"version": "0.3.0" | ||
"version": "0.3.1" | ||
} |
# ts-remove-unused | ||
<div align="center"> | ||
<img width="480" src="./media/screenshot.png" /> | ||
</div> | ||
[![npm version](https://badge.fury.io/js/@line%2Fts-remove-unused.svg)](https://badge.fury.io/js/@line%2Fts-remove-unused) | ||
> Remove unused code from your TypeScript project | ||
## Introduction | ||
When you enable `compilerOptions.noUnusedLocals` for your TypeScript project, it's possible to detect declarations that are not referenced in your file. | ||
```typescript | ||
// TypeScript will throw error: 'a' is declared but its value is never read. | ||
const a = 'a'; | ||
``` | ||
However when this declaration is exported and is not referenced by any file in the project, it's difficult to recognize this. | ||
```typescript | ||
// no errors will be reported even if the declaration is not used across the entire project. | ||
export const a = 'a'; | ||
``` | ||
This is when ts-remove-unused comes in handy. ts-remove-unused is a CLI tools made on top of TypeScript that reports/fixes unused exports. | ||
Let's say you have the following file: | ||
```typescript | ||
export const a = 'a'; | ||
export const b = 'b'; | ||
export const c = 'c'; | ||
console.log(b); | ||
``` | ||
When `a` and `b` are not used in all other files across the project, ts-remove-unused will modify the file to be: | ||
```typescript | ||
const b = 'b'; | ||
export const c = 'c'; | ||
console.log(b); | ||
``` | ||
If you have another file in your project: | ||
```typescript | ||
export const d = 'd'; | ||
export const e = 'e'; | ||
``` | ||
When `d` and `e` are not used in all other files across the project, ts-remove-unused will delete the file for you. | ||
Now you don't have to worry about removing your unused code! | ||
ts-remove-unused supports various exports including variable declarations (`export const`, `export let`), function declarations, class declarations, interface declarations, type alias declarations, default exports... | ||
## Install | ||
@@ -6,0 +66,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
57614
1435
153
0