1 | import t from "../../lib/index.js";
|
---|
2 | import stringifyValidator from "../utils/stringifyValidator.js";
|
---|
3 |
|
---|
4 | export default function generateAstTypes() {
|
---|
5 | let code = `// NOTE: This file is autogenerated. Do not modify.
|
---|
6 | // See packages/babel-types/scripts/generators/ast-types.js for script used.
|
---|
7 |
|
---|
8 | interface BaseComment {
|
---|
9 | value: string;
|
---|
10 | start: number;
|
---|
11 | end: number;
|
---|
12 | loc: SourceLocation;
|
---|
13 | type: "CommentBlock" | "CommentLine";
|
---|
14 | }
|
---|
15 |
|
---|
16 | export interface CommentBlock extends BaseComment {
|
---|
17 | type: "CommentBlock";
|
---|
18 | }
|
---|
19 |
|
---|
20 | export interface CommentLine extends BaseComment {
|
---|
21 | type: "CommentLine";
|
---|
22 | }
|
---|
23 |
|
---|
24 | export type Comment = CommentBlock | CommentLine;
|
---|
25 |
|
---|
26 | export interface SourceLocation {
|
---|
27 | start: {
|
---|
28 | line: number;
|
---|
29 | column: number;
|
---|
30 | };
|
---|
31 |
|
---|
32 | end: {
|
---|
33 | line: number;
|
---|
34 | column: number;
|
---|
35 | };
|
---|
36 | }
|
---|
37 |
|
---|
38 | interface BaseNode {
|
---|
39 | leadingComments: ReadonlyArray<Comment> | null;
|
---|
40 | innerComments: ReadonlyArray<Comment> | null;
|
---|
41 | trailingComments: ReadonlyArray<Comment> | null;
|
---|
42 | start: number | null;
|
---|
43 | end: number | null;
|
---|
44 | loc: SourceLocation | null;
|
---|
45 | type: Node["type"];
|
---|
46 | range?: [number, number];
|
---|
47 | extra?: Record<string, unknown>;
|
---|
48 | }
|
---|
49 |
|
---|
50 | export type CommentTypeShorthand = "leading" | "inner" | "trailing";
|
---|
51 |
|
---|
52 | export type Node = ${t.TYPES.sort().join(" | ")};\n\n`;
|
---|
53 |
|
---|
54 | const deprecatedAlias = {};
|
---|
55 | for (const type in t.DEPRECATED_KEYS) {
|
---|
56 | deprecatedAlias[t.DEPRECATED_KEYS[type]] = type;
|
---|
57 | }
|
---|
58 | for (const type in t.NODE_FIELDS) {
|
---|
59 | const fields = t.NODE_FIELDS[type];
|
---|
60 | const fieldNames = sortFieldNames(Object.keys(t.NODE_FIELDS[type]), type);
|
---|
61 | const struct = [];
|
---|
62 |
|
---|
63 | fieldNames.forEach(fieldName => {
|
---|
64 | const field = fields[fieldName];
|
---|
65 | // Future / annoying TODO:
|
---|
66 | // MemberExpression.property, ObjectProperty.key and ObjectMethod.key need special cases; either:
|
---|
67 | // - convert the declaration to chain() like ClassProperty.key and ClassMethod.key,
|
---|
68 | // - declare an alias type for valid keys, detect the case and reuse it here,
|
---|
69 | // - declare a disjoint union with, for example, ObjectPropertyBase,
|
---|
70 | // ObjectPropertyLiteralKey and ObjectPropertyComputedKey, and declare ObjectProperty
|
---|
71 | // as "ObjectPropertyBase & (ObjectPropertyLiteralKey | ObjectPropertyComputedKey)"
|
---|
72 | let typeAnnotation = stringifyValidator(field.validate, "");
|
---|
73 |
|
---|
74 | if (isNullable(field) && !hasDefault(field)) {
|
---|
75 | typeAnnotation += " | null";
|
---|
76 | }
|
---|
77 |
|
---|
78 | const alphaNumeric = /^\w+$/;
|
---|
79 | const optional = field.optional ? "?" : "";
|
---|
80 |
|
---|
81 | if (t.isValidIdentifier(fieldName) || alphaNumeric.test(fieldName)) {
|
---|
82 | struct.push(`${fieldName}${optional}: ${typeAnnotation};`);
|
---|
83 | } else {
|
---|
84 | struct.push(`"${fieldName}"${optional}: ${typeAnnotation};`);
|
---|
85 | }
|
---|
86 | });
|
---|
87 |
|
---|
88 | code += `export interface ${type} extends BaseNode {
|
---|
89 | type: "${type}";
|
---|
90 | ${struct.join("\n ").trim()}
|
---|
91 | }\n\n`;
|
---|
92 |
|
---|
93 | if (deprecatedAlias[type]) {
|
---|
94 | code += `/**
|
---|
95 | * @deprecated Use \`${type}\`
|
---|
96 | */
|
---|
97 | export interface ${deprecatedAlias[type]} extends BaseNode {
|
---|
98 | type: "${deprecatedAlias[type]}";
|
---|
99 | ${struct.join("\n ").trim()}
|
---|
100 | }\n\n
|
---|
101 | `;
|
---|
102 | }
|
---|
103 | }
|
---|
104 |
|
---|
105 | for (const type in t.FLIPPED_ALIAS_KEYS) {
|
---|
106 | const types = t.FLIPPED_ALIAS_KEYS[type];
|
---|
107 | code += `export type ${type} = ${types
|
---|
108 | .map(type => `${type}`)
|
---|
109 | .join(" | ")};\n`;
|
---|
110 | }
|
---|
111 | code += "\n";
|
---|
112 |
|
---|
113 | code += "export interface Aliases {\n";
|
---|
114 | for (const type in t.FLIPPED_ALIAS_KEYS) {
|
---|
115 | code += ` ${type}: ${type};\n`;
|
---|
116 | }
|
---|
117 | code += "}\n\n";
|
---|
118 |
|
---|
119 | return code;
|
---|
120 | }
|
---|
121 |
|
---|
122 | function hasDefault(field) {
|
---|
123 | return field.default != null;
|
---|
124 | }
|
---|
125 |
|
---|
126 | function isNullable(field) {
|
---|
127 | return field.optional || hasDefault(field);
|
---|
128 | }
|
---|
129 |
|
---|
130 | function sortFieldNames(fields, type) {
|
---|
131 | return fields.sort((fieldA, fieldB) => {
|
---|
132 | const indexA = t.BUILDER_KEYS[type].indexOf(fieldA);
|
---|
133 | const indexB = t.BUILDER_KEYS[type].indexOf(fieldB);
|
---|
134 | if (indexA === indexB) return fieldA < fieldB ? -1 : 1;
|
---|
135 | if (indexA === -1) return 1;
|
---|
136 | if (indexB === -1) return -1;
|
---|
137 | return indexA - indexB;
|
---|
138 | });
|
---|
139 | }
|
---|