babel-plugin-transform-react-remove-prop-types
Advanced tools
Comparing version 0.4.9 to 0.4.10
@@ -49,5 +49,5 @@ "use strict"; | ||
} else { | ||
superClass = binding.path.get('superClass'); | ||
var bindingSuperClass = binding.path.get('superClass'); | ||
if (isPathReactClass(superClass)) { | ||
if (isPathReactClass(bindingSuperClass)) { | ||
answer = true; | ||
@@ -166,2 +166,3 @@ } | ||
}); | ||
return; | ||
} | ||
@@ -168,0 +169,0 @@ |
@@ -9,2 +9,4 @@ "use strict"; | ||
// weak | ||
/* eslint-disable no-param-reassign */ | ||
function isInside(scope, regex) { | ||
@@ -11,0 +13,0 @@ if (!scope.hub.file.opts) { |
{ | ||
"name": "babel-plugin-transform-react-remove-prop-types", | ||
"version": "0.4.9", | ||
"version": "0.4.10", | ||
"description": "Remove unnecessary React propTypes from the production build", | ||
@@ -10,2 +10,3 @@ "main": "lib/index.js", | ||
"test:watch": "mocha -w", | ||
"prettier": "find . -name \"*.js\" | grep -v -f .eslintignore | xargs prettier --write", | ||
"test": "npm run lint && npm run test:unit && npm run flow", | ||
@@ -38,3 +39,3 @@ "prebuild": "rm -rf lib/", | ||
"babel-generator": "^7.0.0-beta.2", | ||
"babel-plugin-flow-react-proptypes": "^5.2.0", | ||
"babel-plugin-flow-react-proptypes": "^6.1.0", | ||
"babel-plugin-transform-flow-strip-types": "^7.0.0-beta.2", | ||
@@ -45,16 +46,18 @@ "babel-preset-es2015": "^7.0.0-beta.2", | ||
"babel-preset-stage-0": "^7.0.0-beta.2", | ||
"chai": "^4.1.0", | ||
"eslint": "^3.19.0", | ||
"eslint-config-airbnb": "^15.1.0", | ||
"chai": "^4.1.2", | ||
"eslint": "^4.8.0", | ||
"eslint-config-airbnb": "^16.0.0", | ||
"eslint-plugin-babel": "^4.1.2", | ||
"eslint-plugin-flowtype": "^2.35.0", | ||
"eslint-plugin-flowtype": "^2.39.1", | ||
"eslint-plugin-import": "^2.7.0", | ||
"eslint-plugin-jsx-a11y": "^5.0.3", | ||
"eslint-plugin-jsx-a11y": "^6.0.2", | ||
"eslint-plugin-mocha": "^4.11.0", | ||
"eslint-plugin-react": "^7.1.0", | ||
"flow-bin": "^0.51.1", | ||
"mocha": "^3.5.0", | ||
"eslint-plugin-prettier": "^2.3.1", | ||
"eslint-plugin-react": "^7.4.0", | ||
"flow-bin": "^0.56.0", | ||
"mocha": "^4.0.1", | ||
"path-exists": "^3.0.0", | ||
"pkgfiles": "^2.3.2" | ||
"pkgfiles": "^2.3.2", | ||
"prettier": "^1.7.4" | ||
} | ||
} |
152
src/index.js
@@ -6,19 +6,18 @@ // @flow weak | ||
// console.log(generate(node).code); | ||
import isAnnotatedForRemoval from './isAnnotatedForRemoval'; | ||
import isStatelessComponent from './isStatelessComponent'; | ||
import remove from './remove'; | ||
import isAnnotatedForRemoval from './isAnnotatedForRemoval' | ||
import isStatelessComponent from './isStatelessComponent' | ||
import remove from './remove' | ||
function isPathReactClass(path) { | ||
if (path.matchesPattern('React.Component') || | ||
path.matchesPattern('React.PureComponent')) { | ||
return true; | ||
if (path.matchesPattern('React.Component') || path.matchesPattern('React.PureComponent')) { | ||
return true | ||
} | ||
const node = path.node; | ||
const node = path.node | ||
if (node && (node.name === 'Component' || node.name === 'PureComponent')) { | ||
return true; | ||
return true | ||
} | ||
return false; | ||
return false | ||
} | ||
@@ -28,19 +27,20 @@ | ||
if (!superClass.node) { | ||
return false; | ||
return false | ||
} | ||
let answer = false; | ||
let answer = false | ||
if (isPathReactClass(superClass)) { | ||
answer = true; | ||
} else if (superClass.node.name) { // Check for inheritance | ||
const className = superClass.node.name; | ||
const binding = scope.getBinding(className); | ||
answer = true | ||
} else if (superClass.node.name) { | ||
// Check for inheritance | ||
const className = superClass.node.name | ||
const binding = scope.getBinding(className) | ||
if (!binding) { | ||
answer = false; | ||
answer = false | ||
} else { | ||
superClass = binding.path.get('superClass'); | ||
const bindingSuperClass = binding.path.get('superClass') | ||
if (isPathReactClass(superClass)) { | ||
answer = true; | ||
if (isPathReactClass(bindingSuperClass)) { | ||
answer = true | ||
} | ||
@@ -50,15 +50,15 @@ } | ||
return answer; | ||
return answer | ||
} | ||
export default function ({ template, types, traverse }) { | ||
export default function({ template, types, traverse }) { | ||
return { | ||
visitor: { | ||
Program(programPath, state) { | ||
let ignoreFilenames; | ||
let ignoreFilenames | ||
if (state.opts.ignoreFilenames) { | ||
ignoreFilenames = new RegExp(state.opts.ignoreFilenames.join('|'), 'gi'); | ||
ignoreFilenames = new RegExp(state.opts.ignoreFilenames.join('|'), 'gi') | ||
} else { | ||
ignoreFilenames = undefined; | ||
ignoreFilenames = undefined | ||
} | ||
@@ -81,9 +81,8 @@ | ||
libraries: (state.opts.additionalLibraries || []).concat('prop-types'), | ||
}; | ||
} | ||
if (state.opts.plugins) { | ||
const pluginsState = state; | ||
const pluginsVisitors = state.opts.plugins.map((pluginOpts) => { | ||
const pluginName = | ||
typeof pluginOpts === 'string' ? pluginOpts : pluginOpts[0]; | ||
const pluginsState = state | ||
const pluginsVisitors = state.opts.plugins.map(pluginOpts => { | ||
const pluginName = typeof pluginOpts === 'string' ? pluginOpts : pluginOpts[0] | ||
@@ -94,14 +93,14 @@ if (typeof pluginOpts !== 'string') { | ||
...pluginOpts[1], | ||
}; | ||
} | ||
} | ||
let plugin = require(pluginName); | ||
let plugin = require(pluginName) | ||
// Required for `babel-plugin-transform-flow-strip-types` | ||
if (typeof plugin !== 'function') { | ||
plugin = plugin.default; | ||
plugin = plugin.default | ||
} | ||
return plugin({ template, types }).visitor; | ||
}); | ||
return plugin({ template, types }).visitor | ||
}) | ||
@@ -113,4 +112,4 @@ traverse( | ||
pluginsState, | ||
programPath.parentPath, | ||
); | ||
programPath.parentPath | ||
) | ||
} | ||
@@ -122,15 +121,15 @@ | ||
exit(path) { | ||
const node = path.node; | ||
const node = path.node | ||
if (node.computed || node.key.name !== 'propTypes') { | ||
return; | ||
return | ||
} | ||
const parent = path.findParent((currentNode) => { | ||
const parent = path.findParent(currentNode => { | ||
if (currentNode.type !== 'CallExpression') { | ||
return false; | ||
return false | ||
} | ||
return currentNode.get('callee').node.name === 'createReactClass'; | ||
}); | ||
return currentNode.get('callee').node.name === 'createReactClass' | ||
}) | ||
@@ -140,3 +139,3 @@ if (parent) { | ||
type: 'createClass', | ||
}); | ||
}) | ||
} | ||
@@ -147,9 +146,6 @@ }, | ||
ClassProperty(path) { | ||
const { | ||
node, | ||
scope, | ||
} = path; | ||
const { node, scope } = path | ||
if (node.key.name === 'propTypes') { | ||
const pathClassDeclaration = scope.path; | ||
const pathClassDeclaration = scope.path | ||
@@ -160,3 +156,3 @@ if (isReactClass(pathClassDeclaration.get('superClass'), scope)) { | ||
pathClassDeclaration, | ||
}); | ||
}) | ||
} | ||
@@ -166,61 +162,63 @@ } | ||
AssignmentExpression(path) { | ||
const { | ||
node, | ||
scope, | ||
} = path; | ||
const { node, scope } = path | ||
if (node.left.computed || !node.left.property || node.left.property.name !== 'propTypes') { | ||
return; | ||
if ( | ||
node.left.computed || | ||
!node.left.property || | ||
node.left.property.name !== 'propTypes' | ||
) { | ||
return | ||
} | ||
const forceRemoval = isAnnotatedForRemoval(path.node.left); | ||
const forceRemoval = isAnnotatedForRemoval(path.node.left) | ||
if (forceRemoval) { | ||
remove(path, globalOptions, { type: 'assign' }); | ||
remove(path, globalOptions, { type: 'assign' }) | ||
return | ||
} | ||
const className = node.left.object.name; | ||
const binding = scope.getBinding(className); | ||
const className = node.left.object.name | ||
const binding = scope.getBinding(className) | ||
if (!binding) { | ||
return; | ||
return | ||
} | ||
if (binding.path.isClassDeclaration()) { | ||
const superClass = binding.path.get('superClass'); | ||
const superClass = binding.path.get('superClass') | ||
if (isReactClass(superClass, scope)) { | ||
remove(path, globalOptions, { type: 'assign' }); | ||
remove(path, globalOptions, { type: 'assign' }) | ||
} | ||
} else if (isStatelessComponent(binding.path)) { | ||
remove(path, globalOptions, { type: 'assign' }); | ||
remove(path, globalOptions, { type: 'assign' }) | ||
} | ||
}, | ||
}); | ||
}) | ||
if (globalOptions.removeImport) { | ||
if (globalOptions.mode === 'remove') { | ||
programPath.scope.crawl(); | ||
programPath.scope.crawl() | ||
programPath.traverse({ | ||
ImportDeclaration(path) { | ||
const { source, specifiers } = path.node; | ||
const { source, specifiers } = path.node | ||
if (globalOptions.libraries.indexOf(source.value) === -1) { | ||
return; | ||
return | ||
} | ||
const haveUsedSpecifiers = specifiers.some((specifier) => { | ||
const importedIdentifierName = specifier.local.name; | ||
const { referencePaths } = path.scope.getBinding(importedIdentifierName); | ||
return referencePaths.length > 0; | ||
}); | ||
const haveUsedSpecifiers = specifiers.some(specifier => { | ||
const importedIdentifierName = specifier.local.name | ||
const { referencePaths } = path.scope.getBinding(importedIdentifierName) | ||
return referencePaths.length > 0 | ||
}) | ||
if (!haveUsedSpecifiers) { | ||
path.remove(); | ||
path.remove() | ||
} | ||
}, | ||
}); | ||
}) | ||
} else { | ||
throw new Error( | ||
'react-remove-prop-types: removeImport and mode=remove can not be used at the same time.', | ||
); | ||
'react-remove-prop-types: removeImport and mode=remove can not be used at the same time.' | ||
) | ||
} | ||
@@ -230,3 +228,3 @@ } | ||
}, | ||
}; | ||
} | ||
} |
// @flow weak | ||
export default function (node) { | ||
const comments = node.trailingComments || []; | ||
export default function(node) { | ||
const comments = node.trailingComments || [] | ||
return !!comments.find(({ value }) => value.trim() === 'remove-proptypes'); | ||
return !!comments.find(({ value }) => value.trim() === 'remove-proptypes') | ||
} |
// @flow weak | ||
function isJSXElementOrReactCreateElement(path) { | ||
let visited = false; | ||
let visited = false | ||
path.traverse({ | ||
CallExpression(path2) { | ||
const callee = path2.get('callee'); | ||
const callee = path2.get('callee') | ||
@@ -14,11 +14,11 @@ if ( | ||
) { | ||
visited = true; | ||
visited = true | ||
} | ||
}, | ||
JSXElement() { | ||
visited = true; | ||
visited = true | ||
}, | ||
}); | ||
}) | ||
return visited; | ||
return visited | ||
} | ||
@@ -29,6 +29,6 @@ | ||
if (path.node.init && path.node.init.body && isJSXElementOrReactCreateElement(path)) { | ||
return true; | ||
return true | ||
} | ||
let visited = false; | ||
let visited = false | ||
@@ -39,39 +39,36 @@ path.traverse({ | ||
if (visited) { | ||
return; | ||
return | ||
} | ||
const argument = path2.get('argument'); | ||
const argument = path2.get('argument') | ||
// Nothing is returned | ||
if (!argument.node) { | ||
return; | ||
return | ||
} | ||
if (isJSXElementOrReactCreateElement(path2)) { | ||
visited = true; | ||
return; | ||
visited = true | ||
return | ||
} | ||
if (argument.node.type === 'CallExpression') { | ||
const name = argument.get('callee').node.name; | ||
const binding = path.scope.getBinding(name); | ||
const name = argument.get('callee').node.name | ||
const binding = path.scope.getBinding(name) | ||
if (!binding) { | ||
return; | ||
return | ||
} | ||
if (isReturningJSXElement(binding.path)) { | ||
visited = true; | ||
visited = true | ||
} | ||
} | ||
}, | ||
}); | ||
}) | ||
return visited; | ||
return visited | ||
} | ||
const VALID_POSSIBLE_STATELESS_COMPONENT_TYPES = [ | ||
'VariableDeclarator', | ||
'FunctionDeclaration', | ||
]; | ||
const VALID_POSSIBLE_STATELESS_COMPONENT_TYPES = ['VariableDeclarator', 'FunctionDeclaration'] | ||
@@ -81,10 +78,10 @@ // Returns `true` if the path represents a function which returns a JSXElement | ||
if (VALID_POSSIBLE_STATELESS_COMPONENT_TYPES.indexOf(path.node.type) === -1) { | ||
return false; | ||
return false | ||
} | ||
if (isReturningJSXElement(path)) { | ||
return true; | ||
return true | ||
} | ||
return false; | ||
return false | ||
} |
// @flow weak | ||
/* eslint-disable no-param-reassign */ | ||
function isInside(scope, regex) { | ||
if (!scope.hub.file.opts) { | ||
return true; | ||
return true | ||
} | ||
const filename = scope.hub.file.opts.filename; | ||
const filename = scope.hub.file.opts.filename | ||
if (!filename) { | ||
return true; | ||
return true | ||
} | ||
return filename.match(regex) !== null; | ||
return filename.match(regex) !== null | ||
} | ||
@@ -26,6 +27,6 @@ | ||
types, | ||
} = globalOptions; | ||
} = globalOptions | ||
if (ignoreFilenames && isInside(path.scope, ignoreFilenames)) { | ||
return; | ||
return | ||
} | ||
@@ -35,6 +36,6 @@ | ||
if (path.node[visitedKey]) { | ||
return; | ||
return | ||
} | ||
path.node[visitedKey] = true; | ||
path.node[visitedKey] = true | ||
@@ -44,8 +45,8 @@ if (mode === 'remove') { | ||
if (path.parentPath.type === 'ConditionalExpression') { | ||
path.replaceWith(types.unaryExpression('void', types.numericLiteral(0))); | ||
path.replaceWith(types.unaryExpression('void', types.numericLiteral(0))) | ||
} else { | ||
path.remove(); | ||
path.remove() | ||
} | ||
return; | ||
return | ||
} | ||
@@ -57,27 +58,31 @@ | ||
case 'createClass': | ||
break; | ||
break | ||
// Inspired from babel-plugin-transform-class-properties. | ||
case 'class static': { | ||
let ref; | ||
let pathClassDeclaration = options.pathClassDeclaration; | ||
let ref | ||
let pathClassDeclaration = options.pathClassDeclaration | ||
if (!pathClassDeclaration.isClassExpression() && pathClassDeclaration.node.id) { | ||
ref = pathClassDeclaration.node.id; | ||
ref = pathClassDeclaration.node.id | ||
} else { | ||
// Class without name not supported | ||
return; | ||
return | ||
} | ||
const node = types.expressionStatement( | ||
types.assignmentExpression('=', types.memberExpression(ref, path.node.key), path.node.value), | ||
); | ||
types.assignmentExpression( | ||
'=', | ||
types.memberExpression(ref, path.node.key), | ||
path.node.value | ||
) | ||
) | ||
// We need to append the node at the parent level in this case. | ||
if (pathClassDeclaration.parentPath.isExportDeclaration()) { | ||
pathClassDeclaration = pathClassDeclaration.parentPath; | ||
pathClassDeclaration = pathClassDeclaration.parentPath | ||
} | ||
pathClassDeclaration.insertAfter(node); | ||
path.remove(); | ||
break; | ||
pathClassDeclaration.insertAfter(node) | ||
path.remove() | ||
break | ||
} | ||
@@ -87,26 +92,26 @@ | ||
if (mode === 'unsafe-wrap') { | ||
path.replaceWith(unsafeWrapTemplate( | ||
{ | ||
path.replaceWith( | ||
unsafeWrapTemplate({ | ||
NODE: path.node, | ||
}, | ||
)); | ||
}) | ||
) | ||
} else { | ||
path.replaceWith(wrapTemplate( | ||
{ | ||
path.replaceWith( | ||
wrapTemplate({ | ||
LEFT: path.node.left, | ||
RIGHT: path.node.right, | ||
}, | ||
)); | ||
}) | ||
) | ||
} | ||
path.node[visitedKey] = true; | ||
break; | ||
path.node[visitedKey] = true | ||
break | ||
default: | ||
break; | ||
break | ||
} | ||
return; | ||
return | ||
} | ||
throw new Error(`transform-react-remove-prop-type: unsupported mode ${mode}.`); | ||
throw new Error(`transform-react-remove-prop-type: unsupported mode ${mode}.`) | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
32797
683
25