add validation to babel-types - fixes #1858
This commit is contained in:
parent
ab78685124
commit
59f71a3a09
@ -24,7 +24,7 @@ export function insertBefore(nodes) {
|
||||
return this._containerInsertBefore(nodes);
|
||||
} else if (this.isStatementOrBlock()) {
|
||||
if (this.node) nodes.push(this.node);
|
||||
this.node = this.container[this.key] = t.blockStatement(nodes);
|
||||
this._replaceWith(t.blockStatement(nodes));
|
||||
} else {
|
||||
throw new Error("We don't know what to do with this node type. We were previously a Statement but we can't fit in here?");
|
||||
}
|
||||
@ -101,7 +101,7 @@ export function insertAfter(nodes) {
|
||||
return this._containerInsertAfter(nodes);
|
||||
} else if (this.isStatementOrBlock()) {
|
||||
if (this.node) nodes.unshift(this.node);
|
||||
this.node = this.container[this.key] = t.blockStatement(nodes);
|
||||
this._replaceWith(t.blockStatement(nodes));
|
||||
} else {
|
||||
throw new Error("We don't know what to do with this node type. We were previously a Statement but we can't fit in here?");
|
||||
}
|
||||
@ -115,6 +115,8 @@ export function insertAfter(nodes) {
|
||||
*/
|
||||
|
||||
export function updateSiblingKeys(fromIndex, incrementBy) {
|
||||
if (!this.parent) return;
|
||||
|
||||
var paths = this.parent._paths;
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
let path = paths[i];
|
||||
|
||||
@ -40,13 +40,12 @@ export function _callRemovalHooks(position) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function _remove() {
|
||||
if (Array.isArray(this.container)) {
|
||||
this.container.splice(this.key, 1);
|
||||
this.updateSiblingKeys(this.key, -1);
|
||||
} else {
|
||||
this.container[this.key] = null;
|
||||
this._replaceWith(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -141,13 +141,27 @@ export function replaceWith(replacement, whateverAllowed) {
|
||||
if (oldNode) t.inheritsComments(replacement, oldNode);
|
||||
|
||||
// replace the node
|
||||
this.node = this.container[this.key] = replacement;
|
||||
this._replaceWith(replacement);
|
||||
this.type = replacement.type;
|
||||
|
||||
// potentially create new scope
|
||||
this.setScope();
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
export function _replaceWith(node) {
|
||||
if (this.inList) {
|
||||
t.validate(this.key, this.parent, [node]);
|
||||
} else {
|
||||
t.validate(this.key, this.parent, node);
|
||||
}
|
||||
|
||||
this.node = this.container[this.key] = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes an array of statements nodes and then explodes it
|
||||
* into expressions. This method retains completion records which is
|
||||
|
||||
@ -1,11 +1,21 @@
|
||||
import define from "./index";
|
||||
import define, { assertValueType, assertNodeType } from "./index";
|
||||
|
||||
define("ArrayExpression", {
|
||||
fields: {
|
||||
elements: { validate: assertValueType("array") }
|
||||
},
|
||||
visitor: ["elements"],
|
||||
aliases: ["Expression"]
|
||||
});
|
||||
|
||||
define("AssignmentExpression", {
|
||||
fields: {
|
||||
elements: {
|
||||
operator: { validate: assertValueType("string") },
|
||||
left: { validate: assertNodeType("LVal") },
|
||||
right: { validate: assertNodeType("Expression") }
|
||||
}
|
||||
},
|
||||
builder: ["operator", "left", "right"],
|
||||
visitor: ["left", "right"],
|
||||
aliases: ["Expression"]
|
||||
@ -13,12 +23,20 @@ define("AssignmentExpression", {
|
||||
|
||||
define("BinaryExpression", {
|
||||
builder: ["operator", "left", "right"],
|
||||
fields: {
|
||||
operator: { validate: assertValueType("string") },
|
||||
left: { validate: assertNodeType("Expression") },
|
||||
right: { validate: assertNodeType("Expression") }
|
||||
},
|
||||
visitor: ["left", "right"],
|
||||
aliases: ["Binary", "Expression"]
|
||||
});
|
||||
|
||||
define("BlockStatement", {
|
||||
visitor: ["body"],
|
||||
fields: {
|
||||
body: { validate: assertValueType("array") }
|
||||
},
|
||||
aliases: ["Scopable", "BlockParent", "Block", "Statement"]
|
||||
});
|
||||
|
||||
@ -29,6 +47,10 @@ define("BreakStatement", {
|
||||
|
||||
define("CallExpression", {
|
||||
visitor: ["callee", "arguments"],
|
||||
fields: {
|
||||
callee: { validate: assertNodeType("Expression") },
|
||||
arguments: { validate: assertValueType("array") }
|
||||
},
|
||||
aliases: ["Expression"]
|
||||
});
|
||||
|
||||
@ -39,6 +61,11 @@ define("CatchClause", {
|
||||
|
||||
define("ConditionalExpression", {
|
||||
visitor: ["test", "consequent", "alternate"],
|
||||
fields: {
|
||||
test: { validate: assertNodeType("Expression") },
|
||||
consequent: { validate: assertNodeType("Expression") },
|
||||
alternate: { validate: assertNodeType("Expression") }
|
||||
},
|
||||
aliases: ["Expression"]
|
||||
});
|
||||
|
||||
@ -62,12 +89,18 @@ define("EmptyStatement", {
|
||||
|
||||
define("ExpressionStatement", {
|
||||
visitor: ["expression"],
|
||||
fields: {
|
||||
expression: { validate: assertNodeType("Expression") }
|
||||
},
|
||||
aliases: ["Statement"]
|
||||
});
|
||||
|
||||
define("File", {
|
||||
builder: ["program", "comments", "tokens"],
|
||||
visitor: ["program"]
|
||||
visitor: ["program"],
|
||||
fields: {
|
||||
program: { validate: assertNodeType("Program") }
|
||||
}
|
||||
});
|
||||
|
||||
define("ForInStatement", {
|
||||
@ -81,24 +114,37 @@ define("ForStatement", {
|
||||
});
|
||||
|
||||
define("FunctionDeclaration", {
|
||||
builder: {
|
||||
id: null,
|
||||
params: null,
|
||||
body: null,
|
||||
generator: false,
|
||||
async: false
|
||||
},
|
||||
builder: ["id", "params", "body", "generator", "async"],
|
||||
visitor: ["id", "params", "body", "returnType", "typeParameters"],
|
||||
fields: {
|
||||
id: { validate: assertNodeType("Identifier") },
|
||||
params: { validate: assertValueType("array") },
|
||||
body: { validate: assertNodeType("BlockStatement") },
|
||||
generator: {
|
||||
default: false,
|
||||
validate: assertValueType("boolean")
|
||||
},
|
||||
async: {
|
||||
default: false,
|
||||
validate: assertValueType("boolean")
|
||||
}
|
||||
},
|
||||
aliases: ["Scopable", "Function", "Func", "BlockParent", "FunctionParent", "Statement", "Pure", "Declaration"]
|
||||
});
|
||||
|
||||
define("FunctionExpression", {
|
||||
builder: {
|
||||
id: null,
|
||||
params: null,
|
||||
body: null,
|
||||
generator: false,
|
||||
async: false
|
||||
builder: ["id", "params", "body", "generator", "async"],
|
||||
fields: {
|
||||
params: { validate: assertValueType("array") },
|
||||
body: { validate: assertNodeType("BlockStatement") },
|
||||
generator: {
|
||||
default: false,
|
||||
validate: assertValueType("boolean")
|
||||
},
|
||||
async: {
|
||||
default: false,
|
||||
validate: assertValueType("boolean")
|
||||
}
|
||||
},
|
||||
visitor: ["id", "params", "body", "returnType", "typeParameters"],
|
||||
aliases: ["Scopable", "Function", "Func", "BlockParent", "FunctionParent", "Expression", "Pure"]
|
||||
@ -107,7 +153,7 @@ define("FunctionExpression", {
|
||||
define("Identifier", {
|
||||
builder: ["name"],
|
||||
visitor: ["typeAnnotation"],
|
||||
aliases: ["Expression"]
|
||||
aliases: ["Expression", "LVal"]
|
||||
});
|
||||
|
||||
define("IfStatement", {
|
||||
@ -120,9 +166,44 @@ define("LabeledStatement", {
|
||||
aliases: ["Statement"]
|
||||
});
|
||||
|
||||
define("Literal", {
|
||||
define("StringLiteral", {
|
||||
builder: ["value"],
|
||||
aliases: ["Expression", "Pure"]
|
||||
fields: {
|
||||
value: { validate: assertValueType("string") }
|
||||
},
|
||||
aliases: ["Expression", "Pure", "Literal", "Immutable"]
|
||||
});
|
||||
|
||||
define("NumberLiteral", {
|
||||
builder: ["value"],
|
||||
fields: {
|
||||
value: { validate: assertValueType("number") }
|
||||
},
|
||||
aliases: ["Expression", "Pure", "Literal", "Immutable"]
|
||||
});
|
||||
|
||||
define("NullLiteral", {
|
||||
aliases: ["Expression", "Pure", "Literal", "Immutable"]
|
||||
});
|
||||
|
||||
define("BooleanLiteral", {
|
||||
builder: ["value"],
|
||||
fields: {
|
||||
value: { validate: assertValueType("boolean") }
|
||||
},
|
||||
aliases: ["Expression", "Pure", "Literal", "Immutable"]
|
||||
});
|
||||
|
||||
define("RegexLiteral", {
|
||||
builder: ["pattern", "flags"],
|
||||
fields: {
|
||||
pattern: { validate: assertValueType("string") },
|
||||
flags: {
|
||||
validate: assertValueType("string"),
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
aliases: ["Expression", "Literal"]
|
||||
});
|
||||
|
||||
define("LogicalExpression", {
|
||||
@ -132,13 +213,12 @@ define("LogicalExpression", {
|
||||
});
|
||||
|
||||
define("MemberExpression", {
|
||||
builder: {
|
||||
object: null,
|
||||
property: null,
|
||||
computed: false
|
||||
builder: ["object", "property", "computed"],
|
||||
fields: {
|
||||
computed: { default: false }
|
||||
},
|
||||
visitor: ["object", "property"],
|
||||
aliases: ["Expression"]
|
||||
aliases: ["Expression", "LVal"]
|
||||
});
|
||||
|
||||
define("NewExpression", {
|
||||
@ -153,15 +233,17 @@ define("ObjectExpression", {
|
||||
|
||||
define("Program", {
|
||||
visitor: ["body"],
|
||||
fields: {
|
||||
body: { validate: assertValueType("array") }
|
||||
},
|
||||
aliases: ["Scopable", "BlockParent", "Block", "FunctionParent"]
|
||||
});
|
||||
|
||||
define("Property", {
|
||||
builder: {
|
||||
kind: "init",
|
||||
key: null,
|
||||
value: null,
|
||||
computed: false
|
||||
builder: ["kind", "key", "value", "computed"],
|
||||
fields: {
|
||||
kind: { default: "init" },
|
||||
computed: { default: false }
|
||||
},
|
||||
visitor: ["key", "value", "decorators"],
|
||||
aliases: ["UserWhitespacable"]
|
||||
@ -178,6 +260,9 @@ define("ReturnStatement", {
|
||||
|
||||
define("SequenceExpression", {
|
||||
visitor: ["expressions"],
|
||||
fields: {
|
||||
expressions: { validate: assertValueType("array") }
|
||||
},
|
||||
aliases: ["Expression"]
|
||||
});
|
||||
|
||||
@ -206,20 +291,18 @@ define("TryStatement", {
|
||||
});
|
||||
|
||||
define("UnaryExpression", {
|
||||
builder: {
|
||||
operator: null,
|
||||
argument: null,
|
||||
prefix: false
|
||||
builder: ["operator", "argument", "prefix"],
|
||||
fields: {
|
||||
prefix: { default: false }
|
||||
},
|
||||
visitor: ["argument"],
|
||||
aliases: ["UnaryLike", "Expression"]
|
||||
});
|
||||
|
||||
define("UpdateExpression", {
|
||||
builder: {
|
||||
operator: null,
|
||||
argument: null,
|
||||
prefix: false
|
||||
builder: ["operator", "argument", "prefix"],
|
||||
fields: {
|
||||
prefix: { default: false }
|
||||
},
|
||||
visitor: ["argument"],
|
||||
aliases: ["Expression"]
|
||||
|
||||
@ -2,12 +2,12 @@ import define from "./index";
|
||||
|
||||
define("AssignmentPattern", {
|
||||
visitor: ["left", "right"],
|
||||
aliases: ["Pattern"]
|
||||
aliases: ["Pattern", "LVal"]
|
||||
});
|
||||
|
||||
define("ArrayPattern", {
|
||||
visitor: ["elements", "typeAnnotation"],
|
||||
aliases: ["Pattern"]
|
||||
aliases: ["Pattern", "LVal"]
|
||||
});
|
||||
|
||||
define("ArrowFunctionExpression", {
|
||||
@ -91,19 +91,18 @@ define("MetaProperty", {
|
||||
});
|
||||
|
||||
define("MethodDefinition", {
|
||||
builder: {
|
||||
key: null,
|
||||
value: null,
|
||||
kind: "method",
|
||||
computed: false,
|
||||
static: false
|
||||
builder: ["key", "value", "kind", "computed", "static"],
|
||||
fields: {
|
||||
kind: { default: "method" },
|
||||
computed: { default: false },
|
||||
static: { default: false }
|
||||
},
|
||||
visitor: ["key", "value", "decorators"]
|
||||
});
|
||||
|
||||
define("ObjectPattern", {
|
||||
visitor: ["properties", "typeAnnotation"],
|
||||
aliases: ["Pattern"]
|
||||
aliases: ["Pattern", "LVal"]
|
||||
});
|
||||
|
||||
define("SpreadElement", {
|
||||
@ -124,7 +123,7 @@ define("TemplateElement");
|
||||
|
||||
define("TemplateLiteral", {
|
||||
visitor: ["quasis", "expressions"],
|
||||
aliases: ["Expression"]
|
||||
aliases: ["Expression", "Literal"]
|
||||
});
|
||||
|
||||
define("YieldExpression", {
|
||||
|
||||
@ -1,21 +1,67 @@
|
||||
import * as t from "../index";
|
||||
|
||||
export var VISITOR_KEYS = {};
|
||||
export var ALIAS_KEYS = {};
|
||||
export var NODE_FIELDS = {};
|
||||
export var BUILDER_KEYS = {};
|
||||
|
||||
function builderFromArray(arr) {
|
||||
var builder = {};
|
||||
for (var key of (arr: Array)) builder[key] = null;
|
||||
return builder;
|
||||
export function assertContains(vals) {
|
||||
return function (val, key) {
|
||||
if (vals.indexOf(val) < 0) {
|
||||
throw new TypeError(`Property ${key} with the value of ${val} expected to be one of ${JSON.stringify(vals)}`);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function assertNodeType(...types) {
|
||||
return function (node, key) {
|
||||
var valid = false;
|
||||
|
||||
for (var type of types) {
|
||||
if (t.is(type, node)) {
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
throw new TypeError(`Property ${key} expected node to be of a type ${JSON.stringify(types)} but instead got ${node && node.type}`);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function assertValueType(type) {
|
||||
return function (val, key) {
|
||||
var valid = typeof val === type;
|
||||
if (type === "array" && Array.isArray(val)) valid = true;
|
||||
|
||||
if (!valid) {
|
||||
throw new TypeError(`Property ${key} expected type of ${type} but got ${typeof val}`);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default function define(type, opts = {}) {
|
||||
opts.fields = opts.fields || {};
|
||||
opts.visitor = opts.visitor || [];
|
||||
opts.aliases = opts.aliases || [];
|
||||
opts.builder = opts.builder || opts.visitor || [];
|
||||
|
||||
if (!opts.builder) opts.builder = builderFromArray(opts.visitor);
|
||||
if (Array.isArray(opts.builder)) opts.builder = builderFromArray(opts.builder);
|
||||
// ensure all field keys are represented in `fields`
|
||||
for (let key of (opts.visitor.concat(opts.builder): Array)) {
|
||||
opts.fields[key] = opts.fields[key] || {};
|
||||
}
|
||||
|
||||
for (let key in opts.fields) {
|
||||
var field = opts.fields[key];
|
||||
|
||||
if (field.default === undefined) {
|
||||
field.default = null;
|
||||
}
|
||||
}
|
||||
|
||||
VISITOR_KEYS[type] = opts.visitor;
|
||||
ALIAS_KEYS[type] = opts.aliases;
|
||||
BUILDER_KEYS[type] = opts.builder;
|
||||
NODE_FIELDS[type] = opts.fields;
|
||||
ALIAS_KEYS[type] = opts.aliases;
|
||||
}
|
||||
|
||||
@ -49,8 +49,8 @@ export const NUMBER_UNARY_OPERATORS = ["+", "-", "++", "--", "~"];
|
||||
export const STRING_UNARY_OPERATORS = ["typeof"];
|
||||
|
||||
import "./definitions/init";
|
||||
import { VISITOR_KEYS, BUILDER_KEYS, ALIAS_KEYS } from "./definitions";
|
||||
export { VISITOR_KEYS, BUILDER_KEYS, ALIAS_KEYS };
|
||||
import { VISITOR_KEYS, ALIAS_KEYS, NODE_FIELDS, BUILDER_KEYS } from "./definitions";
|
||||
export { VISITOR_KEYS, ALIAS_KEYS, NODE_FIELDS, BUILDER_KEYS };
|
||||
export * as react from "./react";
|
||||
|
||||
/**
|
||||
@ -127,44 +127,44 @@ export function isType(nodeType: string, targetType: string): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Please add a description.]
|
||||
*/
|
||||
|
||||
each(t.VISITOR_KEYS, function (keys, type) {
|
||||
if (t.BUILDER_KEYS[type]) return;
|
||||
|
||||
var defs = {};
|
||||
each(keys, function (key) {
|
||||
defs[key] = null;
|
||||
});
|
||||
t.BUILDER_KEYS[type] = defs;
|
||||
});
|
||||
|
||||
/**
|
||||
* [Please add a description.]
|
||||
*/
|
||||
|
||||
each(t.BUILDER_KEYS, function (keys, type) {
|
||||
var builder = function () {
|
||||
function builder() {
|
||||
var node = {};
|
||||
node.type = type;
|
||||
|
||||
var i = 0;
|
||||
|
||||
for (var key in keys) {
|
||||
for (var key of (keys: Array)) {
|
||||
var field = t.NODE_FIELDS[type][key];
|
||||
|
||||
var arg = arguments[i++];
|
||||
if (arg === undefined) arg = keys[key];
|
||||
if (arg === undefined) arg = field.default;
|
||||
if (field.validate) field.validate(arg, key);
|
||||
|
||||
node[key] = arg;
|
||||
}
|
||||
|
||||
return node;
|
||||
};
|
||||
}
|
||||
|
||||
t[type] = builder;
|
||||
t[type[0].toLowerCase() + type.slice(1)] = builder;
|
||||
});
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
export function validate(key, parent, node) {
|
||||
var fields = t.NODE_FIELDS[parent.type];
|
||||
if (!fields) return;
|
||||
|
||||
var field = fields[key];
|
||||
if (!field || !field.validate) return;
|
||||
|
||||
field.validate(node, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if an object is shallowly equal.
|
||||
*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user