Git Product home page Git Product logo

5to6-codemod's Introduction

Build Status GitHub version NPM version Downloads

5to6-codemod

A collection of codemods that allow you to transform your JavaScript code from ES5 to ES6 using jscodeshift.

Usage

  1. npm install -g jscodeshift
  2. npm install 5to6-codemod
  3. jscodeshift -t node_modules/5to6-codemod/transforms/[transform].js [files]
  4. Review changes via git diff. Keep what you want, throw it out if you don't. Magic!

Option flags

When executing codemods, you can configure options like so:

jscodeshift -t node_modules/5to6-codemod/transforms/[transform].js [files] --key=value

Recast options

Our transforms will automatically distinguish and pass through Recast config keys via jscodeshift. Official documentation for Recast's configuration can be found here. We currently support the following Recast keys:

  • esprima
  • inputSourceMap
  • lineTerminator
  • quote
  • range
  • reuseWhitespace
  • sourceFileName
  • sourceMapName
  • sourceRoot
  • tabWidth
  • tolerant
  • trailingComma
  • useTabs
  • wrapColumn

Transforms

  • amd - Transforms AMD style modules to ES6 import/export
  • cjs - Transforms CommonJS style require() calls to ES6 import statements
    • This transformation accepts the following option flags:
      • hoist: Enables hoisting require statements to the top
  • no-strict - Removes "use strict" statements
  • exports - Move CommonJS style module.exports statements to ES6 export statements
  • named-export-generation - Adds named exports corresponding to default export object keys. Only valid for ES6 modules exporting an object as the default export.
  • let - Replace all var calls to use let
  • simple-arrow - Replace all function expressions with a body of a sole return statement into arrow functions

Known issues

  • Can't automagically figure out when you want to use import * as varName.
  • End-of-line comments also missing in many situations
  • simple-arrow loses comments in the function expression body

5to6-codemod's People

Contributors

akloboucnik avatar amilajack avatar ewnd9 avatar frodosamoa avatar gmathieu avatar jamischarles avatar jsnmoon avatar nmn avatar nolanlawson avatar rmacklin avatar xjamundx avatar xzyfer 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  avatar

5to6-codemod's Issues

Handling cjs inline requires

Converting our legacy code, I found these weird cases which cause a few exceptions. I would consider all except var Foo = require('Foo') to be inline requires which es modules isn't meant to support.

Given that modules should only be imported at the the top level, should we assume any requires past the top level are inline? Or is that too simplistic an approach?

describe('foo', function () {
    var Foo = require('Foo')
    beforeEach(function () {
        this.foo = require('foo')
        var test = new fn(require('foo'))
    })
})
var LOOKUP = {
  	foo: require('foo'),
	get bar () { return require('bar') },
}

I'm happy to open a PR, just wanted to get some direction first.

Thanks for this tool, it's really helpful.

Add tests

ideally, this project would have some mocha test to ensure coverage. That's pretty necessary for a project like this, which can have unexpected side effects.

Error when running simple-arrow transformation

This is the stacktrace:

 ERR test.js Transformation error (Cannot read property 'map' of undefined)
TypeError: Cannot read property 'map' of undefined
    at Lines.Lp.join (/Users/dlj/.config/yarn/global/node_modules/recast/lib/lines.js:867:12)
    at printFunctionParams (/Users/dlj/.config/yarn/global/node_modules/recast/lib/printer.js:2669:35)
    at printMethod (/Users/dlj/.config/yarn/global/node_modules/recast/lib/printer.js:2595:13)
    at genericPrintNoParens (/Users/dlj/.config/yarn/global/node_modules/recast/lib/printer.js:389:16)
    at genericPrint (/Users/dlj/.config/yarn/global/node_modules/recast/lib/printer.js:173:9)
    at print (/Users/dlj/.config/yarn/global/node_modules/recast/lib/printer.js:99:15)
    at /Users/dlj/.config/yarn/global/node_modules/recast/lib/patcher.js:193:22
    at Array.forEach (<anonymous>)
    at /Users/dlj/.config/yarn/global/node_modules/recast/lib/patcher.js:176:14
    at print (/Users/dlj/.config/yarn/global/node_modules/recast/lib/printer.js:98:15)

And here's a simple file that demonstrates the issue:

import A from 'A';
  
class B extends A {
    load() {
        return super.load(['Stuff']);
    }
}

export default new B();

npm audit returning several vulnerabilities

The vulnerabilities reported are all in relation to an outdated version of babel and micromatch being used. The version of jscodeshift needs to be updated to ^0.6.0, and that should resolve the problem. While I understand that these aren't actual problems, as these are run-time vulnerabilities, this is causing massive headache for anyone who has npm audit as part of their CI pipeline.

┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Moderate      │ Prototype Pollution                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ lodash                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=4.17.11                                                    │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ 5to6-codemod                                                 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ 5to6-codemod > jscodeshift > babel-core >                    │
│               │ babel-plugin-proto-to-assign > lodash                        │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/782                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Moderate      │ Prototype Pollution                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ lodash                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=4.17.11                                                    │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ 5to6-codemod                                                 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ 5to6-codemod > jscodeshift > babel-core > lodash             │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/782                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Prototype Pollution                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ lodash                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=4.17.5                                                     │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ 5to6-codemod                                                 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ 5to6-codemod > jscodeshift > babel-core >                    │
│               │ babel-plugin-proto-to-assign > lodash                        │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/577                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Prototype Pollution                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ lodash                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=4.17.5                                                     │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ 5to6-codemod                                                 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ 5to6-codemod > jscodeshift > babel-core > lodash             │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/577                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High          │ Regular Expression Denial of Service                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ minimatch                                                    │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=3.0.2                                                      │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ 5to6-codemod                                                 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ 5to6-codemod > jscodeshift > babel-core > minimatch          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/118                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Regular Expression Denial of Service                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ braces                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=2.3.1                                                      │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ 5to6-codemod                                                 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ 5to6-codemod > jscodeshift > micromatch > braces             │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/786                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
found 6 vulnerabilities (3 low, 2 moderate, 1 high) in 5308 scanned packages
  6 vulnerabilities require manual review. See the full report for details.

Complete Exports Rule

  • Comments Missing
  • exports.thing() and module.exports.thing() and module.exports() not properly covered

Named exports generation enhancement

I would like to suggest a new transformation for adding named exports corresponding to the properties in a CommonJS default object export. The following example is common for a codebase transitioning from CommonJS to ES6 modules:

module.before.js:

module.exports = {
  value1: 1,
  value2: 2,
};

module.after.js:

export default {
  value1: 1,
  value2: 2,
};

code.before.js:

var module = require('module.before.js');
var value1 = module.value1, 
  value2 = module.value2;

code.ideal.js:

import { value1, value2 } from 'module.after.js';

Unfortunately, code.ideal.js will not work since modules are not destructurable objects. However, we can add a compatibility shim to make code.ideal.js valid by adding named exports to module.after.js:

module.fixed.js

const exported = {
  value1: 1,
  value2: 2,
};
export default exported;
export const {
  value1,
  value,
} = exported;

Basically, this transformation allows better compatibility between CommonJS and ES2015 module notations; some people are opting to use a Babel 6 plugin to facilitate this behavior.

The downside to this transform is that it can cause declaration collisions since it creates new const declaration for each exported object's properties. Also, this transform can be unintuitive without the above example; it'll require proper documentation in the README for people to grasp its usefulness.

I'll push out a PR for this in a day or two.

[CJS] Support Multiple Requires in an Object with the Same Key

This tool is awesome! We've run into one minor issue on our end and actually have a monkeypatch to fix it.

Given this example:

var fetch = require('fetch');

var Routes = {
    route1: {
        component: require('Foo')
    },
    route2: {
        component: require('Bar')
    },
    route3: {
        component: require('Baz')
    },
    route4: {
        component: require('Foo')
    },
};

module.exports = Routes;

jscodeshift -t $GLOBAL_NODE_MODULES/5to6-codemod/transforms/cjs.js codeModExample.js --extensions=js

will return:

import fetch from 'fetch';
import component from 'Foo';
import component from 'Bar';
import component from 'Baz';
import component from 'Foo';

var Routes = {
    route1: {
        component
    },
    route2: {
        component
    },
    route3: {
        component
    },
    route4: {
        component
    }
};

module.exports = Routes;

Ideally, we would prefer if this resulted in this output:

import fetch from 'fetch';
import Foo from 'Foo';
import Bar from 'Bar';
import Baz from 'Baz';

var Routes = {
    route1: {
        component: Foo
    },
    route2: {
        component: Bar
    },
    route3: {
        component: Baz
    },
    route4: {
        component: Foo
    }
};

module.exports = Routes;

the "fix"

diff --git a/transforms/cjs.js b/transforms/cjs.js
index ab9e41d..406ad3d 100644
--- a/transforms/cjs.js
+++ b/transforms/cjs.js
@@ -73,6 +73,7 @@ module.exports = function transformer(file, api, options) {
 		}).forEach(replaceDeclarator.bind(undefined, j));
 	});

