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 expression = assertNodeType("Expression");
const inOp = assertNodeType("Expression", "PrivateName"); const inOp = assertNodeType("Expression", "PrivateName");
return function (node, key, val) { const validator = function (node, key, val) {
const validator = node.operator === "in" ? inOp : expression; const validator = node.operator === "in" ? inOp : expression;
validator(node, key, val); validator(node, key, val);
}; };
// todo(ts): can be discriminated union by `operator` property
validator.oneOfNodeTypes = ["Expression", "PrivateName"];
return validator;
})(), })(),
}, },
right: { right: {
@ -276,6 +279,15 @@ defineType("File", {
program: { program: {
validate: assertNodeType("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: { fields: {
...patternLikeCommon, ...patternLikeCommon,
name: { name: {
validate: chain(assertValueType("string"), function (node, key, val) { validate: chain(
assertValueType("string"),
Object.assign(
function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return; if (!process.env.BABEL_TYPES_8_BREAKING) return;
if (!isValidIdentifier(val, false)) { if (!isValidIdentifier(val, false)) {
throw new TypeError(`"${val}" is not a valid identifier name`); throw new TypeError(`"${val}" is not a valid identifier name`);
} }
}), },
{ type: "string" },
),
),
}, },
optional: { optional: {
validate: assertValueType("boolean"), validate: assertValueType("boolean"),
@ -583,14 +601,20 @@ defineType("RegExpLiteral", {
validate: assertValueType("string"), validate: assertValueType("string"),
}, },
flags: { flags: {
validate: chain(assertValueType("string"), function (node, key, val) { validate: chain(
assertValueType("string"),
Object.assign(
function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return; if (!process.env.BABEL_TYPES_8_BREAKING) return;
const invalid = /[^gimsuy]/.exec(val); const invalid = /[^gimsuy]/.exec(val);
if (invalid) { if (invalid) {
throw new TypeError(`"${invalid[0]}" is not a valid RegExp flag`); throw new TypeError(`"${invalid[0]}" is not a valid RegExp flag`);
} }
}), },
{ type: "string" },
),
),
default: "", default: "",
}, },
}, },
@ -626,10 +650,13 @@ defineType("MemberExpression", {
const normal = assertNodeType("Identifier", "PrivateName"); const normal = assertNodeType("Identifier", "PrivateName");
const computed = assertNodeType("Expression"); const computed = assertNodeType("Expression");
return function (node, key, val) { const validator = function (node, key, val) {
const validator = node.computed ? computed : normal; const validator = node.computed ? computed : normal;
validator(node, key, val); validator(node, key, val);
}; };
// todo(ts): can be discriminated union by `computed` property
validator.oneOfNodeTypes = ["Expression", "Identifier", "PrivateName"];
return validator;
})(), })(),
}, },
computed: { computed: {
@ -719,10 +746,18 @@ defineType("ObjectMethod", {
); );
const computed = assertNodeType("Expression"); const computed = assertNodeType("Expression");
return function (node, key, val) { const validator = function (node, key, val) {
const validator = node.computed ? computed : normal; const validator = node.computed ? computed : normal;
validator(node, key, val); validator(node, key, val);
}; };
// todo(ts): can be discriminated union by `computed` property
validator.oneOfNodeTypes = [
"Expression",
"Identifier",
"StringLiteral",
"NumericLiteral",
];
return validator;
})(), })(),
}, },
decorators: { decorators: {
@ -776,10 +811,18 @@ defineType("ObjectProperty", {
); );
const computed = assertNodeType("Expression"); const computed = assertNodeType("Expression");
return function (node, key, val) { const validator = function (node, key, val) {
const validator = node.computed ? computed : normal; const validator = node.computed ? computed : normal;
validator(node, key, val); validator(node, key, val);
}; };
// todo(ts): can be discriminated union by `computed` property
validator.oneOfNodeTypes = [
"Expression",
"Identifier",
"StringLiteral",
"NumericLiteral",
];
return validator;
})(), })(),
}, },
value: { value: {
@ -790,6 +833,7 @@ defineType("ObjectProperty", {
shorthand: { shorthand: {
validate: chain( validate: chain(
assertValueType("boolean"), assertValueType("boolean"),
Object.assign(
function (node, key, val) { function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return; if (!process.env.BABEL_TYPES_8_BREAKING) return;
@ -799,6 +843,8 @@ defineType("ObjectProperty", {
); );
} }
}, },
{ type: "boolean" },
),
function (node, key, val) { function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return; if (!process.env.BABEL_TYPES_8_BREAKING) return;
@ -945,7 +991,10 @@ defineType("TryStatement", {
aliases: ["Statement"], aliases: ["Statement"],
fields: { fields: {
block: { block: {
validate: chain(assertNodeType("BlockStatement"), function (node) { validate: chain(
assertNodeType("BlockStatement"),
Object.assign(
function (node) {
if (!process.env.BABEL_TYPES_8_BREAKING) return; if (!process.env.BABEL_TYPES_8_BREAKING) return;
// This validator isn't put at the top level because we can run it // This validator isn't put at the top level because we can run it
@ -956,7 +1005,12 @@ defineType("TryStatement", {
"TryStatement expects either a handler or finalizer, or both", "TryStatement expects either a handler or finalizer, or both",
); );
} }
}), },
{
oneOfNodeTypes: ["BlockStatement"],
},
),
),
}, },
handler: { handler: {
optional: true, optional: true,

View File

@ -170,6 +170,10 @@ defineType("ClassExpression", {
), ),
optional: true, optional: true,
}, },
mixins: {
validate: assertNodeType("InterfaceExtends"),
optional: true,
},
}, },
}); });
@ -177,6 +181,51 @@ defineType("ClassDeclaration", {
inherits: "ClassExpression", inherits: "ClassExpression",
aliases: ["Scopable", "Class", "Statement", "Declaration"], aliases: ["Scopable", "Class", "Statement", "Declaration"],
fields: { 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: { declare: {
validate: assertValueType("boolean"), validate: assertValueType("boolean"),
optional: true, optional: true,
@ -247,6 +296,7 @@ defineType("ExportNamedDeclaration", {
optional: true, optional: true,
validate: chain( validate: chain(
assertNodeType("Declaration"), assertNodeType("Declaration"),
Object.assign(
function (node, key, val) { function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return; if (!process.env.BABEL_TYPES_8_BREAKING) return;
@ -259,6 +309,8 @@ defineType("ExportNamedDeclaration", {
); );
} }
}, },
{ oneOfNodeTypes: ["Declaration"] },
),
function (node, key, val) { function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return; if (!process.env.BABEL_TYPES_8_BREAKING) return;
@ -433,7 +485,10 @@ defineType("MetaProperty", {
aliases: ["Expression"], aliases: ["Expression"],
fields: { fields: {
meta: { meta: {
validate: chain(assertNodeType("Identifier"), function (node, key, val) { validate: chain(
assertNodeType("Identifier"),
Object.assign(
function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return; if (!process.env.BABEL_TYPES_8_BREAKING) return;
let property; let property;
@ -451,7 +506,10 @@ defineType("MetaProperty", {
if (!is("Identifier", node.property, { name: property })) { if (!is("Identifier", node.property, { name: property })) {
throw new TypeError("Unrecognised MetaProperty"); throw new TypeError("Unrecognised MetaProperty");
} }
}), },
{ oneOfNodeTypes: ["Identifier"] },
),
),
}, },
property: { property: {
validate: assertNodeType("Identifier"), validate: assertNodeType("Identifier"),
@ -665,7 +723,10 @@ defineType("YieldExpression", {
aliases: ["Expression", "Terminatorless"], aliases: ["Expression", "Terminatorless"],
fields: { fields: {
delegate: { delegate: {
validate: chain(assertValueType("boolean"), function (node, key, val) { validate: chain(
assertValueType("boolean"),
Object.assign(
function (node, key, val) {
if (!process.env.BABEL_TYPES_8_BREAKING) return; if (!process.env.BABEL_TYPES_8_BREAKING) return;
if (val && !node.argument) { if (val && !node.argument) {
@ -673,7 +734,10 @@ defineType("YieldExpression", {
"Property delegate of YieldExpression cannot be true if there is no argument", "Property delegate of YieldExpression cannot be true if there is no argument",
); );
} }
}), },
{ type: "boolean" },
),
),
default: false, default: false,
}, },
argument: { argument: {

View File

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

View File

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