Improve @babel/types with env.BABEL_TYPES_8_BREAKING (#10917)
Co-authored-by: Justin Ridgewell <justin@ridgewell.name>
This commit is contained in:
parent
405c1aaad8
commit
e7b80a2cb9
@ -101,8 +101,12 @@ Object.keys(types.BUILDER_KEYS)
|
||||
}
|
||||
if (defaultValue !== null || types.NODE_FIELDS[key][field].optional) {
|
||||
fieldDescription.push(
|
||||
" (default: `" + util.inspect(defaultValue) + "`)"
|
||||
" (default: `" + util.inspect(defaultValue) + "`"
|
||||
);
|
||||
if (types.BUILDER_KEYS[key].indexOf(field) < 0) {
|
||||
fieldDescription.push(", excluded from builder function");
|
||||
}
|
||||
fieldDescription.push(")");
|
||||
} else {
|
||||
fieldDescription.push(" (required)");
|
||||
}
|
||||
|
||||
@ -224,12 +224,12 @@ export function assertArrowFunctionExpression(
|
||||
export function assertClassBody(node: Object, opts?: Object = {}): void {
|
||||
assert("ClassBody", node, opts);
|
||||
}
|
||||
export function assertClassDeclaration(node: Object, opts?: Object = {}): void {
|
||||
assert("ClassDeclaration", node, opts);
|
||||
}
|
||||
export function assertClassExpression(node: Object, opts?: Object = {}): void {
|
||||
assert("ClassExpression", node, opts);
|
||||
}
|
||||
export function assertClassDeclaration(node: Object, opts?: Object = {}): void {
|
||||
assert("ClassDeclaration", node, opts);
|
||||
}
|
||||
export function assertExportAllDeclaration(
|
||||
node: Object,
|
||||
opts?: Object = {},
|
||||
|
||||
@ -225,14 +225,14 @@ export function ClassBody(...args: Array<any>): Object {
|
||||
return builder("ClassBody", ...args);
|
||||
}
|
||||
export { ClassBody as classBody };
|
||||
export function ClassDeclaration(...args: Array<any>): Object {
|
||||
return builder("ClassDeclaration", ...args);
|
||||
}
|
||||
export { ClassDeclaration as classDeclaration };
|
||||
export function ClassExpression(...args: Array<any>): Object {
|
||||
return builder("ClassExpression", ...args);
|
||||
}
|
||||
export { ClassExpression as classExpression };
|
||||
export function ClassDeclaration(...args: Array<any>): Object {
|
||||
return builder("ClassDeclaration", ...args);
|
||||
}
|
||||
export { ClassDeclaration as classDeclaration };
|
||||
export function ExportAllDeclaration(...args: Array<any>): Object {
|
||||
return builder("ExportAllDeclaration", ...args);
|
||||
}
|
||||
|
||||
@ -41,6 +41,12 @@ export const BINARY_OPERATORS = [
|
||||
...BOOLEAN_BINARY_OPERATORS,
|
||||
];
|
||||
|
||||
export const ASSIGNMENT_OPERATORS = [
|
||||
"=",
|
||||
"+=",
|
||||
...NUMBER_BINARY_OPERATORS.map(op => op + "="),
|
||||
];
|
||||
|
||||
export const BOOLEAN_UNARY_OPERATORS = ["delete", "!"];
|
||||
export const NUMBER_UNARY_OPERATORS = ["+", "-", "~"];
|
||||
export const STRING_UNARY_OPERATORS = ["typeof"];
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
// @flow
|
||||
import isValidIdentifier from "../validators/isValidIdentifier";
|
||||
|
||||
import esutils from "esutils";
|
||||
|
||||
import is from "../validators/is";
|
||||
|
||||
import {
|
||||
BINARY_OPERATORS,
|
||||
LOGICAL_OPERATORS,
|
||||
ASSIGNMENT_OPERATORS,
|
||||
UNARY_OPERATORS,
|
||||
UPDATE_OPERATORS,
|
||||
} from "../constants";
|
||||
@ -26,7 +30,7 @@ defineType("ArrayExpression", {
|
||||
assertNodeOrValueType("null", "Expression", "SpreadElement"),
|
||||
),
|
||||
),
|
||||
default: [],
|
||||
default: !process.env.BABEL_TYPES_8_BREAKING ? [] : undefined,
|
||||
},
|
||||
},
|
||||
visitor: ["elements"],
|
||||
@ -36,10 +40,29 @@ defineType("ArrayExpression", {
|
||||
defineType("AssignmentExpression", {
|
||||
fields: {
|
||||
operator: {
|
||||
validate: assertValueType("string"),
|
||||
validate: (function() {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) {
|
||||
return assertValueType("string");
|
||||
}
|
||||
|
||||
const identifier = assertOneOf(...ASSIGNMENT_OPERATORS);
|
||||
const pattern = assertOneOf("=");
|
||||
|
||||
return function(node, key, val) {
|
||||
const validator = is("Pattern", node.left) ? pattern : identifier;
|
||||
validator(node, key, val);
|
||||
};
|
||||
})(),
|
||||
},
|
||||
left: {
|
||||
validate: assertNodeType("LVal"),
|
||||
validate: !process.env.BABEL_TYPES_8_BREAKING
|
||||
? assertNodeType("LVal")
|
||||
: assertNodeType(
|
||||
"Identifier",
|
||||
"MemberExpression",
|
||||
"ArrayPattern",
|
||||
"ObjectPattern",
|
||||
),
|
||||
},
|
||||
right: {
|
||||
validate: assertNodeType("Expression"),
|
||||
@ -147,10 +170,14 @@ defineType("CallExpression", {
|
||||
),
|
||||
),
|
||||
},
|
||||
...(!process.env.BABEL_TYPES_8_BREAKING
|
||||
? {
|
||||
optional: {
|
||||
validate: assertOneOf(true, false),
|
||||
optional: true,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
typeArguments: {
|
||||
validate: assertNodeType("TypeParameterInstantiation"),
|
||||
optional: true,
|
||||
@ -166,7 +193,7 @@ defineType("CatchClause", {
|
||||
visitor: ["param", "body"],
|
||||
fields: {
|
||||
param: {
|
||||
validate: assertNodeType("Identifier"),
|
||||
validate: assertNodeType("Identifier", "ArrayPattern", "ObjectPattern"),
|
||||
optional: true,
|
||||
},
|
||||
body: {
|
||||
@ -256,7 +283,15 @@ defineType("ForInStatement", {
|
||||
],
|
||||
fields: {
|
||||
left: {
|
||||
validate: assertNodeType("VariableDeclaration", "LVal"),
|
||||
validate: !process.env.BABEL_TYPES_8_BREAKING
|
||||
? assertNodeType("VariableDeclaration", "LVal")
|
||||
: assertNodeType(
|
||||
"VariableDeclaration",
|
||||
"Identifier",
|
||||
"MemberExpression",
|
||||
"ArrayPattern",
|
||||
"ObjectPattern",
|
||||
),
|
||||
},
|
||||
right: {
|
||||
validate: assertNodeType("Expression"),
|
||||
@ -305,10 +340,8 @@ export const functionCommon = {
|
||||
},
|
||||
generator: {
|
||||
default: false,
|
||||
validate: assertValueType("boolean"),
|
||||
},
|
||||
async: {
|
||||
validate: assertValueType("boolean"),
|
||||
default: false,
|
||||
},
|
||||
};
|
||||
@ -359,6 +392,17 @@ defineType("FunctionDeclaration", {
|
||||
"Pureish",
|
||||
"Declaration",
|
||||
],
|
||||
validate: (function() {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return () => {};
|
||||
|
||||
const identifier = assertNodeType("Identifier");
|
||||
|
||||
return function(parent, key, node) {
|
||||
if (!is("ExportDefaultDeclaration", parent)) {
|
||||
identifier(node, "id", node.id);
|
||||
}
|
||||
};
|
||||
})(),
|
||||
});
|
||||
|
||||
defineType("FunctionExpression", {
|
||||
@ -405,17 +449,55 @@ defineType("Identifier", {
|
||||
fields: {
|
||||
...patternLikeCommon,
|
||||
name: {
|
||||
validate: chain(function(node, key, val) {
|
||||
if (!isValidIdentifier(val)) {
|
||||
// throw new TypeError(`"${val}" is not a valid identifier name`);
|
||||
validate: chain(assertValueType("string"), function(node, key, val) {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return;
|
||||
|
||||
if (!esutils.keyword.isIdentifierNameES6(val)) {
|
||||
throw new TypeError(`"${val}" is not a valid identifier name`);
|
||||
}
|
||||
}, assertValueType("string")),
|
||||
}),
|
||||
},
|
||||
optional: {
|
||||
validate: assertValueType("boolean"),
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
validate(parent, key, node) {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return;
|
||||
|
||||
const match = /\.(\w+)$/.exec(key);
|
||||
if (!match) return;
|
||||
|
||||
const [, parentKey] = match;
|
||||
const nonComp = { computed: false };
|
||||
|
||||
// We can't check if `parent.property === node`, because nodes are validated
|
||||
// before replacing them in the AST.
|
||||
if (parentKey === "property") {
|
||||
if (is("MemberExpression", parent, nonComp)) return;
|
||||
if (is("OptionalMemberExpression", parent, nonComp)) return;
|
||||
} else if (parentKey === "key") {
|
||||
if (is("Property", parent, nonComp)) return;
|
||||
if (is("Method", parent, nonComp)) return;
|
||||
} else if (parentKey === "exported") {
|
||||
if (is("ExportSpecifier", parent)) return;
|
||||
} else if (parentKey === "imported") {
|
||||
if (is("ImportSpecifier", parent, { imported: node })) return;
|
||||
} else if (parentKey === "meta") {
|
||||
if (is("MetaProperty", parent, { meta: node })) return;
|
||||
}
|
||||
|
||||
if (
|
||||
// Ideally this should be strict if this node is a descendant of a block
|
||||
// in strict mode. Also, we should disallow "await" in modules.
|
||||
esutils.keyword.isReservedWordES6(node.name, /* strict */ false) &&
|
||||
// Even if "this" is a keyword, we are using the Identifier
|
||||
// node to represent it.
|
||||
node.name !== "this"
|
||||
) {
|
||||
throw new TypeError(`"${node.name}" is not a valid identifer`);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
defineType("IfStatement", {
|
||||
@ -492,7 +574,14 @@ defineType("RegExpLiteral", {
|
||||
validate: assertValueType("string"),
|
||||
},
|
||||
flags: {
|
||||
validate: assertValueType("string"),
|
||||
validate: chain(assertValueType("string"), function(node, key, val) {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return;
|
||||
|
||||
const invalid = /[^gimsuy]/.exec(val);
|
||||
if (invalid) {
|
||||
throw new TypeError(`"${invalid[0]}" is not a valid RegExp flag`);
|
||||
}
|
||||
}),
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
@ -537,10 +626,14 @@ defineType("MemberExpression", {
|
||||
computed: {
|
||||
default: false,
|
||||
},
|
||||
...(!process.env.BABEL_TYPES_8_BREAKING
|
||||
? {
|
||||
optional: {
|
||||
validate: assertOneOf(true, false),
|
||||
optional: true,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
});
|
||||
|
||||
@ -597,19 +690,15 @@ defineType("ObjectExpression", {
|
||||
});
|
||||
|
||||
defineType("ObjectMethod", {
|
||||
builder: ["kind", "key", "params", "body", "computed"],
|
||||
builder: ["kind", "key", "params", "body", "computed", "generator", "async"],
|
||||
fields: {
|
||||
...functionCommon,
|
||||
...functionTypeAnnotationCommon,
|
||||
kind: {
|
||||
validate: chain(
|
||||
assertValueType("string"),
|
||||
assertOneOf("method", "get", "set"),
|
||||
),
|
||||
default: "method",
|
||||
validate: assertOneOf("method", "get", "set"),
|
||||
...(!process.env.BABEL_TYPES_8_BREAKING ? { default: "method" } : {}),
|
||||
},
|
||||
computed: {
|
||||
validate: assertValueType("boolean"),
|
||||
default: false,
|
||||
},
|
||||
key: {
|
||||
@ -632,6 +721,7 @@ defineType("ObjectMethod", {
|
||||
assertValueType("array"),
|
||||
assertEach(assertNodeType("Decorator")),
|
||||
),
|
||||
optional: true,
|
||||
},
|
||||
body: {
|
||||
validate: assertNodeType("BlockStatement"),
|
||||
@ -657,10 +747,15 @@ defineType("ObjectMethod", {
|
||||
});
|
||||
|
||||
defineType("ObjectProperty", {
|
||||
builder: ["key", "value", "computed", "shorthand", "decorators"],
|
||||
builder: [
|
||||
"key",
|
||||
"value",
|
||||
"computed",
|
||||
"shorthand",
|
||||
...(!process.env.BABEL_TYPES_8_BREAKING ? ["decorators"] : []),
|
||||
],
|
||||
fields: {
|
||||
computed: {
|
||||
validate: assertValueType("boolean"),
|
||||
default: false,
|
||||
},
|
||||
key: {
|
||||
@ -684,7 +779,27 @@ defineType("ObjectProperty", {
|
||||
validate: assertNodeType("Expression", "PatternLike"),
|
||||
},
|
||||
shorthand: {
|
||||
validate: assertValueType("boolean"),
|
||||
validate: chain(
|
||||
assertValueType("boolean"),
|
||||
function(node, key, val) {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return;
|
||||
|
||||
if (val && node.computed) {
|
||||
throw new TypeError(
|
||||
"Property shorthand of ObjectProperty cannot be true if computed is true",
|
||||
);
|
||||
}
|
||||
},
|
||||
function(node, key, val) {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return;
|
||||
|
||||
if (val && !is("Identifier", node.key)) {
|
||||
throw new TypeError(
|
||||
"Property shorthand of ObjectProperty cannot be true if key is not an Identifier",
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
default: false,
|
||||
},
|
||||
decorators: {
|
||||
@ -697,6 +812,17 @@ defineType("ObjectProperty", {
|
||||
},
|
||||
visitor: ["key", "value", "decorators"],
|
||||
aliases: ["UserWhitespacable", "Property", "ObjectMember"],
|
||||
validate: (function() {
|
||||
const pattern = assertNodeType("Identifier", "Pattern");
|
||||
const expression = assertNodeType("Expression");
|
||||
|
||||
return function(parent, key, node) {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return;
|
||||
|
||||
const validator = is("ObjectPattern", parent) ? pattern : expression;
|
||||
validator(node, "value", node.value);
|
||||
};
|
||||
})(),
|
||||
});
|
||||
|
||||
defineType("RestElement", {
|
||||
@ -707,9 +833,22 @@ defineType("RestElement", {
|
||||
fields: {
|
||||
...patternLikeCommon,
|
||||
argument: {
|
||||
validate: assertNodeType("LVal"),
|
||||
validate: !process.env.BABEL_TYPES_8_BREAKING
|
||||
? assertNodeType("LVal")
|
||||
: assertNodeType("Identifier", "Pattern", "MemberExpression"),
|
||||
},
|
||||
},
|
||||
validate(parent, key) {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return;
|
||||
|
||||
const match = /(\w+)\[(\d+)\]/.exec(key);
|
||||
if (!match) throw new Error("Internal Babel error: malformed key.");
|
||||
|
||||
const [, listKey, index] = match;
|
||||
if (parent[listKey].length > index + 1) {
|
||||
throw new TypeError(`RestElement must be last element of ${listKey}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
defineType("ReturnStatement", {
|
||||
@ -792,13 +931,23 @@ defineType("ThrowStatement", {
|
||||
},
|
||||
});
|
||||
|
||||
// todo: at least handler or finalizer should be set to be valid
|
||||
defineType("TryStatement", {
|
||||
visitor: ["block", "handler", "finalizer"],
|
||||
aliases: ["Statement"],
|
||||
fields: {
|
||||
block: {
|
||||
validate: assertNodeType("BlockStatement"),
|
||||
validate: chain(assertNodeType("BlockStatement"), function(node) {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return;
|
||||
|
||||
// This validator isn't put at the top level because we can run it
|
||||
// even if this node doesn't have a parent.
|
||||
|
||||
if (!node.handler && !node.finalizer) {
|
||||
throw new TypeError(
|
||||
"TryStatement expects either a handler or finalizer, or both",
|
||||
);
|
||||
}
|
||||
}),
|
||||
},
|
||||
handler: {
|
||||
optional: true,
|
||||
@ -835,7 +984,9 @@ defineType("UpdateExpression", {
|
||||
default: false,
|
||||
},
|
||||
argument: {
|
||||
validate: assertNodeType("Expression"),
|
||||
validate: !process.env.BABEL_TYPES_8_BREAKING
|
||||
? assertNodeType("Expression")
|
||||
: assertNodeType("Identifier", "MemberExpression"),
|
||||
},
|
||||
operator: {
|
||||
validate: assertOneOf(...UPDATE_OPERATORS),
|
||||
@ -855,10 +1006,7 @@ defineType("VariableDeclaration", {
|
||||
optional: true,
|
||||
},
|
||||
kind: {
|
||||
validate: chain(
|
||||
assertValueType("string"),
|
||||
assertOneOf("var", "let", "const"),
|
||||
),
|
||||
validate: assertOneOf("var", "let", "const"),
|
||||
},
|
||||
declarations: {
|
||||
validate: chain(
|
||||
@ -867,13 +1015,39 @@ defineType("VariableDeclaration", {
|
||||
),
|
||||
},
|
||||
},
|
||||
validate(parent, key, node) {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return;
|
||||
|
||||
if (!is("ForXStatement", parent, { left: node })) return;
|
||||
if (node.declarations.length !== 1) {
|
||||
throw new TypeError(
|
||||
`Exactly one VariableDeclarator is required in the VariableDeclaration of a ${parent.type}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
defineType("VariableDeclarator", {
|
||||
visitor: ["id", "init"],
|
||||
fields: {
|
||||
id: {
|
||||
validate: assertNodeType("LVal"),
|
||||
validate: (function() {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) {
|
||||
return assertNodeType("LVal");
|
||||
}
|
||||
|
||||
const normal = assertNodeType(
|
||||
"Identifier",
|
||||
"ArrayPattern",
|
||||
"ObjectPattern",
|
||||
);
|
||||
const without = assertNodeType("Identifier");
|
||||
|
||||
return function(node, key, val) {
|
||||
const validator = node.init ? normal : without;
|
||||
validator(node, key, val);
|
||||
};
|
||||
})(),
|
||||
},
|
||||
definite: {
|
||||
optional: true,
|
||||
@ -894,7 +1068,7 @@ defineType("WhileStatement", {
|
||||
validate: assertNodeType("Expression"),
|
||||
},
|
||||
body: {
|
||||
validate: assertNodeType("BlockStatement", "Statement"),
|
||||
validate: assertNodeType("Statement"),
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -907,7 +1081,7 @@ defineType("WithStatement", {
|
||||
validate: assertNodeType("Expression"),
|
||||
},
|
||||
body: {
|
||||
validate: assertNodeType("BlockStatement", "Statement"),
|
||||
validate: assertNodeType("Statement"),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -3,6 +3,7 @@ import defineType, {
|
||||
assertShape,
|
||||
assertNodeType,
|
||||
assertValueType,
|
||||
assertNodeOrValueType,
|
||||
chain,
|
||||
assertEach,
|
||||
assertOneOf,
|
||||
@ -13,6 +14,7 @@ import {
|
||||
functionTypeAnnotationCommon,
|
||||
patternLikeCommon,
|
||||
} from "./core";
|
||||
import is from "../validators/is";
|
||||
|
||||
defineType("AssignmentPattern", {
|
||||
visitor: ["left", "right", "decorators" /* for legacy param decorators */],
|
||||
@ -31,11 +33,13 @@ defineType("AssignmentPattern", {
|
||||
right: {
|
||||
validate: assertNodeType("Expression"),
|
||||
},
|
||||
// For TypeScript
|
||||
decorators: {
|
||||
validate: chain(
|
||||
assertValueType("array"),
|
||||
assertEach(assertNodeType("Decorator")),
|
||||
),
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -49,14 +53,16 @@ defineType("ArrayPattern", {
|
||||
elements: {
|
||||
validate: chain(
|
||||
assertValueType("array"),
|
||||
assertEach(assertNodeType("PatternLike")),
|
||||
assertEach(assertNodeOrValueType("null", "PatternLike")),
|
||||
),
|
||||
},
|
||||
// For TypeScript
|
||||
decorators: {
|
||||
validate: chain(
|
||||
assertValueType("array"),
|
||||
assertEach(assertNodeType("Decorator")),
|
||||
),
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -106,7 +112,26 @@ defineType("ClassBody", {
|
||||
},
|
||||
});
|
||||
|
||||
const classCommon = {
|
||||
defineType("ClassExpression", {
|
||||
builder: ["id", "superClass", "body", "decorators"],
|
||||
visitor: [
|
||||
"id",
|
||||
"body",
|
||||
"superClass",
|
||||
"mixins",
|
||||
"typeParameters",
|
||||
"superTypeParameters",
|
||||
"implements",
|
||||
"decorators",
|
||||
],
|
||||
aliases: ["Scopable", "Class", "Expression", "Pureish"],
|
||||
fields: {
|
||||
id: {
|
||||
validate: assertNodeType("Identifier"),
|
||||
// In declarations, this is missing if this is the
|
||||
// child of an ExportDefaultDeclaration.
|
||||
optional: true,
|
||||
},
|
||||
typeParameters: {
|
||||
validate: assertNodeType(
|
||||
"TypeParameterDeclaration",
|
||||
@ -138,35 +163,6 @@ const classCommon = {
|
||||
),
|
||||
optional: true,
|
||||
},
|
||||
};
|
||||
|
||||
defineType("ClassDeclaration", {
|
||||
builder: ["id", "superClass", "body", "decorators"],
|
||||
visitor: [
|
||||
"id",
|
||||
"body",
|
||||
"superClass",
|
||||
"mixins",
|
||||
"typeParameters",
|
||||
"superTypeParameters",
|
||||
"implements",
|
||||
"decorators",
|
||||
],
|
||||
aliases: ["Scopable", "Class", "Statement", "Declaration", "Pureish"],
|
||||
fields: {
|
||||
...classCommon,
|
||||
declare: {
|
||||
validate: assertValueType("boolean"),
|
||||
optional: true,
|
||||
},
|
||||
abstract: {
|
||||
validate: assertValueType("boolean"),
|
||||
optional: true,
|
||||
},
|
||||
id: {
|
||||
validate: assertNodeType("Identifier"),
|
||||
optional: true, // Missing if this is the child of an ExportDefaultDeclaration.
|
||||
},
|
||||
decorators: {
|
||||
validate: chain(
|
||||
assertValueType("array"),
|
||||
@ -177,30 +173,30 @@ defineType("ClassDeclaration", {
|
||||
},
|
||||
});
|
||||
|
||||
defineType("ClassExpression", {
|
||||
inherits: "ClassDeclaration",
|
||||
aliases: ["Scopable", "Class", "Expression", "Pureish"],
|
||||
defineType("ClassDeclaration", {
|
||||
inherits: "ClassExpression",
|
||||
aliases: ["Scopable", "Class", "Statement", "Declaration", "Pureish"],
|
||||
fields: {
|
||||
...classCommon,
|
||||
id: {
|
||||
declare: {
|
||||
validate: assertValueType("boolean"),
|
||||
optional: true,
|
||||
validate: assertNodeType("Identifier"),
|
||||
},
|
||||
body: {
|
||||
validate: assertNodeType("ClassBody"),
|
||||
},
|
||||
superClass: {
|
||||
optional: true,
|
||||
validate: assertNodeType("Expression"),
|
||||
},
|
||||
decorators: {
|
||||
validate: chain(
|
||||
assertValueType("array"),
|
||||
assertEach(assertNodeType("Decorator")),
|
||||
),
|
||||
abstract: {
|
||||
validate: assertValueType("boolean"),
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
validate: (function() {
|
||||
const identifier = assertNodeType("Identifier");
|
||||
|
||||
return function(parent, key, node) {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return;
|
||||
|
||||
if (!is("ExportDefaultDeclaration", parent)) {
|
||||
identifier(node, "id", node.id);
|
||||
}
|
||||
};
|
||||
})(),
|
||||
});
|
||||
|
||||
defineType("ExportAllDeclaration", {
|
||||
@ -248,18 +244,53 @@ defineType("ExportNamedDeclaration", {
|
||||
],
|
||||
fields: {
|
||||
declaration: {
|
||||
validate: assertNodeType("Declaration"),
|
||||
optional: true,
|
||||
validate: chain(
|
||||
assertNodeType("Declaration"),
|
||||
function(node, key, val) {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return;
|
||||
|
||||
// This validator isn't put at the top level because we can run it
|
||||
// even if this node doesn't have a parent.
|
||||
|
||||
if (val && node.specifiers.length) {
|
||||
throw new TypeError(
|
||||
"Only declaration or specifiers is allowed on ExportNamedDeclaration",
|
||||
);
|
||||
}
|
||||
},
|
||||
function(node, key, val) {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return;
|
||||
|
||||
// This validator isn't put at the top level because we can run it
|
||||
// even if this node doesn't have a parent.
|
||||
|
||||
if (val && node.source) {
|
||||
throw new TypeError("Cannot export a declaration from a source");
|
||||
}
|
||||
},
|
||||
),
|
||||
},
|
||||
specifiers: {
|
||||
default: [],
|
||||
validate: chain(
|
||||
assertValueType("array"),
|
||||
assertEach(
|
||||
assertNodeType(
|
||||
(function() {
|
||||
const sourced = assertNodeType(
|
||||
"ExportSpecifier",
|
||||
"ExportDefaultSpecifier",
|
||||
"ExportNamespaceSpecifier",
|
||||
),
|
||||
);
|
||||
const sourceless = assertNodeType("ExportSpecifier");
|
||||
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return sourced;
|
||||
|
||||
return function(node, key, val) {
|
||||
const validator = node.source ? sourced : sourceless;
|
||||
validator(node, key, val);
|
||||
};
|
||||
})(),
|
||||
),
|
||||
),
|
||||
},
|
||||
@ -286,6 +317,7 @@ defineType("ExportSpecifier", {
|
||||
|
||||
defineType("ForOfStatement", {
|
||||
visitor: ["left", "right", "body"],
|
||||
builder: ["left", "right", "body", "await"],
|
||||
aliases: [
|
||||
"Scopable",
|
||||
"Statement",
|
||||
@ -296,7 +328,27 @@ defineType("ForOfStatement", {
|
||||
],
|
||||
fields: {
|
||||
left: {
|
||||
validate: assertNodeType("VariableDeclaration", "LVal"),
|
||||
validate: (function() {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) {
|
||||
return assertNodeType("VariableDeclaration", "LVal");
|
||||
}
|
||||
|
||||
const declaration = assertNodeType("VariableDeclaration");
|
||||
const lval = assertNodeType(
|
||||
"Identifier",
|
||||
"MemberExpression",
|
||||
"ArrayPattern",
|
||||
"ObjectPattern",
|
||||
);
|
||||
|
||||
return function(node, key, val) {
|
||||
if (is("VariableDeclaration", val)) {
|
||||
declaration(node, key, val);
|
||||
} else {
|
||||
lval(node, key, val);
|
||||
}
|
||||
};
|
||||
})(),
|
||||
},
|
||||
right: {
|
||||
validate: assertNodeType("Expression"),
|
||||
@ -306,7 +358,6 @@ defineType("ForOfStatement", {
|
||||
},
|
||||
await: {
|
||||
default: false,
|
||||
validate: assertValueType("boolean"),
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -380,9 +431,26 @@ defineType("MetaProperty", {
|
||||
visitor: ["meta", "property"],
|
||||
aliases: ["Expression"],
|
||||
fields: {
|
||||
// todo: limit to new.target
|
||||
meta: {
|
||||
validate: assertNodeType("Identifier"),
|
||||
validate: chain(assertNodeType("Identifier"), function(node, key, val) {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return;
|
||||
|
||||
let property;
|
||||
switch (val.name) {
|
||||
case "function":
|
||||
property = "sent";
|
||||
break;
|
||||
case "new":
|
||||
property = "target";
|
||||
break;
|
||||
case "import":
|
||||
property = "meta";
|
||||
break;
|
||||
}
|
||||
if (!is("Identifier", node.property, { name: property })) {
|
||||
throw new TypeError("Unrecognised MetaProperty");
|
||||
}
|
||||
}),
|
||||
},
|
||||
property: {
|
||||
validate: assertNodeType("Identifier"),
|
||||
@ -396,19 +464,14 @@ export const classMethodOrPropertyCommon = {
|
||||
optional: true,
|
||||
},
|
||||
accessibility: {
|
||||
validate: chain(
|
||||
assertValueType("string"),
|
||||
assertOneOf("public", "private", "protected"),
|
||||
),
|
||||
validate: assertOneOf("public", "private", "protected"),
|
||||
optional: true,
|
||||
},
|
||||
static: {
|
||||
default: false,
|
||||
validate: assertValueType("boolean"),
|
||||
},
|
||||
computed: {
|
||||
default: false,
|
||||
validate: assertValueType("boolean"),
|
||||
},
|
||||
optional: {
|
||||
validate: assertValueType("boolean"),
|
||||
@ -443,10 +506,7 @@ export const classMethodOrDeclareMethodCommon = {
|
||||
...functionCommon,
|
||||
...classMethodOrPropertyCommon,
|
||||
kind: {
|
||||
validate: chain(
|
||||
assertValueType("string"),
|
||||
assertOneOf("get", "set", "method", "constructor"),
|
||||
),
|
||||
validate: assertOneOf("get", "set", "method", "constructor"),
|
||||
default: "method",
|
||||
},
|
||||
access: {
|
||||
@ -467,7 +527,16 @@ export const classMethodOrDeclareMethodCommon = {
|
||||
|
||||
defineType("ClassMethod", {
|
||||
aliases: ["Function", "Scopable", "BlockParent", "FunctionParent", "Method"],
|
||||
builder: ["kind", "key", "params", "body", "computed", "static"],
|
||||
builder: [
|
||||
"kind",
|
||||
"key",
|
||||
"params",
|
||||
"body",
|
||||
"computed",
|
||||
"static",
|
||||
"generator",
|
||||
"async",
|
||||
],
|
||||
visitor: [
|
||||
"key",
|
||||
"params",
|
||||
@ -554,7 +623,6 @@ defineType("TemplateElement", {
|
||||
}),
|
||||
},
|
||||
tail: {
|
||||
validate: assertValueType("boolean"),
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
@ -595,7 +663,15 @@ defineType("YieldExpression", {
|
||||
aliases: ["Expression", "Terminatorless"],
|
||||
fields: {
|
||||
delegate: {
|
||||
validate: assertValueType("boolean"),
|
||||
validate: chain(assertValueType("boolean"), function(node, key, val) {
|
||||
if (!process.env.BABEL_TYPES_8_BREAKING) return;
|
||||
|
||||
if (val && !node.argument) {
|
||||
throw new TypeError(
|
||||
"Property delegate of YieldExpression cannot be true if there is no argument",
|
||||
);
|
||||
}
|
||||
}),
|
||||
default: false,
|
||||
},
|
||||
argument: {
|
||||
|
||||
@ -26,8 +26,15 @@ defineType("AwaitExpression", {
|
||||
defineType("BindExpression", {
|
||||
visitor: ["object", "callee"],
|
||||
aliases: ["Expression"],
|
||||
fields: {
|
||||
// todo
|
||||
fields: !process.env.BABEL_TYPES_8_BREAKING
|
||||
? {}
|
||||
: {
|
||||
object: {
|
||||
validate: assertNodeType("Expression"),
|
||||
},
|
||||
callee: {
|
||||
validate: assertNodeType("Expression"),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -468,7 +468,7 @@ defineType("VoidTypeAnnotation", {
|
||||
|
||||
// Enums
|
||||
defineType("EnumDeclaration", {
|
||||
alises: ["Declaration"],
|
||||
aliases: ["Declaration"],
|
||||
visitor: ["id", "body"],
|
||||
fields: {
|
||||
id: validateType("Identifier"),
|
||||
|
||||
@ -14,6 +14,7 @@ import {
|
||||
NODE_FIELDS,
|
||||
BUILDER_KEYS,
|
||||
DEPRECATED_KEYS,
|
||||
NODE_PARENT_VALIDATIONS,
|
||||
} from "./utils";
|
||||
import {
|
||||
PLACEHOLDERS,
|
||||
@ -43,6 +44,7 @@ export {
|
||||
NODE_FIELDS,
|
||||
BUILDER_KEYS,
|
||||
DEPRECATED_KEYS,
|
||||
NODE_PARENT_VALIDATIONS,
|
||||
PLACEHOLDERS,
|
||||
PLACEHOLDERS_ALIAS,
|
||||
PLACEHOLDERS_FLIPPED_ALIAS,
|
||||
|
||||
@ -142,7 +142,6 @@ defineType("JSXOpeningElement", {
|
||||
},
|
||||
selfClosing: {
|
||||
default: false,
|
||||
validate: assertValueType("boolean"),
|
||||
},
|
||||
attributes: {
|
||||
validate: chain(
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// @flow
|
||||
import is from "../validators/is";
|
||||
import { validateField } from "../validators/validate";
|
||||
import { validateField, validateChild } from "../validators/validate";
|
||||
|
||||
export const VISITOR_KEYS: { [string]: Array<string> } = {};
|
||||
export const ALIAS_KEYS: { [string]: Array<string> } = {};
|
||||
@ -8,14 +8,13 @@ export const FLIPPED_ALIAS_KEYS: { [string]: Array<string> } = {};
|
||||
export const NODE_FIELDS: { [string]: {} } = {};
|
||||
export const BUILDER_KEYS: { [string]: Array<string> } = {};
|
||||
export const DEPRECATED_KEYS: { [string]: string } = {};
|
||||
export const NODE_PARENT_VALIDATIONS = {};
|
||||
|
||||
function getType(val) {
|
||||
if (Array.isArray(val)) {
|
||||
return "array";
|
||||
} else if (val === null) {
|
||||
return "null";
|
||||
} else if (val === undefined) {
|
||||
return "undefined";
|
||||
} else {
|
||||
return typeof val;
|
||||
}
|
||||
@ -71,7 +70,10 @@ export function assertEach(callback: Validator): Validator {
|
||||
if (!Array.isArray(val)) return;
|
||||
|
||||
for (let i = 0; i < val.length; i++) {
|
||||
callback(node, `${key}[${i}]`, val[i]);
|
||||
const subkey = `${key}[${i}]`;
|
||||
const v = val[i];
|
||||
callback(node, subkey, v);
|
||||
if (process.env.BABEL_TYPES_8_BREAKING) validateChild(node, subkey, v);
|
||||
}
|
||||
}
|
||||
validator.each = callback;
|
||||
@ -96,24 +98,21 @@ export function assertOneOf(...values: Array<any>): Validator {
|
||||
|
||||
export function assertNodeType(...types: Array<string>): Validator {
|
||||
function validate(node, key, val) {
|
||||
let valid = false;
|
||||
|
||||
for (const type of types) {
|
||||
if (is(type, val)) {
|
||||
valid = true;
|
||||
break;
|
||||
validateChild(node, key, val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
throw new TypeError(
|
||||
`Property ${key} of ${
|
||||
node.type
|
||||
} expected node to be of a type ${JSON.stringify(types)} ` +
|
||||
`but instead got ${JSON.stringify(val && val.type)}`,
|
||||
} expected node to be of a type ${JSON.stringify(
|
||||
types,
|
||||
)} but instead got ${JSON.stringify(val && val.type)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
validate.oneOfNodeTypes = types;
|
||||
|
||||
@ -122,24 +121,21 @@ export function assertNodeType(...types: Array<string>): Validator {
|
||||
|
||||
export function assertNodeOrValueType(...types: Array<string>): Validator {
|
||||
function validate(node, key, val) {
|
||||
let valid = false;
|
||||
|
||||
for (const type of types) {
|
||||
if (getType(val) === type || is(type, val)) {
|
||||
valid = true;
|
||||
break;
|
||||
validateChild(node, key, val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
throw new TypeError(
|
||||
`Property ${key} of ${
|
||||
node.type
|
||||
} expected node to be of a type ${JSON.stringify(types)} ` +
|
||||
`but instead got ${JSON.stringify(val && val.type)}`,
|
||||
} expected node to be of a type ${JSON.stringify(
|
||||
types,
|
||||
)} but instead got ${JSON.stringify(val && val.type)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
validate.oneOfNodeOrValueTypes = types;
|
||||
|
||||
@ -200,6 +196,17 @@ export function chain(...fns: Array<Validator>): Validator {
|
||||
return validate;
|
||||
}
|
||||
|
||||
const validTypeOpts = [
|
||||
"aliases",
|
||||
"builder",
|
||||
"deprecatedAlias",
|
||||
"fields",
|
||||
"inherits",
|
||||
"visitor",
|
||||
"validate",
|
||||
];
|
||||
const validFieldKeys = ["default", "optional", "validate"];
|
||||
|
||||
export default function defineType(
|
||||
type: string,
|
||||
opts: {
|
||||
@ -211,16 +218,38 @@ export default function defineType(
|
||||
builder?: Array<string>,
|
||||
inherits?: string,
|
||||
deprecatedAlias?: string,
|
||||
validate?: Validator,
|
||||
} = {},
|
||||
) {
|
||||
const inherits = (opts.inherits && store[opts.inherits]) || {};
|
||||
|
||||
const fields: Object = opts.fields || inherits.fields || {};
|
||||
let fields = opts.fields;
|
||||
if (!fields) {
|
||||
fields = {};
|
||||
if (inherits.fields) {
|
||||
const keys = Object.getOwnPropertyNames(inherits.fields);
|
||||
for (const key of (keys: Array<string>)) {
|
||||
const field = inherits.fields[key];
|
||||
fields[key] = {
|
||||
default: field.default,
|
||||
optional: field.optional,
|
||||
validate: field.validate,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const visitor: Array<string> = opts.visitor || inherits.visitor || [];
|
||||
const aliases: Array<string> = opts.aliases || inherits.aliases || [];
|
||||
const builder: Array<string> =
|
||||
opts.builder || inherits.builder || opts.visitor || [];
|
||||
|
||||
for (const k of (Object.keys(opts): Array<string>)) {
|
||||
if (validTypeOpts.indexOf(k) === -1) {
|
||||
throw new Error(`Unknown type option "${k}" on ${type}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.deprecatedAlias) {
|
||||
DEPRECATED_KEYS[opts.deprecatedAlias] = type;
|
||||
}
|
||||
@ -233,14 +262,20 @@ export default function defineType(
|
||||
for (const key of Object.keys(fields)) {
|
||||
const field = fields[key];
|
||||
|
||||
if (builder.indexOf(key) === -1) {
|
||||
if (field.default !== undefined && builder.indexOf(key) === -1) {
|
||||
field.optional = true;
|
||||
}
|
||||
if (field.default === undefined) {
|
||||
field.default = null;
|
||||
} else if (!field.validate) {
|
||||
} else if (!field.validate && field.default != null) {
|
||||
field.validate = assertValueType(getType(field.default));
|
||||
}
|
||||
|
||||
for (const k of (Object.keys(field): Array<string>)) {
|
||||
if (validFieldKeys.indexOf(k) === -1) {
|
||||
throw new Error(`Unknown field key "${k}" on ${type}.${key}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VISITOR_KEYS[type] = opts.visitor = visitor;
|
||||
@ -252,6 +287,10 @@ export default function defineType(
|
||||
FLIPPED_ALIAS_KEYS[alias].push(type);
|
||||
});
|
||||
|
||||
if (opts.validate) {
|
||||
NODE_PARENT_VALIDATIONS[type] = opts.validate;
|
||||
}
|
||||
|
||||
store[type] = opts;
|
||||
}
|
||||
|
||||
|
||||
@ -781,11 +781,11 @@ export function isClassBody(node: ?Object, opts?: Object): boolean {
|
||||
|
||||
return false;
|
||||
}
|
||||
export function isClassDeclaration(node: ?Object, opts?: Object): boolean {
|
||||
export function isClassExpression(node: ?Object, opts?: Object): boolean {
|
||||
if (!node) return false;
|
||||
|
||||
const nodeType = node.type;
|
||||
if (nodeType === "ClassDeclaration") {
|
||||
if (nodeType === "ClassExpression") {
|
||||
if (typeof opts === "undefined") {
|
||||
return true;
|
||||
} else {
|
||||
@ -795,11 +795,11 @@ export function isClassDeclaration(node: ?Object, opts?: Object): boolean {
|
||||
|
||||
return false;
|
||||
}
|
||||
export function isClassExpression(node: ?Object, opts?: Object): boolean {
|
||||
export function isClassDeclaration(node: ?Object, opts?: Object): boolean {
|
||||
if (!node) return false;
|
||||
|
||||
const nodeType = node.type;
|
||||
if (nodeType === "ClassExpression") {
|
||||
if (nodeType === "ClassDeclaration") {
|
||||
if (typeof opts === "undefined") {
|
||||
return true;
|
||||
} else {
|
||||
@ -3499,8 +3499,8 @@ export function isScopable(node: ?Object, opts?: Object): boolean {
|
||||
"SwitchStatement" === nodeType ||
|
||||
"WhileStatement" === nodeType ||
|
||||
"ArrowFunctionExpression" === nodeType ||
|
||||
"ClassDeclaration" === nodeType ||
|
||||
"ClassExpression" === nodeType ||
|
||||
"ClassDeclaration" === nodeType ||
|
||||
"ForOfStatement" === nodeType ||
|
||||
"ClassMethod" === nodeType ||
|
||||
"ClassPrivateMethod" === nodeType ||
|
||||
@ -3847,8 +3847,8 @@ export function isPureish(node: ?Object, opts?: Object): boolean {
|
||||
"NullLiteral" === nodeType ||
|
||||
"BooleanLiteral" === nodeType ||
|
||||
"ArrowFunctionExpression" === nodeType ||
|
||||
"ClassDeclaration" === nodeType ||
|
||||
"ClassExpression" === nodeType ||
|
||||
"ClassDeclaration" === nodeType ||
|
||||
"BigIntLiteral" === nodeType ||
|
||||
(nodeType === "Placeholder" && "StringLiteral" === node.expectedNode)
|
||||
) {
|
||||
@ -3887,6 +3887,7 @@ export function isDeclaration(node: ?Object, opts?: Object): boolean {
|
||||
"InterfaceDeclaration" === nodeType ||
|
||||
"OpaqueType" === nodeType ||
|
||||
"TypeAlias" === nodeType ||
|
||||
"EnumDeclaration" === nodeType ||
|
||||
"TSDeclareFunction" === nodeType ||
|
||||
"TSInterfaceDeclaration" === nodeType ||
|
||||
"TSTypeAliasDeclaration" === nodeType ||
|
||||
@ -4149,8 +4150,8 @@ export function isClass(node: ?Object, opts?: Object): boolean {
|
||||
const nodeType = node.type;
|
||||
if (
|
||||
nodeType === "Class" ||
|
||||
"ClassDeclaration" === nodeType ||
|
||||
"ClassExpression" === nodeType
|
||||
"ClassExpression" === nodeType ||
|
||||
"ClassDeclaration" === nodeType
|
||||
) {
|
||||
if (typeof opts === "undefined") {
|
||||
return true;
|
||||
|
||||
@ -5,16 +5,20 @@ import esutils from "esutils";
|
||||
* Check if the input `name` is a valid identifier name
|
||||
* and isn't a reserved word.
|
||||
*/
|
||||
export default function isValidIdentifier(name: string): boolean {
|
||||
if (
|
||||
typeof name !== "string" ||
|
||||
esutils.keyword.isReservedWordES6(name, true)
|
||||
) {
|
||||
export default function isValidIdentifier(
|
||||
name: string,
|
||||
reserved: boolean = true,
|
||||
): boolean {
|
||||
if (typeof name !== "string") return false;
|
||||
|
||||
if (reserved) {
|
||||
if (esutils.keyword.isReservedWordES6(name, true)) {
|
||||
return false;
|
||||
} else if (name === "await") {
|
||||
// invalid in module, valid in script; better be safe (see #4952)
|
||||
return false;
|
||||
} else {
|
||||
return esutils.keyword.isIdentifierNameES6(name);
|
||||
}
|
||||
}
|
||||
|
||||
return esutils.keyword.isIdentifierNameES6(name);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// @flow
|
||||
import { NODE_FIELDS } from "../definitions";
|
||||
import { NODE_FIELDS, NODE_PARENT_VALIDATIONS } from "../definitions";
|
||||
|
||||
export default function validate(node?: Object, key: string, val: any): void {
|
||||
if (!node) return;
|
||||
@ -9,6 +9,7 @@ export default function validate(node?: Object, key: string, val: any): void {
|
||||
|
||||
const field = fields[key];
|
||||
validateField(node, key, val, field);
|
||||
validateChild(node, key, val);
|
||||
}
|
||||
|
||||
export function validateField(
|
||||
@ -22,3 +23,10 @@ export function validateField(
|
||||
|
||||
field.validate(node, key, val);
|
||||
}
|
||||
|
||||
export function validateChild(node?: Object, key: string, val?: Object) {
|
||||
if (val == null) return;
|
||||
const validate = NODE_PARENT_VALIDATIONS[val.type];
|
||||
if (!validate) return;
|
||||
validate(node, key, val);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user