+	var moduleNames = {};
 	// var x = { x: require('...'), y: require('...'), ... }
 	root.find(j.VariableDeclaration, { declarations: [{ init: { type: 'ObjectExpression' }}] })
 		.forEach(function (variableDeclaration) {
@@ -83,13 +84,21 @@ module.exports = function transformer(file, api, options) {
 				.find(j.Property, { value: { callee: { name: 'require' }}})
 				.forEach(function (property) {
 					// generate import statement
-					var variableName = property.get('key', 'name').value
+					// var variableName = property.get('key', 'name').value
 					var moduleName = property.get('value', 'arguments', 0, 'value').value
+					var variableName = moduleName.slice(moduleName.lastIndexOf('/')+1, moduleName.length);
 					var importStatement = util.createImportStatement(moduleName, variableName, undefined, property.node.comments)
-
 					// modify property
 					var newProp = api.jscodeshift.property(property.node.kind, property.node.key, property.node.key)
-					newProp.shorthand = true
+					newProp.value = variableName;
+
+					if (moduleNames[variableName]) {
+						j(property).replaceWith(newProp);
+						return
+					} else {
+						moduleNames[variableName] = true;
+					}

 					j(variableDeclaration).insertBefore(importStatement)
 					j(property).replaceWith(newProp)

I would love to get opinions on this, and can open a PR if it's useful to others.

I don't think my monkey-patch should go down as is, it needs cleanup (I'm looking at you, return in the if).

There will be an issue if there's duplication of Module names in subdirectories, such as app/components/Header and app/components/redesign/Header. This change already stores moduleName and attempts to de-dupe, so the concept could be expanded upon to recursively add the subdirectory name to the moduleName if a module already exists.

We could actually go deeper, and do (only in case of namespace conflicts):

import Header from 'app/components/Header';
import RedesignHeader from 'app/components/redesign/Header';

5to6-codemod/transforms/exports.js can't handle variable exports case

var exports = module.exports = {
    'testkey': 'testvalue'
};

// 导出错误类型码
Object.keys(constants).forEach(function (key) {
    if (key.indexOf('ERR_') === 0) {
        exports[key] = constants[key]; // this line will be converted wrong
    }
});

will be converted to

   export const key = ...

Travis

Sorry! This issue is a dupe.

Error when running exports transformation with shadowed variable

This the stacktrace:

 ERR test.js Transformation error (Identifier 'ids' has already been declared (3:12))
SyntaxError: Identifier 'ids' has already been declared (3:12)
    at Object.raise (/Users/dlj/.config/yarn/global/node_modules/@babel/parser/lib/index.js:6322:17)
    at ScopeHandler.checkRedeclarationInScope (/Users/dlj/.config/yarn/global/node_modules/@babel/parser/lib/index.js:3754:12)
    at ScopeHandler.declareName (/Users/dlj/.config/yarn/global/node_modules/@babel/parser/lib/index.js:3720:12)
    at Object.checkLVal (/Users/dlj/.config/yarn/global/node_modules/@babel/parser/lib/index.js:8006:22)
    at Object.checkLVal (/Users/dlj/.config/yarn/global/node_modules/@babel/parser/lib/index.js:373:15)
    at Object.parseVarId (/Users/dlj/.config/yarn/global/node_modules/@babel/parser/lib/index.js:10441:10)
    at Object.parseVar (/Users/dlj/.config/yarn/global/node_modules/@babel/parser/lib/index.js:10412:12)
    at Object.parseVarStatement (/Users/dlj/.config/yarn/global/node_modules/@babel/parser/lib/index.js:10234:10)
    at Object.parseStatementContent (/Users/dlj/.config/yarn/global/node_modules/@babel/parser/lib/index.js:9830:21)
    at Object.parseStatement (/Users/dlj/.config/yarn/global/node_modules/@babel/parser/lib/index.js:9763:17)

And here's a simple file that demonstrates the issue:

class Repeated {
    doSomething(ids) { 
        let ids = { ids: ids.toString() };
        return ids;
    }
}

named-export-generation does not handle string literals as keys

Thanks for your work on this set of codemods, it's saved me at least a day of work already.

I noticed a weird behavior when using the named-export-generation transform on some code that has exports like;

module.exports = {
  'one': 1,
  'two': 2,
};

It looks like the transform is only accounting for keys that are of type Identifier and should be updated to handle keys of type Literal as well.

Unexpected token export

jscodeshift -t node_modules/5to6-codemod/transforms/amd.js src

Result:

    export default _;
    ^^^^^^

SyntaxError: Unexpected token export
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:139:10)
    at Module._compile (module.js:616:28)
    at Module._extensions..js (module.js:663:10)
    at Object.require.extensions.(anonymous function) [as .js] (C:\Users\Matt\AppData\Local\Yarn\config\global\node_modules\babel-regist
er\lib\node.js:152:7)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
All done.
Results:
0 errors
0 unmodified
0 skipped
0 ok
Time elapsed: 1.729seconds

Node v8.11

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.