├── .gitignore ├── LICENSE ├── README.md ├── bin └── 5to6.js ├── package.json └── src ├── index.js └── modules ├── convert-fn-expr-in-obj-to-shorthand.js ├── convert-module-dot-export-to-export-default.js ├── convert-require-stmt-to-import-stmt.js ├── convert-same-key-value-in-obj-expr-to-just-key.js └── strip-use-stricts.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2010-2015 Google, Inc. http://angularjs.org 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Note: Experimental 2 | 3 | 5to6 4 | ======================== 5 | 6 | [Motivation](https://medium.com/@thomas_loh/es5-es6-e55e9bf59819) 7 | 8 | Converts (partial) ES5 code to ES6. Converted files are expected to be used with ES6 transpilers like Babel. 9 | 10 | Uses [recast](https://github.com/benjamn/recast) to get code's AST and detect then modify certain syntax to the equivalent in ES6. Semantics don't change, only the syntax. 11 | 12 | # Supported conversions 13 | 14 | ```javascript 15 | var b = { 16 | abc: abc 17 | } 18 | => 19 | var b = { 20 | abc 21 | } 22 | 23 | { 24 | abc: function() { 25 | console.log('a') 26 | } 27 | } 28 | => 29 | { 30 | abc() { 31 | console.log('a') 32 | } 33 | } 34 | 35 | module.exports = Component 36 | => 37 | export default Component 38 | 39 | var Foo = require('foo') 40 | => 41 | import Foo from 'foo' 42 | 43 | var Bar = require('foo').Bar 44 | => 45 | import {Bar} from 'foo' 46 | 47 | require('foo') 48 | => 49 | import 'foo' 50 | 51 | var Foo = require('foo') 52 | var Bar = Foo.Bar 53 | var Baz = Foo.Baz 54 | => 55 | import Foo, {Bar, Baz} from 'foo' 56 | ``` 57 | 58 | # Install 59 | 60 | ```bash 61 | sudo npm install 5to6 -g 62 | ``` 63 | 64 | # Usage 65 | 66 | ```bash 67 | 5to6 -s src # converts all js or jsx files in "src" folder (relative to current directory) 68 | 69 | 5to6 -s . # converts all js or jsx files in current directory 70 | 71 | 5to6 -s . -v # verbose mode 72 | ``` 73 | 74 | # Caveats 75 | 76 | This lib was initially created to convert a particular project's codebase to ES6, so it assumes certain code structure. If your codebase is using the commonjs style modules structure, it should work. Codebase with everything in one big closure will not work. Again, this lib is experimental. 77 | 78 | 5to6 directly writes to file after conversion. So it depends on git, not for conversion, but for reversion in case output is not as expected etc. 79 | 80 | To revert conversion, simply run 81 | 82 | ```bash 83 | git reset --hard 84 | ``` 85 | 86 | # Credits 87 | 88 | Huge credit goes to [recast](https://github.com/benjamn/recast) by [benjamn](https://github.com/benjamn) 89 | -------------------------------------------------------------------------------- /bin/5to6.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var commander = require("commander"); 4 | var main = require('../src/index'); 5 | var colors = require('colors'); 6 | 7 | var program = new commander.Command('5to6'); 8 | 9 | program.option("-s, --source ", "Source to convert from ES5 to ES6 i.e. 5to6 -s src/js"); 10 | program.option("-v, --verbose", "Verbose mode"); 11 | 12 | var pkg = require("../package.json"); 13 | program.version(pkg.version); 14 | program.parse(process.argv); 15 | 16 | // Verify source 17 | var source = program.source; 18 | var verbose = program.verbose; 19 | 20 | if (!source) { 21 | return program.help(); 22 | } 23 | 24 | // Check git binary 25 | var exec = require('child_process').exec; 26 | exec('which git', verifyGit); 27 | 28 | function verifyGit(error, stdout, stderr) { 29 | 30 | // Git not installed 31 | if (!stdout) { 32 | return console.warn("git must to be installed. In case want to revert changes, can use `git reset --hard`".red); 33 | } 34 | 35 | // Make sure HEAD is clean 36 | exec('git diff', verifyWorkingCopyClean); 37 | 38 | function verifyWorkingCopyClean(error, stdout, stderr) { 39 | 40 | if (stdout) { 41 | return console.warn("git working copy must be clean, otherwise doing `git revert` later (if any) will revert previously changed files as well, so please commit your changed files first...".red); 42 | } 43 | 44 | main(source, {verbose: verbose}); 45 | 46 | } 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "5to6", 3 | "version": "0.0.3", 4 | "description": "Convert (partial) ES5 to ES6", 5 | "main": "src/index.js", 6 | "bin": { 7 | "5to6": "./bin/5to6.js" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git@github.com:thomasloh/5to6.git" 15 | }, 16 | "keywords": [ 17 | "5to6", 18 | "es5", 19 | "es6", 20 | "convert", 21 | "babel", 22 | "javascript", 23 | "recast" 24 | ], 25 | "author": "thomasloh", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/thomasloh/5to6/issues" 29 | }, 30 | "homepage": "https://github.com/thomasloh/5to6", 31 | "dependencies": { 32 | "bluebird": "^2.9.13", 33 | "colors": "^1.0.3", 34 | "commander": "^2.6.0", 35 | "glob": "^4.4.1", 36 | "lodash": "^3.3.1", 37 | "recast": "^0.10.1", 38 | "set": "^1.1.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | var recast = require('recast'); 2 | var _ = require('lodash'); 3 | var n = recast.types.namedTypes; 4 | var b = recast.types.builders; 5 | var fs = require('fs'); 6 | var colors = require('colors'); 7 | var Promise = require('bluebird'); 8 | 9 | var middlewares = [ 10 | require('./modules/convert-require-stmt-to-import-stmt'), 11 | require('./modules/strip-use-stricts'), 12 | require('./modules/convert-module-dot-export-to-export-default.js'), 13 | require('./modules/convert-fn-expr-in-obj-to-shorthand'), 14 | require('./modules/convert-same-key-value-in-obj-expr-to-just-key') 15 | ]; 16 | 17 | ///////////// 18 | // Convert // 19 | ///////////// 20 | function convert(pattern, opts) { 21 | 22 | var verbose = opts.verbose; 23 | 24 | var glob = require('glob'); 25 | var path = require('path'); 26 | var exec = Promise.promisify(require('child_process').exec); 27 | var p = path.join(process.cwd(), pattern, "/**/*.+(jsx|js)"); 28 | 29 | if (verbose) { 30 | console.log("File pattern to search: " + p); 31 | } 32 | 33 | var files = glob.sync(p); 34 | 35 | if (!files) { 36 | if (verbose) { 37 | console.log("Error globbing files.".red); 38 | } 39 | return; 40 | } 41 | 42 | if (!files.length) { 43 | if (verbose) { 44 | console.log("No files to convert.".yellow); 45 | } 46 | } 47 | 48 | Promise.all(files.map(function(file) { 49 | 50 | return exec('git ls-files ' + file + ' --error-unmatch').then(function() { 51 | 52 | // Read file and parse to ast 53 | var code = fs.readFileSync(file, "utf-8"); 54 | var ast = recast.parse(code); 55 | 56 | if (!code) { 57 | if (verbose) { 58 | console.log(file + " is empty or does not exist.".yellow); 59 | } 60 | return; 61 | } 62 | 63 | // Run through middlewares 64 | ast.program.body = middlewares.reduce(function(body, m) { 65 | return m(body); 66 | }, ast.program.body); 67 | 68 | // Write 69 | fs.writeFileSync(file, _.trimLeft(recast.print(ast).code)); 70 | 71 | if (verbose) { 72 | console.log((file + " is converted.").green); 73 | } 74 | 75 | }) 76 | .catch(function(e) { 77 | if (verbose) { 78 | console.log((file + " is not converted because it's not tracked by git.").red); 79 | } 80 | }); 81 | 82 | })); 83 | 84 | } 85 | 86 | 87 | module.exports = convert; 88 | -------------------------------------------------------------------------------- /src/modules/convert-fn-expr-in-obj-to-shorthand.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var recast = require('recast'); 3 | var _ = require('lodash'); 4 | var n = recast.types.namedTypes; 5 | var b = recast.types.builders; 6 | 7 | // { 8 | // abc: function() { 9 | // console.log('a') 10 | // } 11 | // } 12 | // => 13 | // { 14 | // abc() { 15 | // console.log('a') 16 | // } 17 | // } 18 | 19 | module.exports = function convertFnExprOfObjExprPropTo(body) { 20 | 21 | var bod = body; 22 | 23 | if (body.type === "BlockStatement") { 24 | bod = body.body; 25 | } 26 | 27 | bod = bod.map(function(o) { 28 | 29 | if (!o) { 30 | return o; 31 | } 32 | 33 | if (o.body) { 34 | o.body = convertFnExprOfObjExprPropTo(o.body); 35 | return o; 36 | } 37 | 38 | if (o.init && o.init.type === "ObjectExpression") { 39 | o.init.properties = convertFnExprOfObjExprPropTo(o.init.properties); 40 | return o; 41 | } 42 | 43 | if (o.init && o.init.type === "CallExpression") { 44 | o.init.arguments = convertFnExprOfObjExprPropTo(o.init.arguments); 45 | return o; 46 | } 47 | 48 | if (o.declarations) { 49 | o.declarations = convertFnExprOfObjExprPropTo(o.declarations); 50 | return o; 51 | } 52 | 53 | if (o.properties) { 54 | o.properties = convertFnExprOfObjExprPropTo(o.properties); 55 | return o; 56 | } 57 | 58 | if (o.value && o.value.type === "ObjectExpression") { 59 | o.value.properties = convertFnExprOfObjExprPropTo(o.value.properties); 60 | return o; 61 | } 62 | 63 | try { 64 | n.Property.assert(o); 65 | n.Identifier.assert(o.key); 66 | n.FunctionExpression.assert(o.value); 67 | } catch(e) { 68 | return o; 69 | } 70 | 71 | o.method = true; 72 | 73 | return o; 74 | 75 | }); 76 | 77 | if (body.type === "BlockStatement") { 78 | body.body = bod; 79 | } 80 | 81 | return body; 82 | 83 | }; 84 | -------------------------------------------------------------------------------- /src/modules/convert-module-dot-export-to-export-default.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var recast = require('recast'); 3 | var _ = require('lodash'); 4 | var n = recast.types.namedTypes; 5 | var b = recast.types.builders; 6 | 7 | // module.exports = Component 8 | // => 9 | // export default Component 10 | 11 | module.exports = function convertModuleDotExportToExportDefault(body) { 12 | 13 | return body.map(function(o) { 14 | 15 | if (!o) { 16 | return o; 17 | } 18 | 19 | try { 20 | n.ExpressionStatement.assert(o); 21 | n.AssignmentExpression.assert(o.expression); 22 | assert(o.expression.operator === "=", "Must be equal op"); 23 | n.MemberExpression.assert(o.expression.left); 24 | n.Identifier.assert(o.expression.left.object); 25 | assert(o.expression.left.object.name === "module", "Must be 'module' name"); 26 | n.Identifier.assert(o.expression.left.property); 27 | assert(o.expression.left.property.name === "exports", "Must be 'exports' name"); 28 | // n.Identifier.assert(o.expression.right); 29 | } catch(e) { 30 | return o; 31 | } 32 | 33 | // var Module = o.expression.right.name; 34 | o = b.exportDeclaration(true, o.expression.right); 35 | 36 | return o; 37 | 38 | }); 39 | 40 | }; 41 | -------------------------------------------------------------------------------- /src/modules/convert-require-stmt-to-import-stmt.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var recast = require('recast'); 3 | var _ = require('lodash'); 4 | var n = recast.types.namedTypes; 5 | var b = recast.types.builders; 6 | var Set = require('set'); 7 | 8 | ///////////////////////////////////////////////////// 9 | // Convert require statements to import statements // 10 | ///////////////////////////////////////////////////// 11 | 12 | module.exports = function convertRequireStmtsToImportStmts(body) { 13 | 14 | //////////// 15 | // States // 16 | //////////// 17 | var namespaceToMembers = {}; 18 | var moduleNameToPath = {}; 19 | var pathToModuleName = {}; 20 | var importedMembers = new Set(); 21 | var importedNamespaces = new Set(); 22 | 23 | ///////////////////////// 24 | // Assertion utilities // 25 | ///////////////////////// 26 | 27 | // Assert "require('foo')" on CallExpr 28 | function assertIsValidRequireCallExpr(o) { 29 | if (o.callee.name !== "require") { 30 | throw Error("Must be require()"); 31 | } 32 | if (!o.arguments[0]) { 33 | throw Error("Must have at least one argument"); 34 | } 35 | if (typeof o.arguments[0].value !== "string") { 36 | throw Error("Must have string path"); 37 | } 38 | } 39 | 40 | // Is "require('foo')" 41 | function isRequireExprStmt(o) { 42 | 43 | try { 44 | n.ExpressionStatement.assert(o); 45 | n.CallExpression.assert(o.expression); 46 | assertIsValidRequireCallExpr(o.expression); 47 | } catch (e) { 48 | return false; 49 | } 50 | 51 | return true; 52 | 53 | } 54 | 55 | // Is "var foo = require('foo')" 56 | function isVariableDeclarationWithRequireCallExpr(o) { 57 | 58 | try { 59 | n.VariableDeclarator.assert(o); 60 | n.Identifier.assert(o.id); 61 | n.CallExpression.assert(o.init); 62 | assertIsValidRequireCallExpr(o.init); 63 | } catch (e) { 64 | return false; 65 | } 66 | 67 | return true; 68 | 69 | } 70 | 71 | function hasDeclarations(o) { 72 | return o.type == "VariableDeclaration" && 73 | _.isArray(o.declarations) && 74 | o.declarations.length > 0; 75 | } 76 | 77 | // Is "var bar = foo.bar" 78 | function isVariableDeclaratorWithMemberExpr(o) { 79 | 80 | try { 81 | n.VariableDeclarator.assert(o); 82 | n.Identifier.assert(o.id); 83 | n.MemberExpression.assert(o.init); 84 | n.Identifier.assert(o.init.object); 85 | } catch (e) { 86 | return false; 87 | } 88 | 89 | return true; 90 | 91 | } 92 | 93 | // Is "var Bar = require('foo').Bar" 94 | function isRequireVariableDeclarationWithMemberExpr(o) { 95 | try { 96 | n.VariableDeclarator.assert(o); 97 | n.Identifier.assert(o.id); 98 | n.MemberExpression.assert(o.init); 99 | n.Identifier.assert(o.init.property); 100 | n.CallExpression.assert(o.init.object); 101 | n.Identifier.assert(o.init.object.callee); 102 | assertIsValidRequireCallExpr(o.init.object); 103 | assert(o.init.object.arguments.length === 1, "Must have module name"); 104 | assert(o.id.name === o.init.property.name, "Must be equal member extraction"); 105 | } catch (e) { 106 | return false; 107 | } 108 | return true; 109 | } 110 | 111 | function isIdentiferEligibleForNamedImportImported(x) { 112 | return importedNamespaces.contains(x.init.object.name); 113 | } 114 | 115 | // First pass scan to collect info 116 | function firstPass(o) { 117 | 118 | if (_.isArray(o)) { 119 | return _.each(o, firstPass); 120 | } 121 | 122 | if (_.isObject(o)) { 123 | 124 | if (hasDeclarations(o)) { 125 | 126 | _.each(o.declarations, function(declarator) { 127 | 128 | if (isVariableDeclarationWithRequireCallExpr(declarator)) { 129 | var moduleName = declarator.id.name; 130 | var path = declarator.init.arguments[0].value; 131 | moduleNameToPath[moduleName] = path; 132 | pathToModuleName[path] = moduleName; 133 | return; 134 | } 135 | 136 | if (isVariableDeclaratorWithMemberExpr(declarator)) { 137 | var namespace = declarator.init.object.name; 138 | var property = declarator.init.property.name; 139 | namespaceToMembers[namespace] = namespaceToMembers[namespace] || []; 140 | namespaceToMembers[namespace].push(property); 141 | } 142 | 143 | }); 144 | } 145 | 146 | } 147 | } 148 | 149 | // Second pass scan to collect info 150 | function secondPass(o) { 151 | 152 | if (_.isArray(o)) { 153 | return _.each(o, secondPass); 154 | } 155 | 156 | if (_.isObject(o)) { 157 | 158 | if (hasDeclarations(o)) { 159 | 160 | _.each(o.declarations, function(declarator) { 161 | 162 | if (isRequireVariableDeclarationWithMemberExpr(declarator)) { 163 | var modulePath = declarator.init.object.arguments[0].value; 164 | var namespace = pathToModuleName[modulePath]; 165 | var property = declarator.id.name; 166 | 167 | if (namespaceToMembers[namespace] && 168 | namespaceToMembers[namespace].length) { 169 | namespaceToMembers[namespace] = namespaceToMembers[namespace] || []; 170 | namespaceToMembers[namespace].push(property); 171 | importedMembers.add(property); 172 | } 173 | return; 174 | } 175 | 176 | }); 177 | } 178 | 179 | } 180 | } 181 | 182 | 183 | ////////////////////////// 184 | // Conversion utilities // 185 | ////////////////////////// 186 | 187 | // var Foo = require('foo') 188 | // => 189 | // import Foo from 'foo' 190 | function convertRequireVariableDeclarationToImportDefault(o) { 191 | 192 | if (!o) { 193 | return o; 194 | } 195 | 196 | // Validations 197 | try { 198 | n.VariableDeclaration.assert(o); 199 | } catch (e) { 200 | return o; 201 | } 202 | 203 | function isRequireDeclarator(declarator) { 204 | try { 205 | n.VariableDeclarator.assert(declarator); 206 | n.Identifier.assert(declarator.id); 207 | n.CallExpression.assert(declarator.init); 208 | assertIsValidRequireCallExpr(declarator.init); 209 | } catch (e) { 210 | return false; 211 | } 212 | 213 | return true; 214 | } 215 | 216 | var someAreRequires = _.some(o.declarations, isRequireDeclarator); 217 | 218 | if (someAreRequires) { 219 | 220 | var requires = _.filter(o.declarations, isRequireDeclarator); 221 | var nonRequires = _.reject(o.declarations, isRequireDeclarator); 222 | 223 | nonRequires = nonRequires.map(function(declarator) { 224 | 225 | var name = declarator.id.name; 226 | 227 | if (name in namespaceToMembers) { 228 | return null; 229 | } 230 | 231 | return declarator; 232 | }); 233 | 234 | if (!_.all(nonRequires, function(r){return _.isNull(r)})) { 235 | nonRequires = b.variableDeclaration("var", nonRequires); 236 | } else { 237 | nonRequires = null; 238 | } 239 | 240 | requires = requires.map(function(declarator) { 241 | 242 | // Validations 243 | try { 244 | n.VariableDeclarator.assert(declarator); 245 | n.Identifier.assert(declarator.id); 246 | n.CallExpression.assert(declarator.init); 247 | assertIsValidRequireCallExpr(declarator.init); 248 | } catch (e) { 249 | return declarator; 250 | } 251 | 252 | var name = declarator.id.name; 253 | var path = declarator.init.arguments[0].value; 254 | 255 | if (name in namespaceToMembers) { 256 | return null; 257 | } 258 | 259 | declarator = b.importDeclaration([ 260 | b.importDefaultSpecifier(b.identifier(name)) 261 | ], b.moduleSpecifier(path)); 262 | 263 | return declarator; 264 | 265 | }); 266 | 267 | return _.flatten([requires, nonRequires]); 268 | 269 | } else { 270 | return o; 271 | } 272 | 273 | return o; 274 | 275 | } 276 | 277 | // var Bar = require('foo').Bar 278 | // => 279 | // import {Bar} from 'foo' 280 | function convertRequireVariableDeclarationWithMemberExprToImportNamed(o) { 281 | 282 | if (!o) { 283 | return o; 284 | } 285 | 286 | // Validations 287 | 288 | if (hasDeclarations(o)) { 289 | 290 | var someAreRequires = _.some(o.declarations, isRequireVariableDeclarationWithMemberExpr); 291 | 292 | if (someAreRequires) { 293 | 294 | var requires = _.filter(o.declarations, isRequireVariableDeclarationWithMemberExpr); 295 | var nonRequires = _.reject(o.declarations, isRequireVariableDeclarationWithMemberExpr); 296 | 297 | nonRequires = nonRequires.map(function(declarator) { 298 | 299 | var name = declarator.id.name; 300 | 301 | if (name in namespaceToMembers) { 302 | return null; 303 | } 304 | 305 | return declarator; 306 | }); 307 | 308 | if (!_.all(nonRequires, function(r){return _.isNull(r)})) { 309 | nonRequires = b.variableDeclaration("var", nonRequires); 310 | } else { 311 | nonRequires = null; 312 | } 313 | 314 | requires = requires.map(function(declarator) { 315 | 316 | if (!isRequireVariableDeclarationWithMemberExpr(declarator)) { 317 | return declarator; 318 | } 319 | 320 | var name = declarator.id.name; 321 | 322 | if (importedMembers.contains(name)) { 323 | return null; 324 | } 325 | 326 | var path = declarator.init.object.arguments[0].value; 327 | 328 | declarator = b.importDeclaration([ 329 | b.importSpecifier(b.identifier(name)) 330 | ], b.moduleSpecifier(path)); 331 | 332 | return declarator; 333 | 334 | }); 335 | 336 | return _.flatten([requires, nonRequires]); 337 | 338 | } else { 339 | return o; 340 | } 341 | 342 | if (!_.compact(o.declarations).length) { 343 | return null; 344 | } 345 | 346 | } 347 | 348 | return o; 349 | 350 | } 351 | 352 | // require('foo') 353 | // => 354 | // import 'foo' 355 | function convertRequireExprStatementToPlainImport(o) { 356 | 357 | if (!o) { 358 | return o; 359 | } 360 | 361 | try { 362 | n.ExpressionStatement.assert(o); 363 | n.CallExpression.assert(o.expression); 364 | assertIsValidRequireCallExpr(o.expression); 365 | } catch (e) { 366 | return o; 367 | } 368 | 369 | var path = o.expression.arguments[0].value; 370 | 371 | o = b.importDeclaration([], b.moduleSpecifier(path)); 372 | 373 | return o; 374 | 375 | } 376 | 377 | // var Foo = require('foo') 378 | // var Bar = Foo.Bar 379 | // var Baz = Foo.Baz 380 | // => 381 | // import Foo from 'foo' 382 | // import {Bar, Baz} from 'foo' 383 | function convertIdentifierToNamedImport(o) { 384 | 385 | if (!o) { 386 | return o; 387 | } 388 | 389 | if (_.isArray(o.declarations) && o.declarations.length) { 390 | 391 | o.declarations = o.declarations.map(function(declarator) { 392 | 393 | if (!isVariableDeclaratorWithMemberExpr(declarator)) { 394 | return declarator; 395 | } 396 | 397 | var namespace = declarator.init.object.name; 398 | 399 | if (!namespace) { 400 | return declarator; 401 | } 402 | 403 | if (!(namespace in namespaceToMembers)) { 404 | return declarator; 405 | } 406 | var property = declarator.init.property.name; 407 | if (!~namespaceToMembers[namespace].indexOf(property)) { 408 | return declarator; 409 | } 410 | 411 | // 412 | if (isIdentiferEligibleForNamedImportImported(declarator)) { 413 | return null; 414 | } 415 | 416 | var namespace = declarator.init.object.name; 417 | var property = declarator.init.property.name; 418 | 419 | o = b.importDeclaration(_.union([ 420 | b.importDefaultSpecifier(b.identifier(namespace))] 421 | , namespaceToMembers[namespace].map(function(m) { 422 | return b.importSpecifier(b.identifier(m)); 423 | })), b.moduleSpecifier(moduleNameToPath[namespace])); 424 | 425 | importedNamespaces.add(namespace); 426 | 427 | }); 428 | 429 | } 430 | 431 | if (hasDeclarations(o)) { 432 | if (!_.compact(o.declarations).length) { 433 | return null; 434 | } 435 | } 436 | 437 | return o; 438 | 439 | } 440 | 441 | // First pass 442 | firstPass(body); 443 | 444 | // Second pass 445 | secondPass(body); 446 | 447 | // Second pass: Convert 448 | body = body.map(function(o) { 449 | o = convertIdentifierToNamedImport(o); 450 | o = convertRequireVariableDeclarationWithMemberExprToImportNamed(o); 451 | o = convertRequireVariableDeclarationToImportDefault(o); 452 | o = convertRequireExprStatementToPlainImport(o); 453 | return o; 454 | }); 455 | 456 | return _.chain(body) 457 | .flatten() 458 | .reject(function(o) { 459 | return _.isArray(o) && !o.length}) 460 | .value(); 461 | 462 | }; 463 | -------------------------------------------------------------------------------- /src/modules/convert-same-key-value-in-obj-expr-to-just-key.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var recast = require('recast'); 3 | var _ = require('lodash'); 4 | var n = recast.types.namedTypes; 5 | var b = recast.types.builders; 6 | 7 | // var b = { 8 | // abc: abc 9 | // } 10 | // => 11 | // var b = { 12 | // abc 13 | // } 14 | 15 | module.exports = function convertSameKeyValueInObjExprToJustKey(body) { 16 | 17 | return body.map(function(o) { 18 | 19 | if (!o) { 20 | return o; 21 | } 22 | 23 | if (_.isArray(o.body)) { 24 | o.body = convertSameKeyValueInObjExprToJustKey(o.body); 25 | return o; 26 | } 27 | 28 | if (o.init && o.init.type === "ObjectExpression") { 29 | o.init.properties = convertSameKeyValueInObjExprToJustKey(o.init.properties); 30 | return o; 31 | } 32 | 33 | if (o.init && o.init.type === "CallExpression") { 34 | o.init.arguments = convertSameKeyValueInObjExprToJustKey(o.init.arguments); 35 | return o; 36 | } 37 | 38 | if (o.declarations) { 39 | o.declarations = convertSameKeyValueInObjExprToJustKey(o.declarations); 40 | return o; 41 | } 42 | 43 | if (o.properties) { 44 | o.properties = convertSameKeyValueInObjExprToJustKey(o.properties); 45 | return o; 46 | } 47 | 48 | if (o.value && o.value.type === "ObjectExpression") { 49 | o.value.properties = convertSameKeyValueInObjExprToJustKey(o.value.properties); 50 | return o; 51 | } 52 | 53 | try { 54 | n.Property.assert(o); 55 | n.Identifier.assert(o.key); 56 | n.Identifier.assert(o.value); 57 | assert(o.key.name === o.value.name, "Key and value must equal"); 58 | } catch(e) { 59 | return o; 60 | } 61 | 62 | o.shorthand = true; 63 | 64 | return o; 65 | 66 | }); 67 | 68 | }; 69 | -------------------------------------------------------------------------------- /src/modules/strip-use-stricts.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var recast = require('recast'); 3 | var _ = require('lodash'); 4 | var n = recast.types.namedTypes; 5 | var b = recast.types.builders; 6 | 7 | ////////////////////////// 8 | // Strip "use strict;"s // 9 | ////////////////////////// 10 | 11 | module.exports = function stripUseStricts(body) { 12 | 13 | return body.map(function(o) { 14 | 15 | if (!o) { 16 | return o; 17 | } 18 | 19 | // Validations 20 | try { 21 | n.ExpressionStatement.assert(o); 22 | n.Literal.assert(o.expression); 23 | assert(o.expression.value === "use strict", "Expecting \"use strict\"; expr stmt"); 24 | } catch (e) { 25 | return o; 26 | } 27 | 28 | // Strip 29 | return null; 30 | 31 | }); 32 | 33 | }; 34 | --------------------------------------------------------------------------------