mirror of
https://github.com/Sevichecc/Urara-Blog.git
synced 2025-05-02 20:09:30 +08:00
196 lines
5.5 KiB
Text
196 lines
5.5 KiB
Text
import * as t from "../../lib/index.js";
|
|
import stringifyValidator, {
|
|
isValueType,
|
|
} from "../utils/stringifyValidator.js";
|
|
|
|
const parentMaps = new Map([["File", new Set(["null"])]]);
|
|
|
|
function registerParentMaps(parent, nodes) {
|
|
for (const node of nodes) {
|
|
if (!parentMaps.has(node)) {
|
|
parentMaps.set(node, new Set());
|
|
}
|
|
parentMaps.get(node).add(parent);
|
|
}
|
|
}
|
|
|
|
function getNodeTypesFromValidator(validator) {
|
|
if (validator === undefined) return [];
|
|
if (validator.each) {
|
|
return getNodeTypesFromValidator(validator.each);
|
|
}
|
|
if (validator.chainOf) {
|
|
return getNodeTypesFromValidator(validator.chainOf[1]);
|
|
}
|
|
let nodeTypes = [];
|
|
if (validator.oneOfNodeTypes) {
|
|
nodeTypes = validator.oneOfNodeTypes;
|
|
}
|
|
if (validator.oneOfNodeOrValueTypes) {
|
|
nodeTypes = validator.oneOfNodeOrValueTypes.filter(
|
|
type => !isValueType(type)
|
|
);
|
|
}
|
|
return nodeTypes.flatMap(type => t.FLIPPED_ALIAS_KEYS[type] ?? type);
|
|
}
|
|
|
|
export default function generateAstTypes() {
|
|
let code = `// NOTE: This file is autogenerated. Do not modify.
|
|
// See packages/babel-types/scripts/generators/ast-types.js for script used.
|
|
|
|
interface BaseComment {
|
|
value: string;
|
|
start?: number;
|
|
end?: number;
|
|
loc?: SourceLocation;
|
|
// generator will skip the comment if ignore is true
|
|
ignore?: boolean;
|
|
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 {
|
|
type: Node["type"];
|
|
leadingComments?: Comment[] | null;
|
|
innerComments?: Comment[] | null;
|
|
trailingComments?: Comment[] | null;
|
|
start?: number | null;
|
|
end?: number | null;
|
|
loc?: SourceLocation | null;
|
|
range?: [number, number];
|
|
extra?: Record<string, unknown>;
|
|
}
|
|
|
|
export type CommentTypeShorthand = "leading" | "inner" | "trailing";
|
|
|
|
export type Node = ${t.TYPES.filter(k => !t.FLIPPED_ALIAS_KEYS[k])
|
|
.sort()
|
|
.join(" | ")};\n\n`;
|
|
|
|
const deprecatedAlias = {};
|
|
for (const type in t.DEPRECATED_KEYS) {
|
|
deprecatedAlias[t.DEPRECATED_KEYS[type]] = type;
|
|
}
|
|
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 = [];
|
|
|
|
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";
|
|
}
|
|
|
|
const alphaNumeric = /^\w+$/;
|
|
const optional = field.optional ? "?" : "";
|
|
|
|
if (t.isValidIdentifier(fieldName) || alphaNumeric.test(fieldName)) {
|
|
struct.push(`${fieldName}${optional}: ${typeAnnotation};`);
|
|
} else {
|
|
struct.push(`"${fieldName}"${optional}: ${typeAnnotation};`);
|
|
}
|
|
|
|
registerParentMaps(type, getNodeTypesFromValidator(field.validate));
|
|
});
|
|
|
|
code += `export interface ${type} extends BaseNode {
|
|
type: "${type}";
|
|
${struct.join("\n ").trim()}
|
|
}\n\n`;
|
|
|
|
if (deprecatedAlias[type]) {
|
|
code += `/**
|
|
* @deprecated Use \`${type}\`
|
|
*/
|
|
export interface ${deprecatedAlias[type]} extends BaseNode {
|
|
type: "${deprecatedAlias[type]}";
|
|
${struct.join("\n ").trim()}
|
|
}\n\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 += `export type DeprecatedAliases = ${Object.keys(
|
|
t.DEPRECATED_KEYS
|
|
).join(" | ")}\n\n`;
|
|
|
|
code += "export interface ParentMaps {\n";
|
|
|
|
registerParentMaps("null", [...Object.keys(t.DEPRECATED_KEYS)]);
|
|
// todo: provide a better parent type for Placeholder, currently it acts
|
|
// as a catch-all parent type for an abstract NodePath, s.t NodePath.parent must
|
|
// be a Node if type has not been specified
|
|
registerParentMaps("Node", ["Placeholder"]);
|
|
|
|
const parentMapsKeys = [...parentMaps.keys()].sort();
|
|
for (const type of parentMapsKeys) {
|
|
const deduplicated = [...parentMaps.get(type)].sort();
|
|
code += ` ${type}: ${deduplicated.join(" | ")};\n`;
|
|
}
|
|
code += "}\n\n";
|
|
|
|
return code;
|
|
}
|
|
|
|
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;
|
|
});
|
|
}
|