"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]; 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};` ); } } for (let i = 0; i < t.TYPES.length; i++) { let decl = `export function is${ t.TYPES[i] }(node: object | null | undefined, opts?: object | null): `; if (t.NODE_FIELDS[t.TYPES[i]]) { decl += `node is ${t.TYPES[i]};`; } else if (t.FLIPPED_ALIAS_KEYS[t.TYPES[i]]) { decl += `node is ${t.TYPES[i]};`; } else { decl += `boolean;`; } lines.push(decl); } lines.push( `export function validate(n: Node, key: string, value: any): void;`, `export function clone(n: T): T;`, `export function cloneDeep(n: T): T;`, `export function removeProperties( n: Node, opts?: { preserveComments: boolean } | null ): void;`, `export function removePropertiesDeep( n: T, opts?: { preserveComments: boolean } | null ): T;`, `export type TraversalAncestors = ReadonlyArray<{ node: Node, key: string, index?: number, }>; export type TraversalHandler = (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;` ); 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; }); }