Matches pattern cleanup (#5826)
* Extract duplicated function into babel-types Also reimplements in a sane way. * Add tests * cleanup
This commit is contained in:
parent
8df5514083
commit
5cc1cbf3bc
@ -12,54 +12,7 @@ import * as t from "babel-types";
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export function matchesPattern(pattern: string, allowPartial?: boolean): boolean {
|
export function matchesPattern(pattern: string, allowPartial?: boolean): boolean {
|
||||||
// not a member expression
|
return t.matchesPattern(this.node, pattern, allowPartial);
|
||||||
if (!this.isMemberExpression()) return false;
|
|
||||||
|
|
||||||
const parts = pattern.split(".");
|
|
||||||
const search = [this.node];
|
|
||||||
let i = 0;
|
|
||||||
|
|
||||||
function matches(name) {
|
|
||||||
const part = parts[i];
|
|
||||||
return part === "*" || name === part;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (search.length) {
|
|
||||||
const node = search.shift();
|
|
||||||
|
|
||||||
if (allowPartial && i === parts.length) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t.isIdentifier(node)) {
|
|
||||||
// this part doesn't match
|
|
||||||
if (!matches(node.name)) return false;
|
|
||||||
} else if (t.isLiteral(node)) {
|
|
||||||
// this part doesn't match
|
|
||||||
if (!matches(node.value)) return false;
|
|
||||||
} else if (t.isMemberExpression(node)) {
|
|
||||||
if (node.computed && !t.isLiteral(node.property)) {
|
|
||||||
// we can't deal with this
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
search.unshift(node.property);
|
|
||||||
search.unshift(node.object);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else if (t.isThisExpression(node)) {
|
|
||||||
if (!matches("this")) return false;
|
|
||||||
} else {
|
|
||||||
// we can't deal with this
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// too many parts
|
|
||||||
if (++i > parts.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return i === parts.length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -314,6 +314,51 @@ export function cloneDeep(node: Object): Object {
|
|||||||
return newNode;
|
return newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether or not the input node `member` matches the
|
||||||
|
* input `match`.
|
||||||
|
*
|
||||||
|
* For example, given the match `React.createClass` it would match the
|
||||||
|
* parsed nodes of `React.createClass` and `React["createClass"]`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function matchesPattern(
|
||||||
|
member: Object,
|
||||||
|
match: string | Array<string>,
|
||||||
|
allowPartial?: boolean
|
||||||
|
): boolean {
|
||||||
|
// not a member expression
|
||||||
|
if (!t.isMemberExpression(member)) return false;
|
||||||
|
|
||||||
|
const parts = Array.isArray(match) ? match : match.split(".");
|
||||||
|
const nodes = [];
|
||||||
|
|
||||||
|
let node;
|
||||||
|
for (node = member; t.isMemberExpression(node); node = node.object) {
|
||||||
|
nodes.push(node.property);
|
||||||
|
}
|
||||||
|
nodes.push(node);
|
||||||
|
|
||||||
|
if (nodes.length < parts.length) return false;
|
||||||
|
if (!allowPartial && nodes.length > parts.length) return false;
|
||||||
|
|
||||||
|
for (let i = 0, j = nodes.length - 1; i < parts.length; i++, j--) {
|
||||||
|
const node = nodes[j];
|
||||||
|
let value;
|
||||||
|
if (t.isIdentifier(node)) {
|
||||||
|
value = node.name;
|
||||||
|
} else if (t.isStringLiteral(node)) {
|
||||||
|
value = node.value;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts[i] !== value) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a function that when called will return whether or not the
|
* Build a function that when called will return whether or not the
|
||||||
* input `node` `MemberExpression` matches the input `match`.
|
* input `node` `MemberExpression` matches the input `match`.
|
||||||
@ -322,50 +367,10 @@ export function cloneDeep(node: Object): Object {
|
|||||||
* parsed nodes of `React.createClass` and `React["createClass"]`.
|
* parsed nodes of `React.createClass` and `React["createClass"]`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function buildMatchMemberExpression(match:string, allowPartial?: boolean): Function {
|
export function buildMatchMemberExpression(match: string, allowPartial?: boolean): (Object) => boolean {
|
||||||
const parts = match.split(".");
|
const parts = match.split(".");
|
||||||
|
|
||||||
return function (member) {
|
return function (member) {
|
||||||
// not a member expression
|
return matchesPattern(member, parts, allowPartial);
|
||||||
if (!t.isMemberExpression(member)) return false;
|
|
||||||
|
|
||||||
const search = [member];
|
|
||||||
let i = 0;
|
|
||||||
|
|
||||||
while (search.length) {
|
|
||||||
const node = search.shift();
|
|
||||||
|
|
||||||
if (allowPartial && i === parts.length) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t.isIdentifier(node)) {
|
|
||||||
// this part doesn't match
|
|
||||||
if (parts[i] !== node.name) return false;
|
|
||||||
} else if (t.isStringLiteral(node)) {
|
|
||||||
// this part doesn't match
|
|
||||||
if (parts[i] !== node.value) return false;
|
|
||||||
} else if (t.isMemberExpression(node)) {
|
|
||||||
if (node.computed && !t.isStringLiteral(node.property)) {
|
|
||||||
// we can't deal with this
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
search.push(node.object);
|
|
||||||
search.push(node.property);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// we can't deal with this
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// too many parts
|
|
||||||
if (++i > parts.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
45
packages/babel-types/test/misc.js
Normal file
45
packages/babel-types/test/misc.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import * as t from "../lib";
|
||||||
|
import { assert } from "chai";
|
||||||
|
import { parse } from "babylon";
|
||||||
|
|
||||||
|
function parseCode(string) {
|
||||||
|
return parse(string, {
|
||||||
|
allowReturnOutsideFunction: true,
|
||||||
|
}).program.body[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("misc helpers", function () {
|
||||||
|
describe("matchesPattern", function () {
|
||||||
|
it("matches explicitly", function () {
|
||||||
|
const ast = parseCode("a.b.c.d").expression;
|
||||||
|
assert(t.matchesPattern(ast, "a.b.c.d"));
|
||||||
|
assert.isFalse(t.matchesPattern(ast, "a.b.c"));
|
||||||
|
assert.isFalse(t.matchesPattern(ast, "b.c.d"));
|
||||||
|
assert.isFalse(t.matchesPattern(ast, "a.b.c.d.e"));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("matches partially", function () {
|
||||||
|
const ast = parseCode("a.b.c.d").expression;
|
||||||
|
assert(t.matchesPattern(ast, "a.b.c.d", true));
|
||||||
|
assert(t.matchesPattern(ast, "a.b.c", true));
|
||||||
|
assert.isFalse(t.matchesPattern(ast, "b.c.d", true));
|
||||||
|
assert.isFalse(t.matchesPattern(ast, "a.b.c.d.e", true));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("matches string literal expressions", function () {
|
||||||
|
const ast = parseCode("a['b'].c.d").expression;
|
||||||
|
assert(t.matchesPattern(ast, "a.b.c.d"));
|
||||||
|
assert.isFalse(t.matchesPattern(ast, "a.b.c"));
|
||||||
|
assert.isFalse(t.matchesPattern(ast, "b.c.d"));
|
||||||
|
assert.isFalse(t.matchesPattern(ast, "a.b.c.d.e"));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("matches string literal expressions partially", function () {
|
||||||
|
const ast = parseCode("a['b'].c.d").expression;
|
||||||
|
assert(t.matchesPattern(ast, "a.b.c.d", true));
|
||||||
|
assert(t.matchesPattern(ast, "a.b.c", true));
|
||||||
|
assert.isFalse(t.matchesPattern(ast, "b.c.d", true));
|
||||||
|
assert.isFalse(t.matchesPattern(ast, "a.b.c.d.e", true));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user