Last active
October 6, 2017 11:30
-
-
Save olvnikon/201bade96b53cdc7f5f787e8f2066b85 to your computer and use it in GitHub Desktop.
[AST + JSShiftCode] - AngularJS 1.x directive to component
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
const DIRECTIVE_TO_COMPONENT = { | |
scope: "bindings" | |
}; | |
const DEPRECATED_PROPS = ["restrict", "replace", "bindToController"]; | |
const DIRECTIVE_UNIQUE_PROPS = ["link", "compile", "multiElement", "priority", "templateNamespace", "terminal"]; | |
function transform(j, path) { | |
const directiveDeclaration = path.value.arguments[1]; | |
const directiveProperties = directiveDeclaration.body.body[0].argument.properties; | |
const newProps = directiveProperties.filter(prop => !DEPRECATED_PROPS.includes(prop.key.name)); | |
const calleeObject = path.value.callee.object; | |
const args = path.value.arguments; | |
const controllerName = args[0].value; | |
const componentName = controllerName.charAt(0).toLowerCase() + controllerName.slice(1); | |
j(path).replaceWith( | |
j.callExpression( | |
j.memberExpression(j.callExpression(calleeObject.callee, calleeObject.arguments), j.identifier("component")), | |
[ | |
j.literal(componentName), | |
j.objectExpression( | |
newProps.map(prop => { | |
const newIdentifier = DIRECTIVE_TO_COMPONENT[prop.key.name]; | |
return !!newIdentifier ? j.property("init", j.identifier(newIdentifier), prop.value) : prop; | |
}) | |
) | |
] | |
) | |
); | |
} | |
module.exports = function(fileInfo, api, options) { | |
const j = api.jscodeshift; | |
const ast = j(fileInfo.source); | |
ast | |
.find(j.CallExpression) | |
// Filter only directives | |
.filter(path => { | |
const calleeProperty = path.value.callee.property; | |
return calleeProperty && calleeProperty.type === j.Identifier.name && calleeProperty.name === "directive"; | |
}) | |
// Filter directives with only return statement and with restrict "E" | |
.filter(path => { | |
const directiveDeclaration = path.value.arguments[1]; | |
const directiveBody = directiveDeclaration.body.body; | |
return directiveBody.length === 1 && directiveBody[0].type === j.ReturnStatement.name; | |
}) | |
// Filter directives with restrict "E" and without directive unique props | |
.filter(path => { | |
const directiveDeclaration = path.value.arguments[1]; | |
const directiveProperties = directiveDeclaration.body.body[0].argument.properties; | |
const rejectedProps = directiveProperties.filter(prop => DIRECTIVE_UNIQUE_PROPS.includes(prop.key.name)); | |
if (rejectedProps.length > 0) { | |
return false; | |
} | |
const restrict = directiveProperties.filter(prop => prop.key.name === "restrict"); | |
return restrict.length === 0 ? false : restrict[0].value.value === "E"; | |
}) | |
.forEach(path => { | |
transform(j, path); | |
}); | |
return ast.toSource(); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This script converts AngularJS 1.x directives to components if it is allowed to do this. The directive should be an element and shouldn't contain unique for it properties.
Before:
After: