ts-unused-exports
Advanced tools
Comparing version 2.0.11 to 2.1.0
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var getFileExports = function (exports) { | ||
var ex = {}; | ||
exports.forEach(function (e) { return ex[e] = 0; }); | ||
return ex; | ||
var getFileExports = function (file) { | ||
var exports = {}; | ||
file.exports.forEach(function (e) { return exports[e] = 0; }); | ||
return { exports: exports, path: file.fullPath }; | ||
}; | ||
@@ -11,3 +11,3 @@ var getExportMap = function (files) { | ||
files.forEach(function (file) { | ||
map[file.path] = getFileExports(file.exports); | ||
map[file.path] = getFileExports(file); | ||
}); | ||
@@ -18,3 +18,3 @@ return map; | ||
Object.keys(imports).forEach(function (key) { | ||
var ex = exportMap[key]; | ||
var ex = exportMap[key] && exportMap[key].exports; | ||
if (!ex) | ||
@@ -36,6 +36,6 @@ return; | ||
.forEach(function (ex) { | ||
delete fileExports[ex]; | ||
Object.keys(exportMap[ex.slice(2)]) | ||
delete fileExports.exports[ex]; | ||
Object.keys(exportMap[ex.slice(2)].exports) | ||
.filter(function (e) { return e != 'default'; }) | ||
.forEach(function (key) { return fileExports[key] = 0; }); | ||
.forEach(function (key) { return fileExports.exports[key] = 0; }); | ||
}); | ||
@@ -50,8 +50,9 @@ }); | ||
Object.keys(exportMap).forEach(function (file) { | ||
var ex = exportMap[file]; | ||
var unused = Object.keys(ex).filter(function (k) { return ex[k] === 0; }); | ||
var expItem = exportMap[file]; | ||
var exports = expItem.exports, path = expItem.path; | ||
var unused = Object.keys(exports).filter(function (k) { return exports[k] === 0; }); | ||
if (unused.length) | ||
analysis[file] = unused; | ||
analysis[path] = unused; | ||
}); | ||
return analysis; | ||
}); |
import { Analysis } from './analyzer'; | ||
import { TsConfig } from './types'; | ||
export declare const loadTsConfig: (tsconfigPath: string, explicitFiles?: string[] | undefined) => TsConfig; | ||
declare const _default: (tsconfigPath: string, files?: string[] | undefined) => Analysis; | ||
export default _default; |
@@ -8,2 +8,3 @@ "use strict"; | ||
var analyzer_1 = require("./analyzer"); | ||
var argsParser_1 = require("./argsParser"); | ||
var parseTsConfig = function (tsconfigPath) { | ||
@@ -22,2 +23,5 @@ var basePath = path_1.resolve(path_1.dirname(tsconfigPath)); | ||
&& result.raw.compilerOptions.baseUrl, | ||
paths: result.raw | ||
&& result.raw.compilerOptions | ||
&& result.raw.compilerOptions.paths, | ||
files: result.fileNames, | ||
@@ -30,9 +34,10 @@ }; | ||
}; | ||
var loadTsConfig = function (tsconfigPath, explicitFiles) { | ||
var _a = parseTsConfig(tsconfigPath), baseUrl = _a.baseUrl, files = _a.files; | ||
return { baseUrl: baseUrl, files: explicitFiles || files }; | ||
exports.loadTsConfig = function (tsconfigPath, explicitFiles) { | ||
var _a = parseTsConfig(tsconfigPath), baseUrl = _a.baseUrl, files = _a.files, paths = _a.paths; | ||
return { baseUrl: baseUrl, paths: paths, files: explicitFiles || files }; | ||
}; | ||
exports.default = (function (tsconfigPath, files) { | ||
var tsConfig = loadTsConfig(tsconfigPath, files); | ||
return analyzer_1.default(parser_1.default(path_1.dirname(tsconfigPath), tsConfig.files, tsConfig.baseUrl)); | ||
var args = argsParser_1.extractOptionsFromFiles(files); | ||
var tsConfig = exports.loadTsConfig(tsconfigPath, args.tsFiles); | ||
return analyzer_1.default(parser_1.default(path_1.dirname(tsconfigPath), tsConfig, args.options)); | ||
}); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var chalk_1 = require("chalk"); | ||
var app_1 = require("./app"); | ||
var fs_1 = require("fs"); | ||
var usage_1 = require("./usage"); | ||
var argsParser_1 = require("./argsParser"); | ||
var _a = process.argv.slice(2), tsconfig = _a[0], tsFiles = _a.slice(1); | ||
if (!tsconfig || !fs_1.existsSync(tsconfig) || !fs_1.statSync(tsconfig).isFile()) { | ||
console.error("\n usage: ts-unused-exports path/to/tsconfig.json [file1.ts file2.ts]\n\n Note: if no file is specified after tsconfig, the files will be read from the\n tsconfig's \"files\" key which must be present.\n\n If the files are specified, their path must be relative to the tsconfig file.\n For example, given:\n /\n |-- config\n | -- tsconfig.json\n -- src\n -- file.ts\n\n Then the usage would be:\n ts-unused-exports config/tsconfig.json ../src/file.ts\n "); | ||
if (!argsParser_1.hasValidArgs()) { | ||
usage_1.showUsage(); | ||
process.exit(-1); | ||
@@ -15,5 +17,7 @@ } | ||
var files = Object.keys(analysis_1); | ||
console.log(files.length + " module" + (files.length == 1 ? '' : 's') + " with unused exports"); | ||
files.forEach(function (path) { return console.log(path + ": " + analysis_1[path].join(', ')); }); | ||
process.exit(Math.min(255, files.length)); | ||
console.log(chalk_1.default.red(chalk_1.default.bold(files.length.toString()) + " module" + (files.length == 1 ? '' : 's') + " with unused exports")); | ||
files.forEach(function (path) { return console.log(path + ": " + chalk_1.default.bold.yellow(analysis_1[path].join(", "))); }); | ||
if (argsParser_1.extractOptionsFromFiles(tsFiles).options.exitWithCount) { | ||
process.exit(files.length); | ||
} | ||
} | ||
@@ -20,0 +24,0 @@ catch (e) { |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var fs_1 = require("fs"); | ||
var fs_2 = require("fs"); | ||
var path_1 = require("path"); | ||
var app_1 = require("./app"); | ||
var argsParser_1 = require("./argsParser"); | ||
var parser_1 = require("./parser"); | ||
var usage_1 = require("./usage"); | ||
var getFileMap = function (files) { | ||
@@ -34,4 +35,5 @@ var map = {}; | ||
; | ||
var analyzeDeps = function (tsconfigPath) { | ||
var files = parser_1.default(path_1.dirname(tsconfigPath), JSON.parse(fs_1.readFileSync(tsconfigPath, { encoding: 'utf8' })).files); | ||
var analyzeDeps = function (tsconfigPath, extraOptions) { | ||
var tsConfig = app_1.loadTsConfig(tsconfigPath); | ||
var files = parser_1.default(path_1.dirname(tsconfigPath), tsConfig, extraOptions); | ||
var fileMap = getFileMap(files); | ||
@@ -42,5 +44,5 @@ var analysis = {}; | ||
}; | ||
var _a = process.argv.slice(2), tsconfig = _a[0], filter = _a[1]; | ||
if (!tsconfig || !fs_2.existsSync(tsconfig) || !fs_2.statSync(tsconfig).isFile()) { | ||
console.error("usage: deps path/to/tsconfig.json [filter]"); | ||
var _a = process.argv.slice(2), tsconfig = _a[0], filter = _a[1], options = _a.slice(2); | ||
if (!argsParser_1.hasValidArgs()) { | ||
usage_1.showUsage(); | ||
process.exit(-1); | ||
@@ -51,3 +53,4 @@ } | ||
}; | ||
var analysis = analyzeDeps(tsconfig); | ||
var parsedOptions = argsParser_1.extractOptionsFromFiles(options).options; | ||
var analysis = analyzeDeps(tsconfig, parsedOptions); | ||
var deps = getValues(analysis); | ||
@@ -54,0 +57,0 @@ deps.sort(function (a, b) { return a.depth - b.depth; }); |
@@ -1,3 +0,3 @@ | ||
import { File } from './types'; | ||
declare const _default: (rootDir: string, paths: string[], baseUrl?: string | undefined) => File[]; | ||
import { File, TsConfig, ExtraCommandLineOptions } from './types'; | ||
declare const _default: (rootDir: string, TsConfig: TsConfig, extraOptions?: ExtraCommandLineOptions | undefined) => File[]; | ||
export default _default; |
@@ -6,3 +6,5 @@ "use strict"; | ||
var ts = require("typescript"); | ||
var tsconfigPaths = require("tsconfig-paths"); | ||
var TRIM_QUOTES = /^['"](.*)['"]$/; | ||
var EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx']; | ||
var star = ['*']; | ||
@@ -45,3 +47,3 @@ var getFrom = function (moduleSpecifier) { | ||
? decl.exportClause.elements | ||
.map(function (e) { return (e.propertyName || e.name).text; }) | ||
.map(function (e) { return (e.name || e.propertyName).text; }) | ||
: []; | ||
@@ -100,3 +102,3 @@ }; | ||
}; | ||
var mapFile = function (rootDir, path, file, baseUrl) { | ||
var mapFile = function (rootDir, path, file, baseUrl, paths) { | ||
var imports = {}; | ||
@@ -106,9 +108,21 @@ var exports = []; | ||
var baseDir = baseUrl && path_1.resolve(rootDir, baseUrl); | ||
var tsconfigPathsMatcher = baseDir && paths && tsconfigPaths.createMatchPath(baseDir, paths); | ||
var addImport = function (fw) { | ||
var from = fw.from, what = fw.what; | ||
var key = from[0] == '.' | ||
? relativeTo(rootDir, path, from) | ||
: baseDir && baseUrl && isRelativeToBaseDir(baseDir, from) | ||
? path_1.join(baseUrl, from) | ||
: undefined; | ||
var getKey = function (from) { | ||
if (from[0] == '.') { | ||
return relativeTo(rootDir, path, from); | ||
} | ||
else if (baseDir && baseUrl) { | ||
var matchedPath = void 0; | ||
return isRelativeToBaseDir(baseDir, from) | ||
? baseUrl && path_1.join(baseUrl, from) | ||
: tsconfigPathsMatcher && | ||
(matchedPath = tsconfigPathsMatcher(from, undefined, undefined, EXTENSIONS)) | ||
? matchedPath.replace("" + baseDir + path_1.sep, '') | ||
: undefined; | ||
} | ||
return undefined; | ||
}; | ||
var key = getKey(from); | ||
if (!key) | ||
@@ -121,2 +135,12 @@ return undefined; | ||
ts.forEachChild(file, function (node) { | ||
var comments = ts.getLeadingCommentRanges(file.getFullText(), node.getFullStart()); | ||
if (comments) { | ||
var commentRange = comments[comments.length - 1]; | ||
var commentText = file | ||
.getFullText() | ||
.substring(commentRange.pos, commentRange.end); | ||
if (commentText === '// ts-unused-exports:disable-next-line') { | ||
return; | ||
} | ||
} | ||
var kind = node.kind; | ||
@@ -166,2 +190,3 @@ if (kind === ts.SyntaxKind.ImportDeclaration) { | ||
path: name, | ||
fullPath: path, | ||
imports: imports, | ||
@@ -171,47 +196,23 @@ exports: exports | ||
}; | ||
var parseFile = function (rootDir, path, baseUrl) { | ||
var parseFile = function (rootDir, path, baseUrl, paths) { | ||
return mapFile(rootDir, path, ts.createSourceFile(path, fs_1.readFileSync(path, { encoding: 'utf8' }), ts.ScriptTarget.ES2015, | ||
/*setParentNodes */ true), baseUrl); | ||
/*setParentNodes */ true), baseUrl, paths); | ||
}; | ||
var resolvePath = function (rootDir) { return function (path) { | ||
var tsPath = path + ".ts"; | ||
if (fs_1.existsSync(path_1.resolve(rootDir, tsPath))) | ||
return tsPath; | ||
var tsxPath = path + ".tsx"; | ||
if (fs_1.existsSync(path_1.resolve(rootDir, tsxPath))) | ||
return tsxPath; | ||
var jsIndexPath = path + "/index.js"; | ||
if (fs_1.existsSync(path_1.resolve(rootDir, jsIndexPath))) | ||
return jsIndexPath; | ||
var tsIndexPath = path + "/index.ts"; | ||
if (fs_1.existsSync(path_1.resolve(rootDir, tsIndexPath))) | ||
return tsIndexPath; | ||
var tsxIndexPath = path + "/index.tsx"; | ||
if (fs_1.existsSync(path_1.resolve(rootDir, tsxIndexPath))) | ||
return tsxIndexPath; | ||
var jsPath = path + ".js"; | ||
if (fs_1.existsSync(path_1.resolve(rootDir, jsPath))) | ||
return jsPath; | ||
if (fs_1.existsSync(path_1.resolve(rootDir, path))) { | ||
return null; // we have an explicit path that is *not* a TS (e.g. `.sass`). | ||
var parsePaths = function (rootDir, _a, extraOptions) { | ||
var baseUrl = _a.baseUrl, filePaths = _a.files, paths = _a.paths; | ||
var files = filePaths | ||
.filter(function (p) { return p.indexOf('.d.') == -1 && !shouldPathBeIgnored(p, extraOptions.pathsToIgnore); }) | ||
.map(function (path) { return parseFile(rootDir, path_1.resolve(rootDir, path), baseUrl, paths); }); | ||
return files; | ||
}; | ||
// Allow disabling of results, by path from command line (useful for large projects) | ||
var shouldPathBeIgnored = function (path, pathsToIgnore) { | ||
if (!pathsToIgnore) { | ||
return false; | ||
} | ||
throw "Cannot find module '" + path + "'.\n I've tried the following paths and none of them works:\n - " + tsPath + "\n - " + tsxPath + "\n - " + tsIndexPath + "\n - " + tsxIndexPath + "\n - " + jsPath + "\n - " + path + " (only to skip it later)\n "; | ||
}; }; | ||
var notNull = function (v) { return v !== null; }; | ||
var parsePaths = function (rootDir, paths, baseUrl, otherFiles) { | ||
var _a; | ||
var files = otherFiles.concat(paths | ||
.filter(function (p) { return p.indexOf('.d.') == -1; }) | ||
.map(function (path) { return parseFile(rootDir, path_1.resolve(rootDir, path), baseUrl); })); | ||
var found = {}; | ||
files.forEach(function (f) { return found[f.path] = f; }); | ||
var missingImports = (_a = []).concat.apply(_a, files.map(function (f) { return Object.keys(f.imports); })).filter(function (i) { return !found[i]; }) | ||
.map(resolvePath(rootDir)) | ||
.filter(notNull); | ||
return missingImports.length | ||
? parsePaths(rootDir, missingImports, baseUrl, files) | ||
: files; | ||
return pathsToIgnore.some(function (ignore) { return path.indexOf(ignore) >= 0; }); | ||
}; | ||
exports.default = (function (rootDir, paths, baseUrl) { | ||
return parsePaths(rootDir, paths, baseUrl, []); | ||
exports.default = (function (rootDir, TsConfig, extraOptions) { | ||
var activeExtraOptions = extraOptions || {}; | ||
return parsePaths(rootDir, TsConfig, activeExtraOptions); | ||
}); |
@@ -6,2 +6,3 @@ export interface Imports { | ||
path: string; | ||
fullPath: string; | ||
imports: Imports; | ||
@@ -13,1 +14,13 @@ exports: string[]; | ||
} | ||
export interface TsConfigPaths { | ||
[glob: string]: string[]; | ||
} | ||
export interface TsConfig { | ||
baseUrl?: string; | ||
paths?: TsConfigPaths; | ||
files: string[]; | ||
} | ||
export interface ExtraCommandLineOptions { | ||
exitWithCount?: boolean; | ||
pathsToIgnore?: string[]; | ||
} |
{ | ||
"name": "ts-unused-exports", | ||
"version": "2.0.11", | ||
"version": "2.1.0", | ||
"description": "ts-unused-exports finds unused exported symbols in your Typescript project", | ||
@@ -25,3 +25,5 @@ "main": "lib/app.js", | ||
"watch": "tsc -w", | ||
"test": "npm run build && jasmine", | ||
"test": "npm run build && npm run test:unit && npm run test:itest", | ||
"test:unit": "jasmine", | ||
"test:itest": "./bin/ts-unused-exports ./example/tsconfig.json", | ||
"exec": "bin/ts-unused-exports" | ||
@@ -39,5 +41,7 @@ }, | ||
"dependencies": { | ||
"chalk": "^2.4.1", | ||
"strip-json-comments": "^2.0.1", | ||
"tsconfig-paths": "^3.5.0", | ||
"typescript": "^2.9.2" | ||
} | ||
} |
@@ -23,3 +23,3 @@ ts-unused-exports | ||
```shell | ||
./node_modules/.bin/ts-unused-exports path/to/tsconfig.json [file1.ts ...] | ||
./node_modules/.bin/ts-unused-exports path/to/tsconfig.json [file1.ts ...] [options] | ||
``` | ||
@@ -30,6 +30,6 @@ | ||
```shell | ||
ts-unused-exports path/to/tsconfig.json [file1.ts ...] | ||
ts-unused-exports path/to/tsconfig.json [file1.ts ...] [options] | ||
``` | ||
or: | ||
or, as a library: | ||
```ts | ||
@@ -39,2 +39,3 @@ import analyzeTsConfig from 'ts-unused-exports'; | ||
// or const result = analyzeTsConfig('path/to/tsconfig.json', ['file1.ts']); | ||
// or const result = analyzeTsConfig('path/to/tsconfig.json', ['file1.ts', '--ignorePaths=math']); | ||
@@ -45,4 +46,13 @@ // result : { [index:string] : string[] } | ||
Note that if `ts-unused-exports` is called without files, the files will be read from the tsconfig's `files` key which must be present. If called with files, then those file paths should be relative to the `tsconfig.json`, just like you would specifie them in your tsconfig's `files` key. | ||
Options: | ||
| Option name | Description | Example | | ||
|---|---|---| | ||
| `ignorePaths` | Exclude files that match the given path segments. | `--ignorePaths=math;utils` | | ||
| `exitWithCount` | Set the process exit code to be the count of files that have unused exports. | `--exitWithCount` | | ||
Note that if `ts-unused-exports` is called without files, the files will be read from the tsconfig's `files` or `include` key which must be present. If called with files, then those file paths should be relative to the `tsconfig.json`, just like you would specifie them in your tsconfig's `files` key. | ||
`ts-unused-exports` also resolves path aliases specified in tsconfig's `paths` object. | ||
Why should I use this? | ||
@@ -91,10 +101,11 @@ ---------------------- | ||
Also note the exit status (which equals the number of offending modules): | ||
If the option `--exitWithCount` is used, then the exit status will equal the number of offending modules: | ||
```shell | ||
echo $? | ||
# or: echo %ERRORLEVEL% | ||
1 | ||
25 | ||
``` | ||
note: normally the exit code is 0, unless there was a problem with the arguments or the files. | ||
If not using `files` inside your `tsconfig` (e.g. using `webpack` with `ts-loader`), you can explicitly specify the files to check in the command line: | ||
If not using `files` or `include` inside your `tsconfig` (e.g. using `webpack` with `ts-loader`), you can explicitly specify the files to check in the command line: | ||
@@ -110,1 +121,8 @@ ```shell | ||
``` | ||
You can use comment flags to ignore exports: | ||
```ts | ||
// ts-unused-exports:disable-next-line | ||
export function add2(x:number) { return x + 2; } | ||
``` |
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
123
3
27148
4
21
545
1
+ Addedchalk@^2.4.1
+ Addedtsconfig-paths@^3.5.0
+ Added@types/json5@0.0.29(transitive)
+ Addedansi-styles@3.2.1(transitive)
+ Addedchalk@2.4.2(transitive)
+ Addedcolor-convert@1.9.3(transitive)
+ Addedcolor-name@1.1.3(transitive)
+ Addedescape-string-regexp@1.0.5(transitive)
+ Addedhas-flag@3.0.0(transitive)
+ Addedjson5@1.0.2(transitive)
+ Addedminimist@1.2.8(transitive)
+ Addedstrip-bom@3.0.0(transitive)
+ Addedsupports-color@5.5.0(transitive)
+ Addedtsconfig-paths@3.15.0(transitive)