/********************************************************************************************** Some of the source code in this file is sourced from https://github.com/babel/babel, and is licensed as below: MIT License Copyright (c) 2014-present Sebastian McKenzie and other contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ***********************************************************************************************/ import "../packages/compiler/dist/babel-types/types/patch.js"; import * as t from "@babel/types"; let code = `// NOTE: This file is autogenerated. Do not modify. // See packages/babel-types/scripts/generators/typescript-legacy.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"]; extra?: Record; } 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 builderNames = t.BUILDER_KEYS[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 (builderNames.includes(fieldName)) { if (areAllRemainingFieldsNullable(fieldName, builderNames, 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 isDeprecated = !!t.DEPRECATED_KEYS[typeName]; const realName = isDeprecated ? t.DEPRECATED_KEYS[typeName] : typeName; const result = t.NODE_FIELDS[realName] || t.FLIPPED_ALIAS_KEYS[realName] ? `node is ${realName}` : "boolean"; if (isDeprecated) { lines.push(`/** @deprecated Use \`is${realName}\` */`); } lines.push( `export function is${typeName}(node: object | null | undefined, opts?: object | null): ${result};` ); if (isDeprecated) { lines.push(`/** @deprecated Use \`assert${realName}\` */`); } lines.push( `export function assert${typeName}(node: object | null | undefined, opts?: object | null): void;` ); } lines.push( // assert/ `export function assertNode(obj: any): void`, // 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`, `export function createFlowUnionType(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`, `export function createFlowUnionType(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 cloneDeepWithoutLoc(n: T): T;`, `export function cloneNode(n: T, deep?: boolean, withoutLoc?: 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`, // 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; }); } function stringifyValidator(validator, nodePrefix) { if (validator === undefined) { return "any"; } if (validator.each) { return `Array<${stringifyValidator(validator.each, nodePrefix)}>`; } if (validator.chainOf) { const ret = stringifyValidator(validator.chainOf[1], nodePrefix); return Array.isArray(ret) && ret.length === 1 && ret[0] === "any" ? stringifyValidator(validator.chainOf[0], nodePrefix) : ret; } if (validator.oneOf) { return validator.oneOf.map(JSON.stringify).join(" | "); } if (validator.oneOfNodeTypes) { return validator.oneOfNodeTypes.map(_ => nodePrefix + _).join(" | "); } if (validator.oneOfNodeOrValueTypes) { return validator.oneOfNodeOrValueTypes .map(_ => { return isValueType(_) ? _ : nodePrefix + _; }) .join(" | "); } if (validator.type) { return validator.type; } if (validator.shapeOf) { return ( "{ " + Object.keys(validator.shapeOf) .map(shapeKey => { const propertyDefinition = validator.shapeOf[shapeKey]; if (propertyDefinition.validate) { const isOptional = propertyDefinition.optional || propertyDefinition.default != null; return ( shapeKey + (isOptional ? "?: " : ": ") + stringifyValidator(propertyDefinition.validate) ); } return null; }) .filter(Boolean) .join(", ") + " }" ); } return ["any"]; } function isValueType(type) { return type.charAt(0).toLowerCase() === type.charAt(0); } function toFunctionName(typeName) { const _ = typeName.replace(/^TS/, "ts").replace(/^JSX/, "jsx"); return _.slice(0, 1).toLowerCase() + _.slice(1); }