@line/ts-remove-unused
Advanced tools
Comparing version 0.8.0 to 0.9.0
104
dist/cli.js
@@ -48,3 +48,3 @@ #!/usr/bin/env node | ||
// lib/util/removeUnusedExport.ts | ||
// lib/util/edit.ts | ||
import ts6 from "typescript"; | ||
@@ -452,2 +452,3 @@ | ||
}; | ||
var isGlobalScopeAugmentation = (module) => !!(module.flags & ts3.NodeFlags.GlobalAugmentation); | ||
var resolve = ({ | ||
@@ -500,2 +501,16 @@ specifier, | ||
}; | ||
var collectName = (node) => { | ||
if (ts3.isIdentifier(node)) { | ||
return [node.getText()]; | ||
} | ||
if (ts3.isObjectBindingPattern(node)) { | ||
return node.elements.flatMap((element) => collectName(element.name)); | ||
} | ||
if (ts3.isArrayBindingPattern(node)) { | ||
return node.elements.flatMap( | ||
(element) => ts3.isOmittedExpression(element) ? [] : collectName(element.name) | ||
); | ||
} | ||
return []; | ||
}; | ||
var fn = ({ | ||
@@ -509,2 +524,3 @@ file, | ||
const exports = []; | ||
const ambientDeclarations = []; | ||
const sourceFile = ts3.createSourceFile( | ||
@@ -522,4 +538,4 @@ file, | ||
if (isExported) { | ||
const name = node.declarationList.declarations.map( | ||
(d) => d.name.getText() | ||
const name = node.declarationList.declarations.flatMap( | ||
(d) => collectName(d.name) | ||
); | ||
@@ -714,6 +730,15 @@ exports.push({ | ||
} | ||
if (ts3.isModuleDeclaration(node)) { | ||
if (node.name.kind === ts3.SyntaxKind.StringLiteral || isGlobalScopeAugmentation(node)) { | ||
ambientDeclarations.push({ | ||
kind: ts3.SyntaxKind.ModuleDeclaration | ||
}); | ||
return; | ||
} | ||
return; | ||
} | ||
node.forEachChild(visit); | ||
}; | ||
sourceFile.forEachChild(visit); | ||
return { imports, exports }; | ||
return { imports, exports, ambientDeclarations }; | ||
}; | ||
@@ -877,3 +902,3 @@ var parseFile = memoize(fn, { | ||
// lib/util/removeUnusedExport.ts | ||
// lib/util/edit.ts | ||
var stripExportKeyword = (syntaxList) => { | ||
@@ -1016,3 +1041,3 @@ const file = ts6.createSourceFile( | ||
} | ||
const { exports } = parseFile({ | ||
const { exports, ambientDeclarations } = parseFile({ | ||
file: targetFile, | ||
@@ -1023,3 +1048,3 @@ content: files.get(targetFile) || "", | ||
}); | ||
if (usage.size === 0 && deleteUnusedFile && !exports.some((v) => "skip" in v && v.skip)) { | ||
if (usage.size === 0 && deleteUnusedFile && ambientDeclarations.length === 0 && !exports.some((v) => "skip" in v && v.skip)) { | ||
return { | ||
@@ -1031,6 +1056,7 @@ operation: "delete" | ||
const logs = []; | ||
const emptyExportDeclarations = []; | ||
exports.forEach((item) => { | ||
switch (item.kind) { | ||
case ts6.SyntaxKind.VariableStatement: { | ||
if (item.skip || item.name.every((it) => usage.has(it))) { | ||
if (item.skip || item.name.some((it) => usage.has(it))) { | ||
break; | ||
@@ -1045,3 +1071,5 @@ } | ||
position: item.start, | ||
// todo: handle variable statement with multiple declarations properly | ||
// todo: consider a more aggressive approach to modify the declaration | ||
// and only export the names that are actually used in other files | ||
// for now, we remove the export keyword only if all names are unused | ||
code: item.name.join(", ") | ||
@@ -1114,5 +1142,12 @@ }); | ||
case "named": { | ||
if (item.skip || item.name.every((it) => usage.has(it))) { | ||
if (item.skip) { | ||
break; | ||
} | ||
if (item.name.length === 0) { | ||
emptyExportDeclarations.push(item); | ||
break; | ||
} | ||
if (item.name.every((it) => usage.has(it))) { | ||
break; | ||
} | ||
const unused = item.name.filter((it) => !usage.has(it)); | ||
@@ -1202,2 +1237,43 @@ const count = item.name.length - unused.length; | ||
}); | ||
if (emptyExportDeclarations.length > 0) { | ||
if (changes.length === exports.length - emptyExportDeclarations.length) { | ||
emptyExportDeclarations.slice(0, -1).forEach((item) => { | ||
changes.push({ | ||
newText: "", | ||
span: item.change.span | ||
}); | ||
logs.push({ | ||
fileName: targetFile, | ||
position: item.start, | ||
code: "export {};" | ||
}); | ||
}); | ||
} else { | ||
emptyExportDeclarations.forEach((item) => { | ||
changes.push({ | ||
newText: "", | ||
span: item.change.span | ||
}); | ||
logs.push({ | ||
fileName: targetFile, | ||
position: item.start, | ||
code: "export {};" | ||
}); | ||
}); | ||
} | ||
} | ||
if (changes.length === exports.length && ambientDeclarations.length > 0 && exports.length !== 0) { | ||
changes.push({ | ||
newText: ` | ||
// auto-generated by ts-remove-unused to preserve module declaration as augmentation | ||
// this may not be necessary if an import statement exists | ||
export {}; | ||
`, | ||
span: { | ||
start: files.get(targetFile)?.length || 0, | ||
length: 0 | ||
} | ||
}); | ||
} | ||
if (changes.length === 0) { | ||
@@ -1247,3 +1323,3 @@ const result2 = { | ||
}; | ||
var removeUnusedExport = async ({ | ||
var edit = async ({ | ||
entrypoints, | ||
@@ -1724,3 +1800,3 @@ fileService, | ||
}); | ||
await removeUnusedExport({ | ||
await edit({ | ||
fileService, | ||
@@ -1771,4 +1847,4 @@ entrypoints, | ||
).option( | ||
"--experimental-recursive", | ||
"Recursively process files until there are no issue" | ||
"-r, --recursive", | ||
"Recursively look into files until the project is clean" | ||
).action((options) => { | ||
@@ -1775,0 +1851,0 @@ const skipArg = options.skip; |
100
dist/main.js
@@ -43,3 +43,3 @@ // lib/remove.ts | ||
// lib/util/removeUnusedExport.ts | ||
// lib/util/edit.ts | ||
import ts6 from "typescript"; | ||
@@ -447,2 +447,3 @@ | ||
}; | ||
var isGlobalScopeAugmentation = (module) => !!(module.flags & ts3.NodeFlags.GlobalAugmentation); | ||
var resolve = ({ | ||
@@ -495,2 +496,16 @@ specifier, | ||
}; | ||
var collectName = (node) => { | ||
if (ts3.isIdentifier(node)) { | ||
return [node.getText()]; | ||
} | ||
if (ts3.isObjectBindingPattern(node)) { | ||
return node.elements.flatMap((element) => collectName(element.name)); | ||
} | ||
if (ts3.isArrayBindingPattern(node)) { | ||
return node.elements.flatMap( | ||
(element) => ts3.isOmittedExpression(element) ? [] : collectName(element.name) | ||
); | ||
} | ||
return []; | ||
}; | ||
var fn = ({ | ||
@@ -504,2 +519,3 @@ file, | ||
const exports = []; | ||
const ambientDeclarations = []; | ||
const sourceFile = ts3.createSourceFile( | ||
@@ -517,4 +533,4 @@ file, | ||
if (isExported) { | ||
const name = node.declarationList.declarations.map( | ||
(d) => d.name.getText() | ||
const name = node.declarationList.declarations.flatMap( | ||
(d) => collectName(d.name) | ||
); | ||
@@ -709,6 +725,15 @@ exports.push({ | ||
} | ||
if (ts3.isModuleDeclaration(node)) { | ||
if (node.name.kind === ts3.SyntaxKind.StringLiteral || isGlobalScopeAugmentation(node)) { | ||
ambientDeclarations.push({ | ||
kind: ts3.SyntaxKind.ModuleDeclaration | ||
}); | ||
return; | ||
} | ||
return; | ||
} | ||
node.forEachChild(visit); | ||
}; | ||
sourceFile.forEachChild(visit); | ||
return { imports, exports }; | ||
return { imports, exports, ambientDeclarations }; | ||
}; | ||
@@ -872,3 +897,3 @@ var parseFile = memoize(fn, { | ||
// lib/util/removeUnusedExport.ts | ||
// lib/util/edit.ts | ||
var stripExportKeyword = (syntaxList) => { | ||
@@ -1011,3 +1036,3 @@ const file = ts6.createSourceFile( | ||
} | ||
const { exports } = parseFile({ | ||
const { exports, ambientDeclarations } = parseFile({ | ||
file: targetFile, | ||
@@ -1018,3 +1043,3 @@ content: files.get(targetFile) || "", | ||
}); | ||
if (usage.size === 0 && deleteUnusedFile && !exports.some((v) => "skip" in v && v.skip)) { | ||
if (usage.size === 0 && deleteUnusedFile && ambientDeclarations.length === 0 && !exports.some((v) => "skip" in v && v.skip)) { | ||
return { | ||
@@ -1026,6 +1051,7 @@ operation: "delete" | ||
const logs = []; | ||
const emptyExportDeclarations = []; | ||
exports.forEach((item) => { | ||
switch (item.kind) { | ||
case ts6.SyntaxKind.VariableStatement: { | ||
if (item.skip || item.name.every((it) => usage.has(it))) { | ||
if (item.skip || item.name.some((it) => usage.has(it))) { | ||
break; | ||
@@ -1040,3 +1066,5 @@ } | ||
position: item.start, | ||
// todo: handle variable statement with multiple declarations properly | ||
// todo: consider a more aggressive approach to modify the declaration | ||
// and only export the names that are actually used in other files | ||
// for now, we remove the export keyword only if all names are unused | ||
code: item.name.join(", ") | ||
@@ -1109,5 +1137,12 @@ }); | ||
case "named": { | ||
if (item.skip || item.name.every((it) => usage.has(it))) { | ||
if (item.skip) { | ||
break; | ||
} | ||
if (item.name.length === 0) { | ||
emptyExportDeclarations.push(item); | ||
break; | ||
} | ||
if (item.name.every((it) => usage.has(it))) { | ||
break; | ||
} | ||
const unused = item.name.filter((it) => !usage.has(it)); | ||
@@ -1197,2 +1232,43 @@ const count = item.name.length - unused.length; | ||
}); | ||
if (emptyExportDeclarations.length > 0) { | ||
if (changes.length === exports.length - emptyExportDeclarations.length) { | ||
emptyExportDeclarations.slice(0, -1).forEach((item) => { | ||
changes.push({ | ||
newText: "", | ||
span: item.change.span | ||
}); | ||
logs.push({ | ||
fileName: targetFile, | ||
position: item.start, | ||
code: "export {};" | ||
}); | ||
}); | ||
} else { | ||
emptyExportDeclarations.forEach((item) => { | ||
changes.push({ | ||
newText: "", | ||
span: item.change.span | ||
}); | ||
logs.push({ | ||
fileName: targetFile, | ||
position: item.start, | ||
code: "export {};" | ||
}); | ||
}); | ||
} | ||
} | ||
if (changes.length === exports.length && ambientDeclarations.length > 0 && exports.length !== 0) { | ||
changes.push({ | ||
newText: ` | ||
// auto-generated by ts-remove-unused to preserve module declaration as augmentation | ||
// this may not be necessary if an import statement exists | ||
export {}; | ||
`, | ||
span: { | ||
start: files.get(targetFile)?.length || 0, | ||
length: 0 | ||
} | ||
}); | ||
} | ||
if (changes.length === 0) { | ||
@@ -1242,3 +1318,3 @@ const result2 = { | ||
}; | ||
var removeUnusedExport = async ({ | ||
var edit = async ({ | ||
entrypoints, | ||
@@ -1719,3 +1795,3 @@ fileService, | ||
}); | ||
await removeUnusedExport({ | ||
await edit({ | ||
fileService, | ||
@@ -1722,0 +1798,0 @@ entrypoints, |
@@ -115,2 +115,5 @@ import ts from 'typescript'; | ||
}; | ||
type AmbientDeclaration = { | ||
kind: ts.SyntaxKind.ModuleDeclaration; | ||
}; | ||
export declare const parseFile: (args_0: { | ||
@@ -129,3 +132,4 @@ file: string; | ||
exports: Export[]; | ||
ambientDeclarations: AmbientDeclaration[]; | ||
}; | ||
export {}; |
@@ -1,1 +0,1 @@ | ||
export { processFile } from './util/removeUnusedExport.js'; | ||
export { processFile } from './util/edit.js'; |
@@ -1,2 +0,2 @@ | ||
// lib/util/removeUnusedExport.ts | ||
// lib/util/edit.ts | ||
import ts6 from "typescript"; | ||
@@ -182,2 +182,3 @@ | ||
}; | ||
var isGlobalScopeAugmentation = (module) => !!(module.flags & ts3.NodeFlags.GlobalAugmentation); | ||
var resolve = ({ | ||
@@ -230,2 +231,16 @@ specifier, | ||
}; | ||
var collectName = (node) => { | ||
if (ts3.isIdentifier(node)) { | ||
return [node.getText()]; | ||
} | ||
if (ts3.isObjectBindingPattern(node)) { | ||
return node.elements.flatMap((element) => collectName(element.name)); | ||
} | ||
if (ts3.isArrayBindingPattern(node)) { | ||
return node.elements.flatMap( | ||
(element) => ts3.isOmittedExpression(element) ? [] : collectName(element.name) | ||
); | ||
} | ||
return []; | ||
}; | ||
var fn = ({ | ||
@@ -239,2 +254,3 @@ file, | ||
const exports = []; | ||
const ambientDeclarations = []; | ||
const sourceFile = ts3.createSourceFile( | ||
@@ -252,4 +268,4 @@ file, | ||
if (isExported) { | ||
const name = node.declarationList.declarations.map( | ||
(d) => d.name.getText() | ||
const name = node.declarationList.declarations.flatMap( | ||
(d) => collectName(d.name) | ||
); | ||
@@ -444,6 +460,15 @@ exports.push({ | ||
} | ||
if (ts3.isModuleDeclaration(node)) { | ||
if (node.name.kind === ts3.SyntaxKind.StringLiteral || isGlobalScopeAugmentation(node)) { | ||
ambientDeclarations.push({ | ||
kind: ts3.SyntaxKind.ModuleDeclaration | ||
}); | ||
return; | ||
} | ||
return; | ||
} | ||
node.forEachChild(visit); | ||
}; | ||
sourceFile.forEachChild(visit); | ||
return { imports, exports }; | ||
return { imports, exports, ambientDeclarations }; | ||
}; | ||
@@ -573,3 +598,3 @@ var parseFile = memoize(fn, { | ||
// lib/util/removeUnusedExport.ts | ||
// lib/util/edit.ts | ||
var stripExportKeyword = (syntaxList) => { | ||
@@ -702,3 +727,3 @@ const file = ts6.createSourceFile( | ||
} | ||
const { exports } = parseFile({ | ||
const { exports, ambientDeclarations } = parseFile({ | ||
file: targetFile, | ||
@@ -709,3 +734,3 @@ content: files.get(targetFile) || "", | ||
}); | ||
if (usage.size === 0 && deleteUnusedFile && !exports.some((v) => "skip" in v && v.skip)) { | ||
if (usage.size === 0 && deleteUnusedFile && ambientDeclarations.length === 0 && !exports.some((v) => "skip" in v && v.skip)) { | ||
return { | ||
@@ -717,6 +742,7 @@ operation: "delete" | ||
const logs = []; | ||
const emptyExportDeclarations = []; | ||
exports.forEach((item) => { | ||
switch (item.kind) { | ||
case ts6.SyntaxKind.VariableStatement: { | ||
if (item.skip || item.name.every((it) => usage.has(it))) { | ||
if (item.skip || item.name.some((it) => usage.has(it))) { | ||
break; | ||
@@ -731,3 +757,5 @@ } | ||
position: item.start, | ||
// todo: handle variable statement with multiple declarations properly | ||
// todo: consider a more aggressive approach to modify the declaration | ||
// and only export the names that are actually used in other files | ||
// for now, we remove the export keyword only if all names are unused | ||
code: item.name.join(", ") | ||
@@ -800,5 +828,12 @@ }); | ||
case "named": { | ||
if (item.skip || item.name.every((it) => usage.has(it))) { | ||
if (item.skip) { | ||
break; | ||
} | ||
if (item.name.length === 0) { | ||
emptyExportDeclarations.push(item); | ||
break; | ||
} | ||
if (item.name.every((it) => usage.has(it))) { | ||
break; | ||
} | ||
const unused = item.name.filter((it) => !usage.has(it)); | ||
@@ -888,2 +923,43 @@ const count = item.name.length - unused.length; | ||
}); | ||
if (emptyExportDeclarations.length > 0) { | ||
if (changes.length === exports.length - emptyExportDeclarations.length) { | ||
emptyExportDeclarations.slice(0, -1).forEach((item) => { | ||
changes.push({ | ||
newText: "", | ||
span: item.change.span | ||
}); | ||
logs.push({ | ||
fileName: targetFile, | ||
position: item.start, | ||
code: "export {};" | ||
}); | ||
}); | ||
} else { | ||
emptyExportDeclarations.forEach((item) => { | ||
changes.push({ | ||
newText: "", | ||
span: item.change.span | ||
}); | ||
logs.push({ | ||
fileName: targetFile, | ||
position: item.start, | ||
code: "export {};" | ||
}); | ||
}); | ||
} | ||
} | ||
if (changes.length === exports.length && ambientDeclarations.length > 0 && exports.length !== 0) { | ||
changes.push({ | ||
newText: ` | ||
// auto-generated by ts-remove-unused to preserve module declaration as augmentation | ||
// this may not be necessary if an import statement exists | ||
export {}; | ||
`, | ||
span: { | ||
start: files.get(targetFile)?.length || 0, | ||
length: 0 | ||
} | ||
}); | ||
} | ||
if (changes.length === 0) { | ||
@@ -890,0 +966,0 @@ const result2 = { |
@@ -44,3 +44,3 @@ { | ||
}, | ||
"version": "0.8.0" | ||
"version": "0.9.0" | ||
} |
@@ -125,10 +125,9 @@ <h1 align="center">ts-remove-unused</h1> | ||
Options: | ||
--project <file> Path to your tsconfig.json | ||
--skip <regexp_pattern> Specify the regexp pattern to match files that should be skipped from transforming | ||
--include-d-ts Include .d.ts files in target for transformation | ||
--check Check if there are any unused exports without removing them | ||
--experimental-recursive Recursively process files until there are no issue | ||
-h, --help Display this message | ||
-v, --version Display version number | ||
--project <file> Path to your tsconfig.json | ||
--skip <regexp_pattern> Specify the regexp pattern to match files that should be skipped from transforming | ||
--include-d-ts Include .d.ts files in target for transformation | ||
--check Check if there are any unused exports without removing them | ||
-r, --recursive Recursively look into files until the project is clean | ||
-h, --help Display this message | ||
-v, --version Display version number | ||
``` | ||
@@ -165,7 +164,7 @@ <!-- prettier-ignore-end --> | ||
#### `--experimental-recursive` | ||
#### `-r, --recursive` | ||
The default behavior of the CLI is to process all files once. Some issues may not be detected if the unused code is a result of the modification of another file in the project. When this option is enabled, ts-remove-unused will recursively re-edit/re-check files that may be affected by a file edit. | ||
This option is still experimental since it's not optimized (yet) for large scale projects. Using this flag for large scale projects is not recommended. | ||
This will take longer but is helpful when you want to edit in one pass. | ||
@@ -172,0 +171,0 @@ ### Use the JavaScript API |
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
158022
4969
255