improve node type definitions to avoid any's in generated types (#11687)

This commit is contained in:
Bogdan Savluk 2020-06-09 00:39:46 +02:00 committed by GitHub
parent 4108524856
commit 36f9798f42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 219 additions and 73 deletions

View File

@ -84,10 +84,13 @@ defineType("BinaryExpression", {
const expression = assertNodeType("Expression");
const inOp = assertNodeType("Expression", "PrivateName");
return function (node, key, val) {
const validator = function (node, key, val) {
const validator = node.operator === "in" ? inOp : expression;
validator(node, key, val);
};
// todo(ts): can be discriminated union by `operator` property
validator.oneOfNodeTypes = ["Expression", "PrivateName"];
return validator;
})(),
},
right: {
@ -276,6 +279,15 @@ defineType("File", {
program: {
validate: assertNodeType("Program"),
},
comments: {
validate: assertEach(assertNodeType("Comment")),
optional: true,
},
tokens: {
// todo(ts): add Token type
validate: assertEach(Object.assign(() => {}, { type: "any" })),
optional: true,
},
},
});
@ -457,13 +469,19 @@ defineType("Identifier", {
fields: {
...patternLikeCommon,
name: {
validate: chain(assertValueType("string"), function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return;
validate: chain(
assertValueType("string"),
Object.assign(
function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return;
if (!isValidIdentifier(val, false)) {
throw new TypeError(`"${val}" is not a valid identifier name`);
}
}),
if (!isValidIdentifier(val, false)) {
throw new TypeError(`"${val}" is not a valid identifier name`);
}
},
{ type: "string" },
),
),
},
optional: {
validate: assertValueType("boolean"),
@ -583,14 +601,20 @@ defineType("RegExpLiteral", {
validate: assertValueType("string"),
},
flags: {
validate: chain(assertValueType("string"), function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return;
validate: chain(
assertValueType("string"),
Object.assign(
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`);
}
}),
const invalid = /[^gimsuy]/.exec(val);
if (invalid) {
throw new TypeError(`"${invalid[0]}" is not a valid RegExp flag`);
}
},
{ type: "string" },
),
),
default: "",
},
},
@ -626,10 +650,13 @@ defineType("MemberExpression", {
const normal = assertNodeType("Identifier", "PrivateName");
const computed = assertNodeType("Expression");
return function (node, key, val) {
const validator = function (node, key, val) {
const validator = node.computed ? computed : normal;
validator(node, key, val);
};
// todo(ts): can be discriminated union by `computed` property
validator.oneOfNodeTypes = ["Expression", "Identifier", "PrivateName"];
return validator;
})(),
},
computed: {
@ -719,10 +746,18 @@ defineType("ObjectMethod", {
);
const computed = assertNodeType("Expression");
return function (node, key, val) {
const validator = function (node, key, val) {
const validator = node.computed ? computed : normal;
validator(node, key, val);
};
// todo(ts): can be discriminated union by `computed` property
validator.oneOfNodeTypes = [
"Expression",
"Identifier",
"StringLiteral",
"NumericLiteral",
];
return validator;
})(),
},
decorators: {
@ -776,10 +811,18 @@ defineType("ObjectProperty", {
);
const computed = assertNodeType("Expression");
return function (node, key, val) {
const validator = function (node, key, val) {
const validator = node.computed ? computed : normal;
validator(node, key, val);
};
// todo(ts): can be discriminated union by `computed` property
validator.oneOfNodeTypes = [
"Expression",
"Identifier",
"StringLiteral",
"NumericLiteral",
];
return validator;
})(),
},
value: {
@ -790,15 +833,18 @@ defineType("ObjectProperty", {
shorthand: {
validate: chain(
assertValueType("boolean"),
function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return;
Object.assign(
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",
);
}
},
if (val && node.computed) {
throw new TypeError(
"Property shorthand of ObjectProperty cannot be true if computed is true",
);
}
},
{ type: "boolean" },
),
function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return;
@ -945,18 +991,26 @@ defineType("TryStatement", {
aliases: ["Statement"],
fields: {
block: {
validate: chain(assertNodeType("BlockStatement"), function (node) {
if (!process.env.BABEL_TYPES_8_BREAKING) return;
validate: chain(
assertNodeType("BlockStatement"),
Object.assign(
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.
// 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",
);
}
}),
if (!node.handler && !node.finalizer) {
throw new TypeError(
"TryStatement expects either a handler or finalizer, or both",
);
}
},
{
oneOfNodeTypes: ["BlockStatement"],
},
),
),
},
handler: {
optional: true,

View File

@ -170,6 +170,10 @@ defineType("ClassExpression", {
),
optional: true,
},
mixins: {
validate: assertNodeType("InterfaceExtends"),
optional: true,
},
},
});
@ -177,6 +181,51 @@ defineType("ClassDeclaration", {
inherits: "ClassExpression",
aliases: ["Scopable", "Class", "Statement", "Declaration"],
fields: {
id: {
validate: assertNodeType("Identifier"),
},
typeParameters: {
validate: assertNodeType(
"TypeParameterDeclaration",
"TSTypeParameterDeclaration",
"Noop",
),
optional: true,
},
body: {
validate: assertNodeType("ClassBody"),
},
superClass: {
optional: true,
validate: assertNodeType("Expression"),
},
superTypeParameters: {
validate: assertNodeType(
"TypeParameterInstantiation",
"TSTypeParameterInstantiation",
),
optional: true,
},
implements: {
validate: chain(
assertValueType("array"),
assertEach(
assertNodeType("TSExpressionWithTypeArguments", "ClassImplements"),
),
),
optional: true,
},
decorators: {
validate: chain(
assertValueType("array"),
assertEach(assertNodeType("Decorator")),
),
optional: true,
},
mixins: {
validate: assertNodeType("InterfaceExtends"),
optional: true,
},
declare: {
validate: assertValueType("boolean"),
optional: true,
@ -247,18 +296,21 @@ defineType("ExportNamedDeclaration", {
optional: true,
validate: chain(
assertNodeType("Declaration"),
function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return;
Object.assign(
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.
// 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",
);
}
},
if (val && node.specifiers.length) {
throw new TypeError(
"Only declaration or specifiers is allowed on ExportNamedDeclaration",
);
}
},
{ oneOfNodeTypes: ["Declaration"] },
),
function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return;
@ -433,25 +485,31 @@ defineType("MetaProperty", {
aliases: ["Expression"],
fields: {
meta: {
validate: chain(assertNodeType("Identifier"), function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return;
validate: chain(
assertNodeType("Identifier"),
Object.assign(
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");
}
}),
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");
}
},
{ oneOfNodeTypes: ["Identifier"] },
),
),
},
property: {
validate: assertNodeType("Identifier"),
@ -665,15 +723,21 @@ defineType("YieldExpression", {
aliases: ["Expression", "Terminatorless"],
fields: {
delegate: {
validate: chain(assertValueType("boolean"), function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return;
validate: chain(
assertValueType("boolean"),
Object.assign(
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",
);
}
}),
if (val && !node.argument) {
throw new TypeError(
"Property delegate of YieldExpression cannot be true if there is no argument",
);
}
},
{ type: "boolean" },
),
),
default: false,
},
argument: {

View File

@ -11,6 +11,7 @@ import {
classMethodOrPropertyCommon,
classMethodOrDeclareMethodCommon,
} from "./es2015";
import { functionTypeAnnotationCommon } from "./core";
defineType("ArgumentPlaceholder", {});
@ -29,7 +30,18 @@ defineType("BindExpression", {
visitor: ["object", "callee"],
aliases: ["Expression"],
fields: !process.env.BABEL_TYPES_8_BREAKING
? {}
? {
object: {
validate: Object.assign(() => {}, {
oneOfNodeTypes: ["Expression"],
}),
},
callee: {
validate: Object.assign(() => {}, {
oneOfNodeTypes: ["Expression"],
}),
},
}
: {
object: {
validate: assertNodeType("Expression"),
@ -96,10 +108,13 @@ defineType("OptionalMemberExpression", {
const normal = assertNodeType("Identifier");
const computed = assertNodeType("Expression");
return function (node, key, val) {
const validator = function (node, key, val) {
const validator = node.computed ? computed : normal;
validator(node, key, val);
};
// todo(ts): can be discriminated union by `computed` property
validator.oneOfNodeTypes = ["Expression", "Identifier"];
return validator;
})(),
},
computed: {
@ -211,6 +226,7 @@ defineType("ClassPrivateMethod", {
],
fields: {
...classMethodOrDeclareMethodCommon,
...functionTypeAnnotationCommon,
key: {
validate: assertNodeType("PrivateName"),
},
@ -226,6 +242,14 @@ defineType("Import", {
defineType("ImportAttribute", {
visitor: ["key", "value"],
fields: {
key: {
validate: assertNodeType("Identifier"),
},
value: {
validate: assertNodeType("StringLiteral"),
},
},
});
defineType("Decorator", {

View File

@ -65,6 +65,10 @@ defineType("JSXElement", {
),
),
},
selfClosing: {
validate: assertValueType("boolean"),
optional: true,
},
},
});