whitepace + jscodeshift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
/////////////////////////////////////////////////////////////////////////////// | |
// USAGE: jscodeshift ./lib/ -t ./scripts/codemod-react-proptypes.js | |
/////////////////////////////////////////////////////////////////////////////// | |
module.exports = function(file, api){ | |
var js = api.jscodeshift, | |
root = js(file.source), | |
shouldFixWhitespace, | |
collection; | |
/////////////////////////////////////////////////////////////////////////// | |
// FROM: require('react').PropTypes | |
// TO: require('prop-types') | |
/////////////////////////////////////////////////////////////////////////// | |
getReactRequiresWithPropTypesProperty(root, js) | |
.replaceWith(requireCallExpression(js, 'prop-types')); | |
/////////////////////////////////////////////////////////////////////////// | |
// FROM: React.PropTypes | |
// TO: PropTypes | |
/////////////////////////////////////////////////////////////////////////// | |
collection = getReactPropTypesRefs(root, js) | |
.replaceWith(js.identifier('PropTypes')); | |
if (collection.length){ | |
/////////////////////////////////////////////////////////////////////// | |
// FROM: React = require('react'), | |
// TO: React = require('react'), | |
// PropTypes = require('prop-types'), | |
/////////////////////////////////////////////////////////////////////// | |
getVarDeclarationsWhichIncludeReact(root, js) | |
.forEach(function(path){ | |
var atIndex = findIndexOfFirstDeclaration(path, 'React'); | |
if (atIndex < 0){ return; } | |
insertVarDeclarationWithRequire(path, js, { | |
start: atIndex + 1, | |
name: 'PropTypes', | |
module: 'prop-types' | |
}); | |
}); | |
shouldFixWhitespace = true; | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
// FROM: React.createClass | |
// TO: createClass | |
/////////////////////////////////////////////////////////////////////////// | |
collection = getReactCreateClassRefs(root, js) | |
.replaceWith(js.identifier('createReactClass')); | |
if (collection.length){ | |
/////////////////////////////////////////////////////////////////////// | |
// FROM: React = require('react'), | |
// TO: React = require('react'), | |
// createReactClass = require('create-react-class'), | |
/////////////////////////////////////////////////////////////////////// | |
getVarDeclarationsWhichIncludeReact(root, js) | |
.forEach(function(path){ | |
var atIndex = findIndexOfFirstDeclaration(path, 'PropTypes', 'React'); | |
if (atIndex < 0){ return; } | |
insertVarDeclarationWithRequire(path, js, { | |
start: atIndex + 1, | |
name: 'createReactClass', | |
module: 'create-react-class' | |
}); | |
}); | |
shouldFixWhitespace = shouldFixWhitespace || true; | |
} | |
if (shouldFixWhitespace){ | |
/////////////////////////////////////////////////////////////////////// | |
// FROM: Foo = require('foo'), Bar = require('bar'), Baz = require('baz'); | |
// TO: Foo = require('foo'), | |
// Bar = require('bar'), | |
// Baz = require('baz'); | |
/////////////////////////////////////////////////////////////////////// | |
// TODO (mirande): hack! figure out how to do this properly? | |
getVarDeclarationsWhichIncludeReact(root, js) | |
.forEach(function(path){ | |
path.replace(js(path) | |
.toSource({ quote: 'single' }) | |
.split(',') | |
.join(',\n ')); | |
}); | |
} | |
return root.toSource({ quote: 'single' }); | |
}; | |
// utilities ////////////////////////////////////////////////////////////////// | |
function findIndexOfFirstDeclaration(path){ | |
var index = -1, | |
i = 1; | |
while (i < arguments.length){ | |
index = findIndexOfDeclaration(path, arguments[i]); | |
if (index >= 0){ return index; } | |
i += 1; | |
} | |
return index; | |
} | |
function findIndexOfDeclaration(path, name){ | |
return path.value.declarations.findIndex(function(arg){ | |
return arg.id.name === name; | |
}); | |
} | |
function getVarDeclarationsWhichIncludeReact(root, js){ | |
return root.find(js.VariableDeclaration) | |
.filter(function(path){ | |
return path.value.declarations.find(function(dec){ | |
return dec.id.name === 'React'; | |
}); | |
}); | |
} | |
function getReactRequiresWithPropTypesProperty(root, js){ | |
return root.find(js.MemberExpression, { | |
object: { | |
type: 'CallExpression', | |
callee: { type: 'Identifier', name: 'require' }, | |
arguments: [ | |
{ type: 'Literal', value: 'react' } | |
] | |
}, | |
property: { | |
type: 'Identifier', | |
name: 'PropTypes' | |
} | |
}); | |
} | |
function getReactPropTypesRefs(root, js){ | |
return root.find(js.MemberExpression, { | |
object: { | |
type: 'Identifier', | |
name: 'React' | |
}, | |
property: { | |
type: 'Identifier', | |
name: 'PropTypes' | |
} | |
}); | |
} | |
function getReactCreateClassRefs(root, js){ | |
return root.find(js.MemberExpression, { | |
object: { | |
type: 'Identifier', | |
name: 'React' | |
}, | |
property: { | |
type: 'Identifier', | |
name: 'createClass' | |
} | |
}); | |
} | |
function insertVarDeclarationWithRequire(path, js, options){ | |
path.value.declarations.splice( | |
options.start, | |
options.end || 0, | |
js.variableDeclarator( | |
js.identifier(options.name), | |
requireCallExpression(js, options.module) | |
) | |
); | |
} | |
function requireCallExpression(js, name){ | |
return js.callExpression( | |
js.identifier('require'), | |
[js.literal(name)] | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var React = require('react'), | |
omit = require('lodash/omit'), | |
glyphBtn = React.createFactory(require('./glyph')); | |
module.exports = React.createClass({ | |
displayName: 'AppendElementButton', | |
propTypes: { | |
className: React.PropTypes.string, | |
onAppend: React.PropTypes.func.isRequired, | |
}, | |
getDefaultProps: function(){ | |
return { className: 'btn-append-element' }; | |
}, | |
onAppend: function(event){ | |
event.preventDefault(); | |
this.props.onAppend(); | |
}, | |
render: function(){ | |
var props = omit(this.props, ['onAppend']); | |
props.onClick = this.onAppend; | |
props.text = 'append element'; | |
return glyphBtn(props); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var React = require('react'), | |
PropTypes = require('prop-types'), | |
createReactClass = require('create-react-class'), | |
omit = require('lodash/omit'), | |
glyphBtn = React.createFactory(require('./glyph')); | |
module.exports = createReactClass({ | |
displayName: 'AppendElementButton', | |
propTypes: { | |
className: PropTypes.string, | |
onAppend: PropTypes.func.isRequired, | |
}, | |
getDefaultProps: function(){ | |
return { className: 'btn-append-element' }; | |
}, | |
onAppend: function(event){ | |
event.preventDefault(); | |
this.props.onAppend(); | |
}, | |
render: function(){ | |
var props = omit(this.props, ['onAppend']); | |
props.onClick = this.onAppend; | |
props.text = 'append element'; | |
return glyphBtn(props); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment