add 12 missing NODE_FIELDS (#13577)

* test: add fields test

* fix(babel-types): add missing NODE_FIELDS and tests

fix #13558
fix #13563

* chore: avoid using fs-extra

* chore: code cleanup

* chore: avoid util.promisify

* fix: remove bad ts-expect-error suppressions
This commit is contained in:
Andy Edwards 2021-07-23 08:36:08 -05:00 committed by GitHub
parent 844baebd26
commit 1d48bb0d8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 177 additions and 4 deletions

View File

@ -548,12 +548,10 @@ export function OpaqueType(
this.print(node.supertype, node); this.print(node.supertype, node);
} }
// @ts-expect-error todo(flow->ts) `.impltype` does not exist on t.DeclareOpaqueType
if (node.impltype) { if (node.impltype) {
this.space(); this.space();
this.token("="); this.token("=");
this.space(); this.space();
// @ts-expect-error todo(flow->ts) `.impltype` does not exist on t.DeclareOpaqueType
this.print(node.impltype, node); this.print(node.impltype, node);
} }
this.semicolon(); this.semicolon();

View File

@ -116,7 +116,6 @@ export const Flow = {
} else if (t.isImportDeclaration(node)) { } else if (t.isImportDeclaration(node)) {
return node.importKind === "type" || node.importKind === "typeof"; return node.importKind === "type" || node.importKind === "typeof";
} else if (t.isExportDeclaration(node)) { } else if (t.isExportDeclaration(node)) {
// @ts-expect-error todo(flow->ts) `exportKind` does not exist on ExportAllDeclaration
return node.exportKind === "type"; return node.exportKind === "type";
} else if (t.isImportSpecifier(node)) { } else if (t.isImportSpecifier(node)) {
return node.importKind === "type" || node.importKind === "typeof"; return node.importKind === "type" || node.importKind === "typeof";

View File

@ -30,7 +30,8 @@
"devDependencies": { "devDependencies": {
"@babel/generator": "workspace:*", "@babel/generator": "workspace:*",
"@babel/parser": "workspace:*", "@babel/parser": "workspace:*",
"chalk": "^4.1.0" "chalk": "^4.1.0",
"glob": "^7.1.7"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"

View File

@ -643,6 +643,7 @@ export interface RestElement extends BaseNode {
type: "RestElement"; type: "RestElement";
argument: LVal; argument: LVal;
decorators?: Array<Decorator> | null; decorators?: Array<Decorator> | null;
optional?: boolean | null;
typeAnnotation?: TypeAnnotation | TSTypeAnnotation | Noop | null; typeAnnotation?: TypeAnnotation | TSTypeAnnotation | Noop | null;
} }
@ -653,6 +654,7 @@ export interface RestProperty extends BaseNode {
type: "RestProperty"; type: "RestProperty";
argument: LVal; argument: LVal;
decorators?: Array<Decorator> | null; decorators?: Array<Decorator> | null;
optional?: boolean | null;
typeAnnotation?: TypeAnnotation | TSTypeAnnotation | Noop | null; typeAnnotation?: TypeAnnotation | TSTypeAnnotation | Noop | null;
} }
@ -751,6 +753,7 @@ export interface ArrayPattern extends BaseNode {
type: "ArrayPattern"; type: "ArrayPattern";
elements: Array<null | PatternLike>; elements: Array<null | PatternLike>;
decorators?: Array<Decorator> | null; decorators?: Array<Decorator> | null;
optional?: boolean | null;
typeAnnotation?: TypeAnnotation | TSTypeAnnotation | Noop | null; typeAnnotation?: TypeAnnotation | TSTypeAnnotation | Noop | null;
} }
@ -835,6 +838,7 @@ export interface ExportDefaultDeclaration extends BaseNode {
| TSDeclareFunction | TSDeclareFunction
| ClassDeclaration | ClassDeclaration
| Expression; | Expression;
exportKind?: "value" | null;
} }
export interface ExportNamedDeclaration extends BaseNode { export interface ExportNamedDeclaration extends BaseNode {
@ -1024,6 +1028,7 @@ export interface ClassProperty extends BaseNode {
optional?: boolean | null; optional?: boolean | null;
override?: boolean; override?: boolean;
readonly?: boolean | null; readonly?: boolean | null;
variance?: Variance | null;
} }
export interface ClassPrivateProperty extends BaseNode { export interface ClassPrivateProperty extends BaseNode {
@ -1032,7 +1037,10 @@ export interface ClassPrivateProperty extends BaseNode {
value?: Expression | null; value?: Expression | null;
decorators?: Array<Decorator> | null; decorators?: Array<Decorator> | null;
static: any; static: any;
definite?: boolean | null;
readonly?: boolean | null;
typeAnnotation?: TypeAnnotation | TSTypeAnnotation | Noop | null; typeAnnotation?: TypeAnnotation | TSTypeAnnotation | Noop | null;
variance?: Variance | null;
} }
export interface ClassPrivateMethod extends BaseNode { export interface ClassPrivateMethod extends BaseNode {
@ -1142,6 +1150,7 @@ export interface DeclareOpaqueType extends BaseNode {
id: Identifier; id: Identifier;
typeParameters?: TypeParameterDeclaration | null; typeParameters?: TypeParameterDeclaration | null;
supertype?: FlowType | null; supertype?: FlowType | null;
impltype?: FlowType | null;
} }
export interface DeclareVariable extends BaseNode { export interface DeclareVariable extends BaseNode {
@ -1651,6 +1660,8 @@ export interface TSParameterProperty extends BaseNode {
type: "TSParameterProperty"; type: "TSParameterProperty";
parameter: Identifier | AssignmentPattern; parameter: Identifier | AssignmentPattern;
accessibility?: "public" | "private" | "protected" | null; accessibility?: "public" | "private" | "protected" | null;
decorators?: Array<Decorator> | null;
override?: boolean | null;
readonly?: boolean | null; readonly?: boolean | null;
} }
@ -1710,6 +1721,7 @@ export interface TSPropertySignature extends BaseNode {
typeAnnotation?: TSTypeAnnotation | null; typeAnnotation?: TSTypeAnnotation | null;
initializer?: Expression | null; initializer?: Expression | null;
computed?: boolean | null; computed?: boolean | null;
kind: "get" | "set";
optional?: boolean | null; optional?: boolean | null;
readonly?: boolean | null; readonly?: boolean | null;
} }
@ -1992,6 +2004,7 @@ export interface TSImportEqualsDeclaration extends BaseNode {
type: "TSImportEqualsDeclaration"; type: "TSImportEqualsDeclaration";
id: Identifier; id: Identifier;
moduleReference: TSEntityName | TSExternalModuleReference; moduleReference: TSEntityName | TSExternalModuleReference;
importKind?: "type" | "value" | null;
isExport: boolean; isExport: boolean;
} }

View File

@ -900,6 +900,11 @@ defineType("RestElement", {
? assertNodeType("LVal") ? assertNodeType("LVal")
: assertNodeType("Identifier", "Pattern", "MemberExpression"), : assertNodeType("Identifier", "Pattern", "MemberExpression"),
}, },
// For Flow
optional: {
validate: assertValueType("boolean"),
optional: true,
},
}, },
validate(parent, key) { validate(parent, key) {
if (!process.env.BABEL_TYPES_8_BREAKING) return; if (!process.env.BABEL_TYPES_8_BREAKING) return;
@ -1206,6 +1211,10 @@ defineType("ArrayPattern", {
), ),
optional: true, optional: true,
}, },
optional: {
validate: assertValueType("boolean"),
optional: true,
},
}, },
}); });
@ -1440,6 +1449,7 @@ defineType("ExportDefaultDeclaration", {
"Expression", "Expression",
), ),
}, },
exportKind: validateOptional(assertOneOf("value")),
}, },
}); });
@ -2095,6 +2105,10 @@ defineType("ClassProperty", {
validate: assertValueType("boolean"), validate: assertValueType("boolean"),
optional: true, optional: true,
}, },
variance: {
validate: assertNodeType("Variance"),
optional: true,
},
}, },
}); });
@ -2123,6 +2137,18 @@ defineType("ClassPrivateProperty", {
), ),
optional: true, optional: true,
}, },
readonly: {
validate: assertValueType("boolean"),
optional: true,
},
definite: {
validate: assertValueType("boolean"),
optional: true,
},
variance: {
validate: assertNodeType("Variance"),
optional: true,
},
}, },
}); });

View File

@ -121,6 +121,7 @@ defineType("DeclareOpaqueType", {
id: validateType("Identifier"), id: validateType("Identifier"),
typeParameters: validateOptionalType("TypeParameterDeclaration"), typeParameters: validateOptionalType("TypeParameterDeclaration"),
supertype: validateOptionalType("FlowType"), supertype: validateOptionalType("FlowType"),
impltype: validateOptionalType("FlowType"),
}, },
}); });

View File

@ -49,6 +49,17 @@ defineType("TSParameterProperty", {
parameter: { parameter: {
validate: assertNodeType("Identifier", "AssignmentPattern"), validate: assertNodeType("Identifier", "AssignmentPattern"),
}, },
override: {
validate: assertValueType("boolean"),
optional: true,
},
decorators: {
validate: chain(
assertValueType("array"),
assertEach(assertNodeType("Decorator")),
),
optional: true,
},
}, },
}); });
@ -110,6 +121,9 @@ defineType("TSPropertySignature", {
readonly: validateOptional(bool), readonly: validateOptional(bool),
typeAnnotation: validateOptionalType("TSTypeAnnotation"), typeAnnotation: validateOptionalType("TSTypeAnnotation"),
initializer: validateOptionalType("Expression"), initializer: validateOptionalType("Expression"),
kind: {
validate: assertOneOf("get", "set"),
},
}, },
}); });
@ -494,6 +508,10 @@ defineType("TSImportEqualsDeclaration", {
"TSEntityName", "TSEntityName",
"TSExternalModuleReference", "TSExternalModuleReference",
]), ]),
importKind: {
validate: assertOneOf("type", "value"),
optional: true,
},
}, },
}); });

