diff --git a/packages/babel-generator/src/generators/flow.ts b/packages/babel-generator/src/generators/flow.ts index 909f408703..55832c8915 100644 --- a/packages/babel-generator/src/generators/flow.ts +++ b/packages/babel-generator/src/generators/flow.ts @@ -548,12 +548,10 @@ export function OpaqueType( this.print(node.supertype, node); } - // @ts-expect-error todo(flow->ts) `.impltype` does not exist on t.DeclareOpaqueType if (node.impltype) { this.space(); this.token("="); this.space(); - // @ts-expect-error todo(flow->ts) `.impltype` does not exist on t.DeclareOpaqueType this.print(node.impltype, node); } this.semicolon(); diff --git a/packages/babel-traverse/src/path/lib/virtual-types.ts b/packages/babel-traverse/src/path/lib/virtual-types.ts index 9ce9ec73d1..51566d8e95 100644 --- a/packages/babel-traverse/src/path/lib/virtual-types.ts +++ b/packages/babel-traverse/src/path/lib/virtual-types.ts @@ -116,7 +116,6 @@ export const Flow = { } else if (t.isImportDeclaration(node)) { return node.importKind === "type" || node.importKind === "typeof"; } else if (t.isExportDeclaration(node)) { - // @ts-expect-error todo(flow->ts) `exportKind` does not exist on ExportAllDeclaration return node.exportKind === "type"; } else if (t.isImportSpecifier(node)) { return node.importKind === "type" || node.importKind === "typeof"; diff --git a/packages/babel-types/package.json b/packages/babel-types/package.json index fdb842e7ff..49824bb258 100644 --- a/packages/babel-types/package.json +++ b/packages/babel-types/package.json @@ -30,7 +30,8 @@ "devDependencies": { "@babel/generator": "workspace:*", "@babel/parser": "workspace:*", - "chalk": "^4.1.0" + "chalk": "^4.1.0", + "glob": "^7.1.7" }, "engines": { "node": ">=6.9.0" diff --git a/packages/babel-types/src/ast-types/generated/index.ts b/packages/babel-types/src/ast-types/generated/index.ts index 531a113769..5375ac186e 100755 --- a/packages/babel-types/src/ast-types/generated/index.ts +++ b/packages/babel-types/src/ast-types/generated/index.ts @@ -643,6 +643,7 @@ export interface RestElement extends BaseNode { type: "RestElement"; argument: LVal; decorators?: Array | null; + optional?: boolean | null; typeAnnotation?: TypeAnnotation | TSTypeAnnotation | Noop | null; } @@ -653,6 +654,7 @@ export interface RestProperty extends BaseNode { type: "RestProperty"; argument: LVal; decorators?: Array | null; + optional?: boolean | null; typeAnnotation?: TypeAnnotation | TSTypeAnnotation | Noop | null; } @@ -751,6 +753,7 @@ export interface ArrayPattern extends BaseNode { type: "ArrayPattern"; elements: Array; decorators?: Array | null; + optional?: boolean | null; typeAnnotation?: TypeAnnotation | TSTypeAnnotation | Noop | null; } @@ -835,6 +838,7 @@ export interface ExportDefaultDeclaration extends BaseNode { | TSDeclareFunction | ClassDeclaration | Expression; + exportKind?: "value" | null; } export interface ExportNamedDeclaration extends BaseNode { @@ -1024,6 +1028,7 @@ export interface ClassProperty extends BaseNode { optional?: boolean | null; override?: boolean; readonly?: boolean | null; + variance?: Variance | null; } export interface ClassPrivateProperty extends BaseNode { @@ -1032,7 +1037,10 @@ export interface ClassPrivateProperty extends BaseNode { value?: Expression | null; decorators?: Array | null; static: any; + definite?: boolean | null; + readonly?: boolean | null; typeAnnotation?: TypeAnnotation | TSTypeAnnotation | Noop | null; + variance?: Variance | null; } export interface ClassPrivateMethod extends BaseNode { @@ -1142,6 +1150,7 @@ export interface DeclareOpaqueType extends BaseNode { id: Identifier; typeParameters?: TypeParameterDeclaration | null; supertype?: FlowType | null; + impltype?: FlowType | null; } export interface DeclareVariable extends BaseNode { @@ -1651,6 +1660,8 @@ export interface TSParameterProperty extends BaseNode { type: "TSParameterProperty"; parameter: Identifier | AssignmentPattern; accessibility?: "public" | "private" | "protected" | null; + decorators?: Array | null; + override?: boolean | null; readonly?: boolean | null; } @@ -1710,6 +1721,7 @@ export interface TSPropertySignature extends BaseNode { typeAnnotation?: TSTypeAnnotation | null; initializer?: Expression | null; computed?: boolean | null; + kind: "get" | "set"; optional?: boolean | null; readonly?: boolean | null; } @@ -1992,6 +2004,7 @@ export interface TSImportEqualsDeclaration extends BaseNode { type: "TSImportEqualsDeclaration"; id: Identifier; moduleReference: TSEntityName | TSExternalModuleReference; + importKind?: "type" | "value" | null; isExport: boolean; } diff --git a/packages/babel-types/src/definitions/core.ts b/packages/babel-types/src/definitions/core.ts index 5cc742a161..6e275614e2 100644 --- a/packages/babel-types/src/definitions/core.ts +++ b/packages/babel-types/src/definitions/core.ts @@ -900,6 +900,11 @@ defineType("RestElement", { ? assertNodeType("LVal") : assertNodeType("Identifier", "Pattern", "MemberExpression"), }, + // For Flow + optional: { + validate: assertValueType("boolean"), + optional: true, + }, }, validate(parent, key) { if (!process.env.BABEL_TYPES_8_BREAKING) return; @@ -1206,6 +1211,10 @@ defineType("ArrayPattern", { ), optional: true, }, + optional: { + validate: assertValueType("boolean"), + optional: true, + }, }, }); @@ -1440,6 +1449,7 @@ defineType("ExportDefaultDeclaration", { "Expression", ), }, + exportKind: validateOptional(assertOneOf("value")), }, }); @@ -2095,6 +2105,10 @@ defineType("ClassProperty", { validate: assertValueType("boolean"), optional: true, }, + variance: { + validate: assertNodeType("Variance"), + optional: true, + }, }, }); @@ -2123,6 +2137,18 @@ defineType("ClassPrivateProperty", { ), optional: true, }, + readonly: { + validate: assertValueType("boolean"), + optional: true, + }, + definite: { + validate: assertValueType("boolean"), + optional: true, + }, + variance: { + validate: assertNodeType("Variance"), + optional: true, + }, }, }); diff --git a/packages/babel-types/src/definitions/flow.ts b/packages/babel-types/src/definitions/flow.ts index 4c73176ef0..2b42c7ffbc 100644 --- a/packages/babel-types/src/definitions/flow.ts +++ b/packages/babel-types/src/definitions/flow.ts @@ -121,6 +121,7 @@ defineType("DeclareOpaqueType", { id: validateType("Identifier"), typeParameters: validateOptionalType("TypeParameterDeclaration"), supertype: validateOptionalType("FlowType"), + impltype: validateOptionalType("FlowType"), }, }); diff --git a/packages/babel-types/src/definitions/typescript.ts b/packages/babel-types/src/definitions/typescript.ts index e8e3115722..bd70b4467a 100644 --- a/packages/babel-types/src/definitions/typescript.ts +++ b/packages/babel-types/src/definitions/typescript.ts @@ -49,6 +49,17 @@ defineType("TSParameterProperty", { parameter: { 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), typeAnnotation: validateOptionalType("TSTypeAnnotation"), initializer: validateOptionalType("Expression"), + kind: { + validate: assertOneOf("get", "set"), + }, }, }); @@ -494,6 +508,10 @@ defineType("TSImportEqualsDeclaration", { "TSEntityName", "TSExternalModuleReference", ]), + importKind: { + validate: assertOneOf("type", "value"), + optional: true, + }, }, }); diff --git a/packages/babel-types/test/fields.js b/packages/babel-types/test/fields.js new file mode 100644 index 0000000000..13408b8c2f --- /dev/null +++ b/packages/babel-types/test/fields.js @@ -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)}`, + ); + } + }), + ); +}); diff --git a/yarn.lock b/yarn.lock index 3c2a0f4da1..42916384e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3606,6 +3606,7 @@ __metadata: "@babel/helper-validator-identifier": "workspace:^7.14.8" "@babel/parser": "workspace:*" chalk: ^4.1.0 + glob: ^7.1.7 to-fast-properties: ^2.0.0 languageName: unknown linkType: soft