GithubHelp home page GithubHelp logo

yamafaktory / shrimpit Goto Github PK

View Code? Open in Web Editor NEW
259.0 6.0 16.0 1.41 MB

Shrimpit 🍤 is a small CLI analysis tool for checking unused JavaScript, JSX & Vue templates ES6 exports in your project.

License: MIT License

JavaScript 98.81% TypeScript 1.19%
es6 jsx vuejs exports imports import export javascript modules tool

shrimpit's Introduction

Shrimpit 🍤 Build Status npm version Standard - JavaScript Style Guide

Shrimpit is a small CLI analysis tool for checking unused JavaScript, JSX & Vue templates ES6 exports in your project.

Install

npm

npm i -g shrimpit

yarn

yarn global add shrimpit

Usage

shrimpit path/to/your/files /another/path

Globbing patterns are also supported:

shrimpit test/**/*.js

Adding the --tree flag will output the complete files tree with all the imports and the exports per file:

shrimpit --tree path/to/your/files

Please note that default unnamed exports are rendered as default (unnamed):

shrimpit test --tree
 Shrimpit!

 > Files tree

{ test:
   { core:
      { a:
         { 'a.js':
            { imports:
               [ { location: 'test/core/b/b.js',
                   name: 'test',
                   unnamedDefault: true },
                 { location: 'test/core/b/b.js',
                   name: 'a',
                   unnamedDefault: false },
                 { location: 'test/core/c/c.js',
                   name: 'User',
                   unnamedDefault: true } ],
              exports:
               [ { location: 'test/core/a/a.js',
                   name: 'a',
                   unnamedDefault: false },
                 { location: 'test/core/a/a.js',
                   name: 'c',
                   unnamedDefault: false },
                 { location: 'test/core/a/a.js', name: 'd', unnamedDefault: true } ] } },
        b:
         { 'b.js':
            { imports:
               [ { location: 'test/core/c/c.js',
                   name: 'Cat',
                   unnamedDefault: false },
                 { location: 'test/core/d/d.js',
                   name: 'unamedFunction',
                   unnamedDefault: true },
                 { location: 'test/core/a/a.js',
                   name: 'a',
                   unnamedDefault: false },
                 { location: 'test/core/a/a.js',
                   name: 'c',
                   unnamedDefault: false },
                 { location: 'test/core/a/a.js', name: 'd', unnamedDefault: true } ],
              exports:
               [ { location: 'test/core/b/b.js',
                   name: 'a',
                   unnamedDefault: false },
                 { location: 'test/core/b/b.js',
                   name: 'b',
                   unnamedDefault: false },
                 { location: 'test/core/b/b.js',
                   name: 'default (unnamed)',
                   unnamedDefault: true } ] } },
        c:
         { 'c.js':
            { imports:
               [ { location: 'test/core/a/a.js',
                   name: 'a',
                   unnamedDefault: false },
                 { location: 'test/core/a/a.js',
                   name: 'c',
                   unnamedDefault: false },
                 { location: 'test/core/a/a.js',
                   name: 'd',
                   unnamedDefault: false },
                 { location: 'test/core/b/b.js',
                   name: 'b',
                   unnamedDefault: false } ],
              exports:
               [ { location: 'test/core/c/c.js',
                   name: 'Cat',
                   unnamedDefault: false },
                 { location: 'test/core/c/c.js',
                   name: 'User',
                   unnamedDefault: true } ] } },
        d:
         { 'd.js':
            { imports: [],
              exports:
               [ { location: 'test/core/d/d.js',
                   name: 'test/core/d',
                   unnamedDefault: true } ] } } } } }

 > Unused exports

All Clear Ahead, Captain.

Flow & Vue

Shrimpit supports Flow annotations and Vue templates out of the box!

TypeScript (experimental)

Since Babel 7, the TypeScript AST can directly be parsed. You can use the --typescript flag to enable it:

shrimpit --tree --typescript path/to/your/files

Please note that the Flow and TypeScript parsers are mutually exclusive.

