typescript.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. "use strict";
  2. const t = require("../../packages/babel-types");
  3. const utils = require("./utils");
  4. let code = `// NOTE: This file is autogenerated. Do not modify.
  5. // See scripts/generators/typescript.js for script used.
  6. interface BaseComment {
  7. value: string;
  8. start: number;
  9. end: number;
  10. loc: SourceLocation;
  11. type: "BlockComment" | "LineComment";
  12. }
  13. export interface BlockComment extends BaseComment {
  14. type: "BlockComment";
  15. }
  16. export interface LineComment extends BaseComment {
  17. type: "LineComment";
  18. }
  19. export type Comment = BlockComment | LineComment;
  20. export interface SourceLocation {
  21. start: {
  22. line: number;
  23. column: number;
  24. };
  25. end: {
  26. line: number;
  27. column: number;
  28. };
  29. }
  30. interface BaseNode {
  31. leadingComments: ReadonlyArray<Comment> | null;
  32. innerComments: ReadonlyArray<Comment> | null;
  33. trailingComments: ReadonlyArray<Comment> | null;
  34. start: number | null;
  35. end: number | null;
  36. loc: SourceLocation | null;
  37. type: Node["type"];
  38. }
  39. export type Node = ${t.TYPES.sort().join(" | ")};\n\n`;
  40. //
  41. const lines = [];
  42. for (const type in t.NODE_FIELDS) {
  43. const fields = t.NODE_FIELDS[type];
  44. const fieldNames = sortFieldNames(Object.keys(t.NODE_FIELDS[type]), type);
  45. const struct = ['type: "' + type + '";'];
  46. const args = [];
  47. fieldNames.forEach(fieldName => {
  48. const field = fields[fieldName];
  49. let typeAnnotation = utils.stringifyValidator(field.validate, "");
  50. if (isNullable(field) && !hasDefault(field)) {
  51. typeAnnotation += " | null";
  52. }
  53. if (areAllRemainingFieldsNullable(fieldName, fieldNames, fields)) {
  54. args.push(
  55. `${t.toBindingIdentifierName(fieldName)}${
  56. isNullable(field) ? "?:" : ":"
  57. } ${typeAnnotation}`
  58. );
  59. } else {
  60. args.push(
  61. `${t.toBindingIdentifierName(fieldName)}: ${typeAnnotation}${
  62. isNullable(field) ? " | undefined" : ""
  63. }`
  64. );
  65. }
  66. if (t.isValidIdentifier(fieldName)) {
  67. struct.push(`${fieldName}: ${typeAnnotation};`);
  68. }
  69. });
  70. code += `export interface ${type} extends BaseNode {
  71. ${struct.join("\n ").trim()}
  72. }\n\n`;
  73. // super and import are reserved words in JavaScript
  74. if (type !== "Super" && type !== "Import") {
  75. lines.push(
  76. `export function ${utils.toFunctionName(type)}(${args.join(
  77. ", "
  78. )}): ${type};`
  79. );
  80. }
  81. }
  82. for (let i = 0; i < t.TYPES.length; i++) {
  83. let decl = `export function is${
  84. t.TYPES[i]
  85. }(node: object, opts?: object | null): `;
  86. if (t.NODE_FIELDS[t.TYPES[i]]) {
  87. decl += `node is ${t.TYPES[i]};`;
  88. } else {
  89. decl += `boolean;`;
  90. }
  91. lines.push(decl);
  92. }
  93. lines.push(
  94. `export function validate(n: Node, key: string, value: any): void;`,
  95. `export function clone<T extends Node>(n: T): T;`,
  96. `export function cloneDeep<T extends Node>(n: T): T;`,
  97. `export function removeProperties(
  98. n: Node,
  99. opts?: { preserveComments: boolean } | null
  100. ): void;`,
  101. `export function removePropertiesDeep<T extends Node>(
  102. n: T,
  103. opts?: { preserveComments: boolean } | null
  104. ): T;`,
  105. `export type TraversalAncestors = ReadonlyArray<{
  106. node: Node,
  107. key: string,
  108. index?: number,
  109. }>;
  110. export type TraversalHandler<T> = (node: Node, parent: TraversalAncestors, type: T) => void;
  111. export type TraversalHandlers<T> = {
  112. enter?: TraversalHandler<T>,
  113. exit?: TraversalHandler<T>,
  114. };`.replace(/(^|\n) {2}/g, "$1"),
  115. // eslint-disable-next-line
  116. `export function traverse<T>(n: Node, h: TraversalHandler<T> | TraversalHandlers<T>, state?: T): void;`
  117. );
  118. for (const type in t.DEPRECATED_KEYS) {
  119. code += `/**
  120. * @deprecated Use \`${t.DEPRECATED_KEYS[type]}\`
  121. */
  122. export type ${type} = ${t.DEPRECATED_KEYS[type]};\n
  123. `;
  124. }
  125. for (const type in t.FLIPPED_ALIAS_KEYS) {
  126. const types = t.FLIPPED_ALIAS_KEYS[type];
  127. code += `export type ${type} = ${types
  128. .map(type => `${type}`)
  129. .join(" | ")};\n`;
  130. }
  131. code += lines.join("\n") + "\n";
  132. //
  133. process.stdout.write(code);
  134. //
  135. function areAllRemainingFieldsNullable(fieldName, fieldNames, fields) {
  136. const index = fieldNames.indexOf(fieldName);
  137. return fieldNames.slice(index).every(_ => isNullable(fields[_]));
  138. }
  139. function hasDefault(field) {
  140. return field.default != null;
  141. }
  142. function isNullable(field) {
  143. return field.optional || hasDefault(field);
  144. }
  145. function sortFieldNames(fields, type) {
  146. return fields.sort((fieldA, fieldB) => {
  147. const indexA = t.BUILDER_KEYS[type].indexOf(fieldA);
  148. const indexB = t.BUILDER_KEYS[type].indexOf(fieldB);
  149. if (indexA === indexB) return fieldA < fieldB ? -1 : 1;
  150. if (indexA === -1) return 1;
  151. if (indexB === -1) return -1;
  152. return indexA - indexB;
  153. });
  154. }