123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- import t from "../../lib/index.js";
- import definitions from "../../lib/definitions/index.js";
- import formatBuilderName from "../utils/formatBuilderName.js";
- import lowerFirst from "../utils/lowerFirst.js";
- import stringifyValidator from "../utils/stringifyValidator.js";
-
- 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 generateBuilderArgs(type) {
- const fields = t.NODE_FIELDS[type];
- const fieldNames = sortFieldNames(Object.keys(t.NODE_FIELDS[type]), type);
- const builderNames = t.BUILDER_KEYS[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, "t.");
-
- if (isNullable(field) && !hasDefault(field)) {
- typeAnnotation += " | null";
- }
-
- if (builderNames.includes(fieldName)) {
- const bindingIdentifierName = t.toBindingIdentifierName(fieldName);
- if (areAllRemainingFieldsNullable(fieldName, builderNames, fields)) {
- args.push(
- `${bindingIdentifierName}${
- isNullable(field) ? "?:" : ":"
- } ${typeAnnotation}`
- );
- } else {
- args.push(
- `${bindingIdentifierName}: ${typeAnnotation}${
- isNullable(field) ? " | undefined" : ""
- }`
- );
- }
- }
- });
-
- return args;
- }
-
- export default function generateBuilders(kind) {
- return kind === "uppercase.js"
- ? generateUppercaseBuilders()
- : generateLowercaseBuilders();
- }
-
- function generateLowercaseBuilders() {
- let output = `/*
- * This file is auto-generated! Do not modify it directly.
- * To re-generate run 'make build'
- */
- import builder from "../builder";
- import type * as t from "../..";
-
- /* eslint-disable @typescript-eslint/no-unused-vars */
-
- `;
-
- const reservedNames = new Set(["super", "import"]);
- Object.keys(definitions.BUILDER_KEYS).forEach(type => {
- const defArgs = generateBuilderArgs(type);
- const formatedBuilderName = formatBuilderName(type);
- const formatedBuilderNameLocal = reservedNames.has(formatedBuilderName)
- ? `_${formatedBuilderName}`
- : formatedBuilderName;
- output += `${
- formatedBuilderNameLocal === formatedBuilderName ? "export " : ""
- }function ${formatedBuilderNameLocal}(${defArgs.join(
- ", "
- )}): t.${type} { return builder("${type}", ...arguments); }\n`;
- if (formatedBuilderNameLocal !== formatedBuilderName) {
- output += `export { ${formatedBuilderNameLocal} as ${formatedBuilderName} };\n`;
- }
-
- // This is needed for backwards compatibility.
- // It should be removed in the next major version.
- // JSXIdentifier -> jSXIdentifier
- if (/^[A-Z]{2}/.test(type)) {
- output += `export { ${formatedBuilderNameLocal} as ${lowerFirst(
- type
- )} }\n`;
- }
- });
-
- Object.keys(definitions.DEPRECATED_KEYS).forEach(type => {
- const newType = definitions.DEPRECATED_KEYS[type];
- const formatedBuilderName = formatBuilderName(type);
- output += `/** @deprecated */
- function ${type}(...args: Array<any>): any {
- console.trace("The node type ${type} has been renamed to ${newType}");
- return builder("${type}", ...args);
- }
- export { ${type} as ${formatedBuilderName} };\n`;
- // This is needed for backwards compatibility.
- // It should be removed in the next major version.
- // JSXIdentifier -> jSXIdentifier
- if (/^[A-Z]{2}/.test(type)) {
- output += `export { ${type} as ${lowerFirst(type)} }\n`;
- }
- });
-
- return output;
- }
-
- function generateUppercaseBuilders() {
- let output = `/*
- * This file is auto-generated! Do not modify it directly.
- * To re-generate run 'make build'
- */
-
- /**
- * This file is written in JavaScript and not TypeScript because uppercase builders
- * conflict with AST types. TypeScript reads the uppercase.d.ts file instead.
- */
-
- export {\n`;
-
- Object.keys(definitions.BUILDER_KEYS).forEach(type => {
- const formatedBuilderName = formatBuilderName(type);
- output += ` ${formatedBuilderName} as ${type},\n`;
- });
-
- Object.keys(definitions.DEPRECATED_KEYS).forEach(type => {
- const formatedBuilderName = formatBuilderName(type);
- output += ` ${formatedBuilderName} as ${type},\n`;
- });
-
- output += ` } from './index';\n`;
- return output;
- }
|