View File

@ -0,0 +1,116 @@
import * as t from "../lib";
import glob from "glob";
import path from "path";
import fs from "fs";
import { inspect } from "util";
// eslint-disable-next-line no-restricted-globals
const packages = path.resolve(__dirname, "..", "..");
function readJson(file) {
return new Promise((resolve, reject) => {
fs.readFile(file, "utf8", (err, data) => {
if (err) reject(err);
else resolve(JSON.parse(data));
});
});
}
function traverse(thing, visitor) {
if (Array.isArray(thing)) {
thing.forEach(elem => traverse(elem, visitor));
} else if (thing instanceof Object && typeof thing.type === "string") {
visitor(thing);
for (const key in thing) {
const value = thing[key];
if (value instanceof Object) traverse(value, visitor);
}
}
}
const files = glob.sync(
path.join("babel-parser", "test", "**", "output.json"),
{
cwd: packages,
ignore: [
path.join("**", "estree*", "**"),
path.join("**", "is-expression-babel-parser", "**"),
],
},
);
const ignoredFields = {
ArrowFunctionExpression: { id: true, predicate: true },
ClassMethod: { id: true, predicate: true },
ClassPrivateMethod: { id: true, predicate: true },
ClassPrivateProperty: { declare: true, optional: true },
FunctionDeclaration: { predicate: true },
FunctionExpression: { predicate: true },
ImportDeclaration: { attributes: true },
ObjectProperty: { method: true },
ObjectMethod: { method: true, id: true, predicate: true },
StaticBlock: { static: true },
TSDeclareMethod: { id: true },
};
function isEmpty(obj) {
for (const key in obj) return false;
return true;
}
describe("NODE_FIELDS contains all fields in", function () {
files.forEach(file =>
it(`${file}`, async function () {
const ast = await readJson(path.resolve(packages, file));
if (ast.type === "File" && ast.errors && ast.errors.length) return;
t[`assert${ast.type}`](ast);
const missingFields = {};
traverse(ast, node => {
const { type } = node;
switch (type) {
case "File":
case "CommentBlock":
case "CommentLine":
return;
}
if (ignoredFields[type] === true) return;
const fields = t.NODE_FIELDS[type];
if (!fields) {
if (!missingFields[type]) {
missingFields[type] = {
MISSING_TYPE: true,
};
}
return;
}
for (const field in node) {
switch (field) {
case "type":
case "start":
case "end":
case "loc":
case "range":
case "leadingComments":
case "innerComments":
case "trailingComments":
case "comments":
case "extra":
continue;
}
if (!fields[field]) {
if (ignoredFields[type] && ignoredFields[type][field]) continue;
if (!missingFields[type]) missingFields[type] = {};
if (!missingFields[type][field]) {
missingFields[type][field] = true;
}
}
}
});
if (!isEmpty(missingFields)) {
throw new Error(
`the following NODE_FIELDS were missing: ${inspect(missingFields)}`,
);
}
}),
);
});

View File

@ -3606,6 +3606,7 @@ __metadata:
"@babel/helper-validator-identifier": "workspace:^7.14.8" "@babel/helper-validator-identifier": "workspace:^7.14.8"
"@babel/parser": "workspace:*" "@babel/parser": "workspace:*"
chalk: ^4.1.0 chalk: ^4.1.0
glob: ^7.1.7
to-fast-properties: ^2.0.0 to-fast-properties: ^2.0.0
languageName: unknown languageName: unknown
linkType: soft linkType: soft