Skip to content

Instantly share code, notes, and snippets.

@nathan-muir
Created January 23, 2018 08:38
Show Gist options
  • Save nathan-muir/3aa99ce7fcde32824a77975c27b7d761 to your computer and use it in GitHub Desktop.
Save nathan-muir/3aa99ce7fcde32824a77975c27b7d761 to your computer and use it in GitHub Desktop.
Meteor Blaze JS CodeShift
/**
* jscodeshift script that converts
* Template.xyz.{helperName} = function(){}
* to use
* Template.xyz.helpers({ helperName: function(){} })
*/
export default function transformer(file, api) {
let j = api.jscodeshift;
let ast = j(file.source);
ast.find(j.AssignmentExpression)
.filter(path => {
let { type, operator, left, right } = path.node;
let valid = operator === '='
&& (right.type === 'FunctionExpression' || right.type === 'ArrowFunctionExpression')
&& left.type === 'MemberExpression' && left.object.type === 'MemberExpression'
&& left.object.object.type === 'Identifier' && left.object.object.name === 'Template'
&& left.property.name !== 'created'
&& left.property.name !== 'rendered'
&& left.property.name !== 'destroyed';
return valid;
})
.forEach(function (path) {
let { left, right } = path.node;
// console.log('left=', left, 'right=', right);
let prop;
if (right.type === 'ArrowFunctionExpression') {
let body;
if (j.BlockStatement.check(right.body)) {
body = right.body;
} else {
// const comments = right.init.body.comments;
body = j.blockStatement([
j.returnStatement(right.body),
]);
}
prop = j.property('init', j.identifier(left.property.name), j.functionExpression(
right.id, right.params, body, right.generator, right.expression
))
} else {
prop = j.property('init', j.identifier(left.property.name), right);
}
prop.method = true;
let resultNode = j.callExpression(
j.memberExpression(left.object, j.identifier('helpers')),
[
j.objectExpression([
prop
])
]
);
resultNode.comments = [];
j(path).replaceWith(resultNode);
});
let helperBlocks = new Map();
ast.find(j.CallExpression)
.filter(path => {
let { callee } = path.node;
let valid = callee.type === 'MemberExpression' &&
callee.object.type === 'MemberExpression' &&
callee.object.object.name === 'Template' &&
callee.property.name === 'helpers' &&
path.node.arguments.length === 1 &&
path.node.arguments[0].type === 'ObjectExpression';
return valid;
}).forEach(function (path) {
let { callee } = path.node;
let templateName = callee.object.property.name;
let exprs = helperBlocks.get(templateName) || [];
helperBlocks.set(templateName, exprs.concat([path]))
});
helperBlocks.forEach(function (paths) {
if (paths.length === 1) return;
let firstPath = paths.shift();
let firstExpr = firstPath.node;
let properties = firstExpr.arguments[0].properties.slice(0);
paths.forEach(function (path) {
let expr = path.node;
properties.push(...expr.arguments[0].properties);
j(path).remove()
});
j(firstPath).replaceWith(
j.callExpression(firstExpr.callee, [
j.objectExpression(properties)
])
)
});
return ast.toSource();
}
/**
* jscodeshift script that converts
* TemplateHooks(Template.xyz, {created: function(){} });
* to use
* Template.xyz.onCreated(function(){})
*/
export default function transformer(file, api) {
let j = api.jscodeshift;
let ast = j(file.source);
ast.find(j.CallExpression)
.filter(path => {
let { callee } = path.node;
let valid = callee.name === 'TemplateHooks'
&& path.node.arguments.length === 2
&& path.node.arguments[0].type === 'MemberExpression'
&& path.node.arguments[1].type === 'ObjectExpression'
;
return valid;
})
.forEach(function (path) {
let [exp, obj] = path.node.arguments;
let newNodes = obj.properties.map(function ({ key, value }) {
let propName;
if (key.type === 'Literal') {
propName = key.value;
} else if (key.type === 'Identifier') {
propName = key.name;
}
let fnName;
if (propName === 'created') {
fnName = 'onCreated'
} else if (propName === 'rendered') {
fnName = 'onRendered'
} else if (propName === 'destroyed') {
fnName = 'onDestroyed'
}
let fn;
if (value.type === 'ArrowFunctionExpression') {
let body;
if (j.BlockStatement.check(value.body)) {
body = value.body;
} else {
// const comments = value.init.body.comments;
body = j.blockStatement([
j.returnStatement(value.body),
]);
}
fn = j.functionExpression(
value.id, value.params, body, value.generator, value.expression
)
} else {
fn = value;
}
let c = j.callExpression(
j.memberExpression(exp, j.identifier(fnName)),
[
fn
]
);
return j.expressionStatement(c)
});
// Need to replace the parent "ExpressionStatement"'s
j(path.parent).replaceWith(newNodes)
});
return ast.toSource();
}
/**
* jscodeshift script that converts
* Template.xyz.(rendered|created|destroyed) = function(){}
* to use
* Template.xyz.(onRendered|onCreated|onDestroyed)(function(){})
*/
export default function transformer(file, api) {
let j = api.jscodeshift;
let ast = j(file.source);
ast.find(j.AssignmentExpression)
.filter(path => {
let { type, operator, left, right } = path.node;
let valid = operator === '='
&& (right.type === 'FunctionExpression' || right.type === 'ArrowFunctionExpression')
&& left.type === 'MemberExpression' && left.object.type === 'MemberExpression'
&& left.object.object.type === 'Identifier' && left.object.object.name === 'Template'
&& (left.property.name === 'created' || left.property.name === 'rendered' || left.property.name === 'destroyed');
return valid;
})
.forEach(function (path) {
let { left, right } = path.node;
// console.log('left=', left, 'right=', right);
let fn;
if (right.type === 'ArrowFunctionExpression') {
let body;
if (j.BlockStatement.check(right.body)) {
body = right.body;
} else {
// const comments = right.init.body.comments;
body = j.blockStatement([
j.returnStatement(right.body),
]);
}
fn = j.functionExpression(
right.id, right.params, body, right.generator, right.expression
)
} else {
fn = right;
}
let propName =left.property.name;
let fnName;
if (propName === 'created') {
fnName = 'onCreated'
} else if (propName === 'rendered'){
fnName = 'onRendered'
} else if (propName === 'destroyed') {
fnName = 'onDestroyed'
}
let resultNode = j.callExpression(
j.memberExpression(left.object, j.identifier(fnName)),
[
fn
]
);
resultNode.comments = [];
j(path).replaceWith(resultNode);
});
return ast.toSource();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment