"use strict"; const t = require("../../"); const stringifyValidator = require("../utils/stringifyValidator"); const toFunctionName = require("../utils/toFunctionName"); let code = `// NOTE: This file is autogenerated. Do not modify. // See packages/babel-types/scripts/generators/typescript.js for script used. interface BaseComment { value: string; start: number; end: number; loc: SourceLocation; type: "CommentBlock" | "CommentLine"; } export interface CommentBlock extends BaseComment { type: "CommentBlock"; } export interface CommentLine extends BaseComment { type: "CommentLine"; } export type Comment = CommentBlock | CommentLine; export interface SourceLocation { start: { line: number; column: number; }; end: { line: number; column: number; }; } interface BaseNode { leadingComments: ReadonlyArray | null; innerComments: ReadonlyArray | null; trailingComments: ReadonlyArray | null; start: number | null; end: number | null; loc: SourceLocation | null; type: Node["type"]; } export type Node = ${t.TYPES.sort().join(" | ")};\n\n`; // const lines = []; for (const type in t.NODE_FIELDS) { const fields = t.NODE_FIELDS[type]; const fieldNames = sortFieldNames(Object.keys(t.NODE_FIELDS[type]), type); const struct = ['type: "' + type + '";']; const args = []; fieldNames.forEach(fieldName => { const field = fields[fieldName]; // Future / annoying TODO: // MemberExpression.property, ObjectProperty.key and ObjectMethod.key need special cases; either: // - convert the declaration to chain() like ClassProperty.key and ClassMethod.key, // - declare an alias type for valid keys, detect the case and reuse it here, // - declare a disjoint union with, for example, ObjectPropertyBase, // ObjectPropertyLiteralKey and ObjectPropertyComputedKey, and declare ObjectProperty // as "ObjectPropertyBase & (ObjectPropertyLiteralKey | ObjectPropertyComputedKey)" let typeAnnotation = stringifyValidator(field.validate, ""); if (isNullable(field) && !hasDefault(field)) { typeAnnotation += " | null"; } if (areAllRemainingFieldsNullable(fieldName, fieldNames, fields)) { args.push( `${t.toBindingIdentifierName(fieldName)}${ isNullable(field) ? "?:" : ":" } ${typeAnnotation}` ); } else { args.push( `${t.toBindingIdentifierName(fieldName)}: ${typeAnnotation}${ isNullable(field) ? " | undefined" : "" }` ); } const alphaNumeric = /^\w+$/; if (t.isValidIdentifier(fieldName) || alphaNumeric.test(fieldName)) { struct.push(`${fieldName}: ${typeAnnotation};`); } else { struct.push(`"${fieldName}": ${typeAnnotation};`); } }); code += `export interface ${type} extends BaseNode { ${struct.join("\n ").trim()} }\n\n`; // super and import are reserved words in JavaScript if (type !== "Super" && type !== "Import") { lines.push( `export function ${toFunctionName(type)}(${args.join(", ")}): ${type};` ); } else { const functionName = toFunctionName(type); lines.push( `declare function _${functionName}(${args.join(", ")}): ${type};`, `export { _${functionName} as ${functionName}}` ); } } for (const typeName of t.TYPES) { const result = t.NODE_FIELDS[typeName] || t.FLIPPED_ALIAS_KEYS[typeName] ? `node is ${typeName}` : "boolean"; lines.push( `export function is${typeName}(node: object | null | undefined, opts?: object | null): ${result};`, // TypeScript 3.7: https://github.com/microsoft/TypeScript/pull/32695 will allow assert declarations // eslint-disable-next-line max-len `// export function assert${typeName}(node: object | null | undefined, opts?: object | null): asserts ${ result === "boolean" ? "node" : result };` ); } lines.push( // assert/ // Commented out as this declaration requires TypeScript 3.7 (what do?) `// export function assertNode(obj: any): asserts obj is Node`, // builders/ // eslint-disable-next-line max-len `export function createTypeAnnotationBasedOnTypeof(type: 'string' | 'number' | 'undefined' | 'boolean' | 'function' | 'object' | 'symbol'): StringTypeAnnotation | VoidTypeAnnotation | NumberTypeAnnotation | BooleanTypeAnnotation | GenericTypeAnnotation`, `export function createUnionTypeAnnotation(types: [T]): T`, // this probably misbehaves if there are 0 elements, and it's not a UnionTypeAnnotation if there's only 1 // it is possible to require "2 or more" for this overload ([T, T, ...T[]]) but it requires typescript 3.0 `export function createUnionTypeAnnotation(types: ReadonlyArray): UnionTypeAnnotation`, // this smells like "internal API" // eslint-disable-next-line max-len `export function buildChildren(node: { children: ReadonlyArray }): JSXElement['children']`, // clone/ `export function clone(n: T): T;`, `export function cloneDeep(n: T): T;`, `export function cloneNode(n: T, deep?: boolean): T;`, `export function cloneWithoutLoc(n: T): T;`, // comments/ `export type CommentTypeShorthand = 'leading' | 'inner' | 'trailing'`, // eslint-disable-next-line max-len `export function addComment(node: T, type: CommentTypeShorthand, content: string, line?: boolean): T`, // eslint-disable-next-line max-len `export function addComments(node: T, type: CommentTypeShorthand, comments: ReadonlyArray): T`, `export function inheritInnerComments(node: Node, parent: Node): void`, `export function inheritLeadingComments(node: Node, parent: Node): void`, `export function inheritsComments(node: T, parent: Node): void`, `export function inheritTrailingComments(node: Node, parent: Node): void`, `export function removeComments(node: T): T`, // converters/ // eslint-disable-next-line max-len `export function ensureBlock(node: Extract): BlockStatement`, // too complex? // eslint-disable-next-line max-len `export function ensureBlock = 'body'>(node: Extract>, key: K): BlockStatement`, // gatherSequenceExpressions is not exported `export function toBindingIdentifierName(name: { toString(): string } | null | undefined): string`, `export function toBlock(node: Statement | Expression, parent?: Function | null): BlockStatement`, // it is possible for `node` to be an arbitrary object if `key` is always provided, // but that doesn't look like intended API // eslint-disable-next-line max-len `export function toComputedKey>(node: T, key?: Expression | Identifier): Expression`, `export function toExpression(node: Function): FunctionExpression`, `export function toExpression(node: Class): ClassExpression`, `export function toExpression(node: ExpressionStatement | Expression | Class | Function): Expression`, `export function toIdentifier(name: { toString(): string } | null | undefined): string`, `export function toKeyAlias(node: Method | Property, key?: Node): string`, // NOTE: this actually uses Scope from @babel/traverse, but we can't add a dependency on its types, // as they live in @types. Declare the structural subset that is required. // eslint-disable-next-line max-len `export function toSequenceExpression(nodes: ReadonlyArray, scope: { push(value: { id: LVal; kind: 'var'; init?: Expression}): void; buildUndefinedNode(): Node }): SequenceExpression | undefined`, `export function toStatement(node: AssignmentExpression, ignore?: boolean): ExpressionStatement`, `export function toStatement(node: Statement | AssignmentExpression, ignore?: boolean): Statement`, `export function toStatement(node: Class, ignore: true): ClassDeclaration | undefined`, `export function toStatement(node: Class, ignore?: boolean): ClassDeclaration`, `export function toStatement(node: Function, ignore: true): FunctionDeclaration | undefined`, `export function toStatement(node: Function, ignore?: boolean): FunctionDeclaration`, // eslint-disable-next-line max-len `export function toStatement(node: Statement | Class | Function | AssignmentExpression, ignore: true): Statement | undefined`, // eslint-disable-next-line max-len `export function toStatement(node: Statement | Class | Function | AssignmentExpression, ignore?: boolean): Statement`, // eslint-disable-next-line max-len `export function valueToNode(value: undefined): Identifier`, // (should this not be a UnaryExpression to avoid shadowing?) `export function valueToNode(value: boolean): BooleanLiteral`, `export function valueToNode(value: null): NullLiteral`, `export function valueToNode(value: string): StringLiteral`, // Infinities and NaN need to use a BinaryExpression; negative values must be wrapped in UnaryExpression `export function valueToNode(value: number): NumericLiteral | BinaryExpression | UnaryExpression`, `export function valueToNode(value: RegExp): RegExpLiteral`, // eslint-disable-next-line max-len `export function valueToNode(value: ReadonlyArray): ArrayExpression`, // this throws with objects that are not PlainObject according to lodash, // or if there are non-valueToNode-able values `export function valueToNode(value: object): ObjectExpression`, // eslint-disable-next-line max-len `export function valueToNode(value: undefined | boolean | null | string | number | RegExp | object): Expression`, // modifications/ // eslint-disable-next-line max-len `export function removeTypeDuplicates(types: ReadonlyArray): FlowType[]`, // eslint-disable-next-line max-len `export function appendToMemberExpression>(member: T, append: MemberExpression['property'], computed?: boolean): T`, // eslint-disable-next-line max-len `export function inherits(child: T, parent: Node | null | undefined): T`, // eslint-disable-next-line max-len `export function prependToMemberExpression>(member: T, prepend: MemberExpression['object']): T`, `export function removeProperties( n: Node, opts?: { preserveComments: boolean } | null ): void;`, `export function removePropertiesDeep( n: T, opts?: { preserveComments: boolean } | null ): T;`, // retrievers/ // eslint-disable-next-line max-len `export function getBindingIdentifiers(node: Node, duplicates: true, outerOnly?: boolean): Record>`, // eslint-disable-next-line max-len `export function getBindingIdentifiers(node: Node, duplicates?: false, outerOnly?: boolean): Record`, // eslint-disable-next-line max-len `export function getBindingIdentifiers(node: Node, duplicates: boolean, outerOnly?: boolean): Record>`, // eslint-disable-next-line max-len `export function getOuterBindingIdentifiers(node: Node, duplicates: true): Record>`, `export function getOuterBindingIdentifiers(node: Node, duplicates?: false): Record`, // eslint-disable-next-line max-len `export function getOuterBindingIdentifiers(node: Node, duplicates: boolean): Record>`, // traverse/ `export type TraversalAncestors = ReadonlyArray<{ node: Node, key: string, index?: number, }>; export type TraversalHandler = ( this: undefined, node: Node, parent: TraversalAncestors, type: T ) => void; export type TraversalHandlers = { enter?: TraversalHandler, exit?: TraversalHandler, };`.replace(/(^|\n) {2}/g, "$1"), // eslint-disable-next-line `export function traverse(n: Node, h: TraversalHandler | TraversalHandlers, state?: T): void;`, `export function traverseFast(n: Node, h: TraversalHandler, state?: T): void;`, // utils/ // cleanJSXElementLiteralChild is not exported // inherit is not exported `export function shallowEqual(actual: object, expected: T): actual is T`, // validators/ // eslint-disable-next-line max-len `export function buildMatchMemberExpression(match: string, allowPartial?: boolean): (node: Node | null | undefined) => node is MemberExpression`, // eslint-disable-next-line max-len `export function is(type: T, n: Node | null | undefined, required?: undefined): n is Extract`, // eslint-disable-next-line max-len `export function is>(type: T, n: Node | null | undefined, required: Partial

): n is P`, // eslint-disable-next-line max-len `export function is

(type: string, n: Node | null | undefined, required: Partial

): n is P`, `export function is(type: string, n: Node | null | undefined, required?: Partial): n is Node`, `export function isBinding(node: Node, parent: Node, grandparent?: Node): boolean`, // eslint-disable-next-line max-len `export function isBlockScoped(node: Node): node is FunctionDeclaration | ClassDeclaration | VariableDeclaration`, `export function isImmutable(node: Node): node is Immutable`, `export function isLet(node: Node): node is VariableDeclaration`, `export function isNode(node: object | null | undefined): node is Node`, `export function isNodesEquivalent>(a: T, b: any): b is T`, `export function isNodesEquivalent(a: any, b: any): boolean`, `export function isPlaceholderType(placeholderType: Node['type'], targetType: Node['type']): boolean`, `export function isReferenced(node: Node, parent: Node, grandparent?: Node): boolean`, `export function isScope(node: Node, parent: Node): node is Scopable`, `export function isSpecifierDefault(specifier: ModuleSpecifier): boolean`, `export function isType(nodetype: string, targetType: T): nodetype is T`, `export function isType(nodetype: string | null | undefined, targetType: string): boolean`, `export function isValidES3Identifier(name: string): boolean`, `export function isValidIdentifier(name: string): boolean`, `export function isVar(node: Node): node is VariableDeclaration`, // the MemberExpression implication is incidental, but it follows from the implementation // eslint-disable-next-line max-len `export function matchesPattern(node: Node | null | undefined, match: string | ReadonlyArray, allowPartial?: boolean): node is MemberExpression`, // TypeScript 3.7: ": asserts n is T" // eslint-disable-next-line max-len `export function validate(n: Node | null | undefined, key: K, value: T[K]): void`, `export function validate(n: Node, key: string, value: any): void;` ); for (const type in t.DEPRECATED_KEYS) { code += `/** * @deprecated Use \`${t.DEPRECATED_KEYS[type]}\` */ export type ${type} = ${t.DEPRECATED_KEYS[type]};\n `; } for (const type in t.FLIPPED_ALIAS_KEYS) { const types = t.FLIPPED_ALIAS_KEYS[type]; code += `export type ${type} = ${types .map(type => `${type}`) .join(" | ")};\n`; } code += "\n"; code += "export interface Aliases {\n"; for (const type in t.FLIPPED_ALIAS_KEYS) { code += ` ${type}: ${type};\n`; } code += "}\n\n"; code += lines.join("\n") + "\n"; // process.stdout.write(code); // function areAllRemainingFieldsNullable(fieldName, fieldNames, fields) { const index = fieldNames.indexOf(fieldName); return fieldNames.slice(index).every(_ => isNullable(fields[_])); } function hasDefault(field) { return field.default != null; } function isNullable(field) { return field.optional || hasDefault(field); } function sortFieldNames(fields, type) { return fields.sort((fieldA, fieldB) => { const indexA = t.BUILDER_KEYS[type].indexOf(fieldA); const indexB = t.BUILDER_KEYS[type].indexOf(fieldB); if (indexA === indexB) return fieldA < fieldB ? -1 : 1; if (indexA === -1) return 1; if (indexB === -1) return -1; return indexA - indexB; }); }