Linting

The code quality is checked by the JavaScript Standard Style.

License

Released under the MIT license by Davy Duperron.

shrimpit's People

Contributors

benadamstyles avatar greenkeeper[bot] avatar jaydenseric avatar yamafaktory avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

shrimpit's Issues

Version 10 of node.js has been released

Version 10 of Node.js (code name Dubnium) has been released! 🎊

To see what happens to your code in Node.js 10, Greenkeeper has created a branch with the following changes:

  • Added the new Node.js version to your .travis.yml
  • The new Node.js version is in-range for the engines in 1 of your package.json files, so that was left alone

If you’re interested in upgrading this repo to Node.js 10, you can open a PR with these changes. Please note that this issue is just intended as a friendly reminder and the PR as a possible starting point for getting your code running on Node.js 10.

More information on this issue

Greenkeeper has checked the engines key in any package.json file, the .nvmrc file, and the .travis.yml file, if present.

  • engines was only updated if it defined a single version, not a range.
  • .nvmrc was updated to Node.js 10
  • .travis.yml was only changed if there was a root-level node_js that didn’t already include Node.js 10, such as node or lts/*. In this case, the new version was appended to the list. We didn’t touch job or matrix configurations because these tend to be quite specific and complex, and it’s difficult to infer what the intentions were.

For many simpler .travis.yml configurations, this PR should suffice as-is, but depending on what you’re doing it may require additional work or may not be applicable at all. We’re also aware that you may have good reasons to not update to Node.js 10, which is why this was sent as an issue and not a pull request. Feel free to delete it without comment, I’m a humble robot and won’t feel rejected 🤖


FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Add --help

Would be nice if the de facto standard --help would be implemented, users (at least me!) expect it to work. 🙂

Not working at all

It just outputs all the exports. I thought this is the tool for detecting unused ones.

fails

I'm getting a failure

/usr/local/lib/node_modules/shrimpit/index.js:16
class Shrimpit {
^^^^^

SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode

is this because I'm currently running node v5.6.0

Re-exports support

Hi!
Great lib! However it doesn't handle re-exports properly. For example:

// a.js
export const a1 = {};
export const a2 = {};
// b.js
export * from "./a";
// c.js
import { a1 } from "./b";

These files would produce:

 Shrimpit!  

 > Unused exports  

[ { location: 'test/a.js', name: 'a1', unnamedDefault: false },
  { location: 'test/a.js', name: 'a2', unnamedDefault: false } ]

However, only a2 is unused.

Would you please support re-exports?

Support node v4.6.x

Doesn't work in node v4.6.0 because of

class Shrimpit {
^^^^^

SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode

Glob input?

Hey, love this. I thought, "I wonder if there's a tool to check for unused exports", and there it was!

I was wondering if you'd accept a PR to change the path input to accept glob patterns instead of direct paths? I've tried to use my shell's glob expansion but it's not expressive enough for what I need.

Thanks!

Static class property leades to shrimpit exception

The following file leades to a TypeError exception:

// a.js
export default class A {
  static a = {};
}

shrimpit output:

 Shrimpit!

! TypeError: Cannot read property 'name' of undefined

The problem seems to be in line 350. Only setting name when path.scope.parent.path.node.id is defined seems to work, but I'm not sure if it breaks the unused export detection.

Statements inside class property functions are picked up as unused exports

Consider the following example:

// b.js

export default class B {
  objectMethod = () => {
    if (true) {
    }
  };
}
// c.js
import B from "./b";

Shrimpit output:

 Shrimpit!

 > Unused exports

[ { location: 'b.js', name: '/', unnamedDefault: false } ]

The output is correct if objectMethod is written like this:

objectMethod() {
// ...
}

Amazingly enough, the output is also correct if the if condition is "condition" instead of "true".

Make linting optional

Hi, I like the tool, thank you for it.

I am trying to use it, but getting linting error messages. I have my own standards and tools for that, so would like to only use it to find out unused exports. Could you add an option to ignore linting or even better, make the linting optional?

Need more info on error log

Hi! First of all, thank you for your work 👍

I have tried to run shrimpit on a big project with lots of components and the only line I'm getting as a result:

! SyntaxError: Unterminated JSX contents (17:14)

Any suggestions how to track the file name or get more debug info? Thanks in advance.

Work with UMD?

Hi, is it possible to use this with UMD? (Universal Module Definition). As an example with my library Ola, when I try it on the minified code I get:

 Shrimpit!  

[]
 > Unused exports  

However, if I remove the headers and use the export default I get the correct:

[ { location: 'data/ola.js',
    name: 'default (unnamed)',
    unnamedDefault: true } ]

What UMD (with Rollup.js) does is to change the export default ... for this wrapper:

(function(global, factory) {
  typeof exports === "object" && typeof module !== "undefined"
    ? (module.exports = factory())
    : typeof define === "function" && define.amd
    ? define(factory)
    : ((global = global || self), (global.Ola = factory()));
})(this, function() {
  "use strict";

  // CODE HERE

  return Ola;
});

There could be two ways AFAIK to implement this with Shrimpit:

  1. Pattern (regexp) match this block of code and replace the last return for a export default.
  2. Detect the module.exports match here and use that to find out what is exported. Though, that is probably difficult/impossible without actually running the code.

I'm trying to use Shrimpit to detect the export from an arbitrary npm module, but it's becoming a lot more difficult than I thought.

namespace-imports TypeError

Hi,

I'm getting a TypeError when running shrimpit on ES6 Modules which use wilcard import statements.

import * as foods from './food-types'
...

System:

Step to recreate:

npm install shrimpit -g
shrimpit /users/ldstein/AppData/Roaming/npm/node_modules/shrimpit/test/namespace-imports/b.js

Output is:

(node:9872) UnhandledPromiseRejectionWarning: TypeError: Cannot destructure property `imports` of 'undefined' or 'null'.
    at namespaceImports.map (C:\Users\ldstein\AppData\Roaming\npm\node_modules\shrimpit\lib.js:318:41)
    at Array.map (<anonymous>)
    at Shrimpit.resolveNamespaceImports (C:\Users\ldstein\AppData\Roaming\npm\node_modules\shrimpit\lib.js:317:27)
    at Shrimpit.exec (C:\Users\ldstein\AppData\Roaming\npm\node_modules\shrimpit\lib.js:142:10)
    at process._tickCallback (internal/process/next_tick.js:68:7)
(node:9872) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:9872) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Anyone else able to confirm if they are seeing the same behaviour?

Wrong output if exports use the same name

Thanks again for creating this tool.

Currently all export and import names are flattened when analyzing unused exports. This leads to issues when multiple files have exports with the same name. Example:

// a.js
export function a() {

}
// b.js
export function a() {

}

export function b() {

}
// c.js
import { a } from './a';
import { b } from './b';

a();
b();

shrimpit! output:

 Shrimpit!

 > Files tree

{ '.': null,
  'a.js': { exports: [ 'a' ], imports: [] },
  'b.js': { exports: [ 'a', 'b' ], imports: [] },
  'c.js': { exports: [], imports: [ 'a', 'b' ] } }

 > Unused exports

All Clear Ahead, Captain.

This is wrong, because export a from file b.js is not used anywhere. However it gets declared as used, since c.js is using the named export a from a.js.

In general I think it might more sense to always use the full path identifier for imports and exports, since it makes it more readable when fixing unused exports. As an example, I'm currently cleaning up a codebase with a lot of react components and in conjunction with bug #36 my output is often something like this:

 Shrimpit!

 > Unused exports

[ 'constructor',
  'componentDidMount',
  'componentWillReceiveProps',
  'setState',
  'error',
  'constructor',
  'componentDidMount',
...

Apart from the real issue mentioned above, not using the full path identifier makes it hard to find the file that has the unused export.

Renamed imports lead to unused exports

Example:

// a.js
export const a = {};
// b.js
import { a as b } from "./a";

shrimpit output:

 Shrimpit!

 > Unused exports

[ { location: 'second/a.js', name: 'a', unnamedDefault: false } ]

However a is actually imported in file b.js.

create vscode plugin

I found this tool is very good so extending it to be vscode plugin will be very useful which will give you code fix to remove unused exports.

Error while trying to run it

When trying to run it with any command I get this error:

 Shrimpit!  

(node:9578) UnhandledPromiseRejectionWarning: TypeError: Expected `cwd` to be of type `string` but received type `undefined`
    at module.exports (/home/francisco/.nvm/versions/node/v11.3.0/lib/node_modules/shrimpit/node_modules/dir-glob/index.js:48:25)
    at globDirs (/home/francisco/.nvm/versions/node/v11.3.0/lib/node_modules/shrimpit/node_modules/globby/index.js:58:9)
    at getPattern (/home/francisco/.nvm/versions/node/v11.3.0/lib/node_modules/shrimpit/node_modules/globby/index.js:61:64)
    at Promise.all.globTasks.map.task (/home/francisco/.nvm/versions/node/v11.3.0/lib/node_modules/shrimpit/node_modules/globby/index.js:72:69)
    at Array.map (<anonymous>)
    at module.exports (/home/francisco/.nvm/versions/node/v11.3.0/lib/node_modules/shrimpit/node_modules/globby/index.js:72:41)
    at Shrimpit.exec (/home/francisco/.nvm/versions/node/v11.3.0/lib/node_modules/shrimpit/lib.js:126:25)
    at Object.<anonymous> (/home/francisco/.nvm/versions/node/v11.3.0/lib/node_modules/shrimpit/index.js:6:10)
    at Module._compile (internal/modules/cjs/loader.js:722:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:733:10)
(node:9578) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:9578) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

I just installed shrimpit with npm install shrimpit -g in Ubuntu 18.04. My Node.js version is v11.3.0.

Doesn't resolve index.js files correctly

Thanks for such an awesome tool!

Our project had a src/constants/index.js file with a bunch of named exports.

These named exports were imported in components within src/components with a specifier something like ../constants, and shrimpit was assuming this means ../constants.js and didn't bother looking for ./constants/index.js like Node.js and other tools do.

This resulted in all our constants reporting incorrectly as unused.

Named function expression is mistaken for an export

Neat tool, I found a small gotcha on an actual project. Named function expressions seem to be mistaken for exports and therefore result in "unused exports" false positives.

Example:

a.js

export default function outer () {
  const f = function inner () {
  }
}

Output:

$ shrimpit --tree a.js 
 Shrimpit!  

 > Files tree  

{ 'a.js': 
   { imports: [],
     exports: 
      [ { location: 'a.js', name: 'outer', unnamedDefault: true },
        { location: 'a.js', name: 'inner', unnamedDefault: false },
        { location: 'a.js',
          name: 'default (unnamed)',
          unnamedDefault: true } ] } } 

 > Unused exports  

[ { location: 'a.js', name: 'outer', unnamedDefault: true },
  { location: 'a.js', name: 'inner', unnamedDefault: false },
  { location: 'a.js',
    name: 'default (unnamed)',
    unnamedDefault: true } ] 

Default exported class is not picked up correctly

First of all thanks for the great tool! It is really providing a lot of value when cleaning up old code.

I found a bug when exporting classes in the default export:

// a.js
export default class User extends Person {
  walk() {
    console.log("I'm walking");
  }
}
// b.js
import User from './a';

new User().walk();

shrimpit! Output:

 Shrimpit!

 > Files tree

{ '.': null,
  'a.js': { exports: [ 'walk', '/' ], imports: [] },
  'b.js': { exports: [], imports: [ '/' ] } }

 > Unused exports

[ 'walk' ]

Expectation: It should not traverse the members of the class declaration, it should simply check whether the "Default" export of a.js is used anywhere.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.