mirror of
https://github.com/gosticks/DefinitelyTyped.git
synced 2026-10-05 07:17:04 +00:00
[jscodeshift] Fix compiler errors in test/js-transforms
This commit is contained in:
Vendored
+4
-2
@@ -250,7 +250,9 @@ declare module "jscodeshift/src/Collection" {
|
||||
|
||||
declare module "jscodeshift/src/collections/Node" {
|
||||
import { Collection } from "jscodeshift/src/Collection";
|
||||
import { ASTNode, Type } from "recast";
|
||||
import { ASTNode, Type, NodePath } from "recast";
|
||||
|
||||
type ASTPath<N> = NodePath<N, N>;
|
||||
|
||||
export interface TraversalMethods {
|
||||
/**
|
||||
@@ -285,7 +287,7 @@ declare module "jscodeshift/src/collections/Node" {
|
||||
* is provided it is executed for every node and the node is replaced with the
|
||||
* functions return value.
|
||||
*/
|
||||
replaceWith<T>(nodes: T | T[] | ((path: any, i: number) => T)): this;
|
||||
replaceWith<T>(nodes: T | T[] | ((path: ASTPath<N>, i: number) => T)): Collection<T>;
|
||||
|
||||
/**
|
||||
* Inserts a new node before the current one.
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
Sample jscodeshift transforms taken from https://github.com/jhgg/js-transforms
|
||||
and converted to TypeScript, for use as real-world test cases.
|
||||
Executable → Regular
+3
-2
@@ -8,8 +8,9 @@
|
||||
* let x = ::this.foo;
|
||||
*
|
||||
*/
|
||||
import { Transform, MemberExpression } from "jscodeshift";
|
||||
|
||||
module.exports = function (file, api) {
|
||||
const transform: Transform = function (file, api) {
|
||||
const j = api.jscodeshift;
|
||||
return j(file.source)
|
||||
// Find stuff that looks like this.xyz.bind(this)
|
||||
@@ -17,6 +18,6 @@ module.exports = function (file, api) {
|
||||
// Ensure that .bind() is being called with only one argument, and that argument is "this".
|
||||
.filter(p => p.value.arguments.length == 1 && p.value.arguments[0].type == "ThisExpression")
|
||||
// We can now replace it with ::this.xyz
|
||||
.replaceWith(p => j.bindExpression(null, p.value.callee.object))
|
||||
.replaceWith(p => j.bindExpression(null, (p.value.callee as MemberExpression).object))
|
||||
.toSource();
|
||||
};
|
||||
+14
-5
@@ -25,8 +25,9 @@
|
||||
* var a = c => c;
|
||||
*
|
||||
*/
|
||||
import { Transform, MemberExpression, FunctionExpression } from "jscodeshift";
|
||||
|
||||
module.exports = function(file, api) {
|
||||
const transform: Transform = function(file, api) {
|
||||
const j = api.jscodeshift;
|
||||
|
||||
return j(file.source)
|
||||
@@ -35,16 +36,24 @@ module.exports = function(file, api) {
|
||||
// Verify that .bind() is only being called with `this` as it's sole arguments.
|
||||
.filter(p => p.value.arguments.length == 1 && p.value.arguments[0].type == "ThisExpression")
|
||||
.replaceWith(p => {
|
||||
var callee = p.value.callee as MemberExpression;
|
||||
var object = callee.object as FunctionExpression;
|
||||
// Grab the function body. Since we looked for the CallExpression originally, the "callee.object" would refer
|
||||
// to the FunctionExpression that's being called .bind(this) on. We need the body of that function
|
||||
// to transform into an ArrowFunctionExpression.
|
||||
var body = p.value.callee.object.body;
|
||||
var body = object.body;
|
||||
// We can get a bit clever here. If we have a function that consists of a single return statement in it's body,
|
||||
// we can transform it to the more compact arrowFunctionExpression (a, b) => a + b, vs (a + b) => { return a + b }
|
||||
var useExpression = body.type == 'BlockStatement' && body.body.length == 1 && body.body[0].type == "ReturnStatement";
|
||||
body = useExpression ? body.body[0].argument : body;
|
||||
var useExpression = false;
|
||||
if (body.type == 'BlockStatement' && body.body.length == 1) {
|
||||
const first = body.body[0];
|
||||
if (first.type == "ReturnStatement") {
|
||||
useExpression = true;
|
||||
body = first.argument!;
|
||||
}
|
||||
}
|
||||
|
||||
return j.arrowFunctionExpression(p.value.callee.object.params, body, useExpression);
|
||||
return j.arrowFunctionExpression(object.params, body, useExpression);
|
||||
})
|
||||
.toSource();
|
||||
};
|
||||
+10
-3
@@ -25,8 +25,9 @@
|
||||
* return a + b + this.c;
|
||||
* }
|
||||
*/
|
||||
import { Transform } from "jscodeshift";
|
||||
|
||||
module.exports = function (file, api) {
|
||||
const transform: Transform = function (file, api) {
|
||||
const j = api.jscodeshift;
|
||||
|
||||
return j(file.source)
|
||||
@@ -38,8 +39,14 @@ module.exports = function (file, api) {
|
||||
var body = p.value.body;
|
||||
// We can get a bit clever here. If we have a function that consists of a single return statement in it's body,
|
||||
// we can transform it to the more compact arrowFunctionExpression (a, b) => a + b, vs (a + b) => { return a + b }
|
||||
var useExpression = body.type == 'BlockStatement' && body.body.length == 1 && body.body[0].type == "ReturnStatement";
|
||||
body = useExpression ? body.body[0].argument : body;
|
||||
var useExpression = false;
|
||||
if (body.type == 'BlockStatement' && body.body.length == 1) {
|
||||
const first = body.body[0];
|
||||
if (first.type == "ReturnStatement") {
|
||||
useExpression = true;
|
||||
body = first.argument!;
|
||||
}
|
||||
}
|
||||
return j.arrowFunctionExpression(p.value.params, body, useExpression);
|
||||
})
|
||||
.toSource();
|
||||
|
||||
@@ -19,37 +19,40 @@
|
||||
* }
|
||||
*
|
||||
*/
|
||||
import { Transform, VariableDeclarator, ObjectPattern, Identifier, BlockStatement } from "jscodeshift";
|
||||
|
||||
let keywords = 'this function if return var else for new in typeof while case break try catch delete throw switch continue default instanceof do void finally with debugger implements interface package private protected public static class enum export extends import super true false null abstract boolean byte char const double final float goto int long native short synchronized throws transient volatile';
|
||||
keywords = keywords.split(' ').reduce((f, k) => {
|
||||
const keywordsStr = 'this function if return var else for new in typeof while case break try catch delete throw switch continue default instanceof do void finally with debugger implements interface package private protected public static class enum export extends import super true false null abstract boolean byte char const double final float goto int long native short synchronized throws transient volatile';
|
||||
let keywords = keywordsStr.split(' ').reduce<{ [key: string]: boolean }>((f, k) => {
|
||||
f[k] = true;
|
||||
return f;
|
||||
}, {});
|
||||
const isKeyword = k => keywords.hasOwnProperty(k);
|
||||
const isKeyword = (k: string) => keywords.hasOwnProperty(k);
|
||||
|
||||
module.exports = function (file, api) {
|
||||
const transform: Transform = function (file, api) {
|
||||
const j = api.jscodeshift;
|
||||
const {statement} = j.template;
|
||||
|
||||
return j(file.source)
|
||||
.find(j.FunctionExpression)
|
||||
.replaceWith(p => {
|
||||
console.log(p);
|
||||
// console.log(p);
|
||||
const root = j(p.value);
|
||||
const variablesToReplace = {};
|
||||
const variablesToReplace: { [name: string]: boolean } = {};
|
||||
|
||||
// Figure out if the variable was defined from props, so that we can re-use that definition.
|
||||
const isFromProps = (name, resolvedScope) => {
|
||||
const isFromProps = (name: string, resolvedScope: any) => {
|
||||
return resolvedScope.getBindings()[name].every(
|
||||
p => {
|
||||
(p: any) => {
|
||||
const decl = j(p).closest(j.VariableDeclarator);
|
||||
// What happens when our VariableDeclarator is too high up the parent AST?
|
||||
|
||||
if (!decl.size()) return false;
|
||||
const node = decl.nodes()[0];
|
||||
const node: VariableDeclarator = decl.nodes()[0];
|
||||
|
||||
if (!(node.init.type == 'MemberExpression' &&
|
||||
if (!(node.init != null &&
|
||||
node.init.type == 'MemberExpression' &&
|
||||
node.init.object.type == 'ThisExpression' &&
|
||||
node.init.property.type == 'Identifier' &&
|
||||
node.init.property.name == 'props'))
|
||||
return false;
|
||||
|
||||
@@ -74,17 +77,17 @@ module.exports = function (file, api) {
|
||||
}
|
||||
})
|
||||
.filter(e => {
|
||||
const resolvedScope = e.scope.lookup(e.value.property.name);
|
||||
const resolvedScope = e.scope.lookup((e.value.property as Identifier).name);
|
||||
// If the scope is null, that means that this property isn't defined in the scope yet,
|
||||
// and we can use it. Otherwise, if it is defined, we should see if it was defined from `this.props`
|
||||
// if none of these cases are true, we can't do substitution.
|
||||
return resolvedScope == null || isFromProps(e.value.property.name, resolvedScope);
|
||||
return resolvedScope == null || isFromProps((e.value.property as Identifier).name, resolvedScope);
|
||||
})
|
||||
// Ensure that our substitution won't cause us to define a keyword, i.e. `this.props.while` won't
|
||||
// get converted into `while`.
|
||||
.filter(p => !isKeyword(p.value.property.name))
|
||||
.filter(p => !isKeyword((p.value.property as Identifier).name))
|
||||
// Now, do the replacement, `this.props.xyz` => `xyz`.
|
||||
.replaceWith(p => p.value.property)
|
||||
.replaceWith(p => p.value.property as Identifier)
|
||||
// Finally, mark the variable as something we will need to define earlier in the function,
|
||||
// if it's not already defined.
|
||||
.forEach(p => {
|
||||
@@ -117,7 +120,8 @@ module.exports = function (file, api) {
|
||||
if (propDefinitions.size()) {
|
||||
const nodePath = propDefinitions.paths()[0];
|
||||
const node = nodePath.value;
|
||||
const newPattern = j.objectPattern(node.id.properties.concat(properties));
|
||||
// TODO(brieb): support narrowing based on second argument to `find`
|
||||
const newPattern = j.objectPattern((node.id as ObjectPattern).properties.concat(properties));
|
||||
nodePath.replace(j.variableDeclarator(newPattern, node.init));
|
||||
return p.value;
|
||||
}
|
||||
@@ -130,7 +134,7 @@ module.exports = function (file, api) {
|
||||
return j.functionExpression(
|
||||
p.value.id,
|
||||
p.value.params,
|
||||
j.blockStatement([decl].concat(p.value.body.body))
|
||||
j.blockStatement([decl].concat((p.value.body as BlockStatement).body))
|
||||
);
|
||||
}
|
||||
).toSource();
|
||||
|
||||
@@ -27,12 +27,13 @@
|
||||
* }
|
||||
*/
|
||||
|
||||
import { Transform, ASTNode } from "jscodeshift";
|
||||
|
||||
module.exports = function (file, api) {
|
||||
const transform: Transform = function (file, api) {
|
||||
const j = api.jscodeshift;
|
||||
const {statement} = j.template;
|
||||
|
||||
function hasJSXElement(ast) {
|
||||
function hasJSXElement(ast: ASTNode) {
|
||||
return j(ast).find(j.JSXElement).size() > 0;
|
||||
}
|
||||
|
||||
@@ -41,21 +42,22 @@ module.exports = function (file, api) {
|
||||
.filter(p => p.value.declarations.length == 1)
|
||||
.replaceWith(p => {
|
||||
const decl = p.value.declarations[0];
|
||||
if (decl.init.type !== 'ArrowFunctionExpression' ||
|
||||
(!hasJSXElement(decl.init.body) && decl.init.body.type !== "JSXElement"))
|
||||
return p.value;
|
||||
if (decl.type === "VariableDeclarator" && decl.init != null) {
|
||||
if (decl.init.type !== 'ArrowFunctionExpression' ||
|
||||
(!hasJSXElement(decl.init.body) && decl.init.body.type !== "JSXElement"))
|
||||
return p.value;
|
||||
|
||||
let body = decl.init.body;
|
||||
body = body.type == "JSXElement" ? j.returnStatement(body) : body = body.body;
|
||||
let body: any = decl.init.body;
|
||||
body = body.type == "JSXElement" ? j.returnStatement(body) : body = body.body;
|
||||
|
||||
j(body)
|
||||
.find(j.Identifier, {name: 'props'})
|
||||
.replaceWith(p => j.memberExpression(j.thisExpression(), j.identifier('props')));
|
||||
|
||||
return statement`class ${decl.id} extends Component {
|
||||
render() { ${body} }
|
||||
}`;
|
||||
j(body)
|
||||
.find(j.Identifier, {name: 'props'})
|
||||
.replaceWith(p => j.memberExpression(j.thisExpression(), j.identifier('props')));
|
||||
|
||||
return statement`class ${decl.id} extends Component {
|
||||
render() { ${body} }
|
||||
}`;
|
||||
}
|
||||
})
|
||||
.toSource();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user