flowgen
Version:
Generate flowtype definition files from TypeScript
730 lines (570 loc) • 29.5 kB
JavaScript
"use strict";
exports.__esModule = true;
exports.default = void 0;
exports.fixDefaultTypeArguments = fixDefaultTypeArguments;
exports.getFullyQualifiedName = getFullyQualifiedName;
exports.getFullyQualifiedPropertyAccessExpression = getFullyQualifiedPropertyAccessExpression;
exports.getLeftMostPropertyAccessExpression = getLeftMostPropertyAccessExpression;
exports.getTypeofFullyQualifiedName = getTypeofFullyQualifiedName;
exports.printEntityName = printEntityName;
exports.printFlowGenHelper = printFlowGenHelper;
exports.printPropertyAccessExpression = printPropertyAccessExpression;
exports.printType = void 0;
var ts = _interopRequireWildcard(require("typescript"));
var _util = _interopRequireDefault(require("util"));
var printers = _interopRequireWildcard(require("./index"));
var _checker = require("../checker");
var logger = _interopRequireWildcard(require("../logger"));
var _env = require("../env");
var _smartIdentifiers = require("./smart-identifiers");
var _errorMessage = require("../errors/error-message");
var _options = require("../options");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function printEntityName(type) {
if (type.kind === ts.SyntaxKind.QualifiedName) {
return printers.relationships.namespace(type.left.kind === ts.SyntaxKind.Identifier ? type.left.text : printEntityName(type.left)) + printEntityName(type.right);
} else if (type.kind === ts.SyntaxKind.Identifier) {
return printers.relationships.namespace(type.text, true);
} else {
return "";
}
}
function printPropertyAccessExpression(type) {
if (type.kind === ts.SyntaxKind.PropertyAccessExpression) {
return printers.relationships.namespace(ts.isIdentifier(type.expression) ? type.expression.text : // @ts-expect-error todo(flow->ts)
printPropertyAccessExpression(type.expression)) + printPropertyAccessExpression(type.name);
} else if (type.kind === ts.SyntaxKind.Identifier) {
return printers.relationships.namespace( // @ts-expect-error todo(flow->ts)
printers.identifiers.print(type.text), true);
} else {
return "";
}
}
function getLeftMostPropertyAccessExpression(type) {
if (type.kind === ts.SyntaxKind.PropertyAccessExpression) {
return ts.isIdentifier(type.expression) ? type.expression : // @ts-expect-error todo(flow->ts)
getLeftMostPropertyAccessExpression(type.expression);
} else if (type.kind === ts.SyntaxKind.Identifier) {
return type;
}
}
function getFullyQualifiedPropertyAccessExpression(symbol, type, delimiter = "$") {
if (_checker.checker.current) {
var _symbol$parent, _symbol$parent$valueD, _symbol$parent2, _symbol$parent2$value, _symbol$parent3;
const typeChecker = _checker.checker.current;
let isExternalSymbol = false;
const leftMost = getLeftMostPropertyAccessExpression(type);
if (leftMost) {
//$todo Flow has problems when switching variables instead of literals
const leftMostSymbol = typeChecker.getSymbolAtLocation(leftMost); // todo(flow->ts)
const decl = leftMostSymbol ? leftMostSymbol.declarations[0] : {};
isExternalSymbol = decl.kind === ts.SyntaxKind.NamespaceImport || decl.kind === ts.SyntaxKind.NamedImports;
}
if (!symbol || typeChecker.isUnknownSymbol(symbol) || isExternalSymbol) {
return printPropertyAccessExpression(type);
}
if (((_symbol$parent = symbol.parent) == null ? void 0 : (_symbol$parent$valueD = _symbol$parent.valueDeclaration) == null ? void 0 : _symbol$parent$valueD.kind) === ts.SyntaxKind.SourceFile || ((_symbol$parent2 = symbol.parent) == null ? void 0 : (_symbol$parent2$value = _symbol$parent2.valueDeclaration) == null ? void 0 : _symbol$parent2$value.kind) === ts.SyntaxKind.ModuleDeclaration && (((_symbol$parent3 = symbol.parent) == null ? void 0 : _symbol$parent3.valueDeclaration.flags) & ts.NodeFlags.Namespace) === 0) {
return typeChecker.symbolToString(symbol);
} // if (
// (symbol.flags & ts.SymbolFlags.ValueModule) ===
// ts.SymbolFlags.ValueModule
// ) {
// return typeChecker.symbolToString(
// symbol,
// undefined,
// /*meaning*/ undefined,
// ts.SymbolFormatFlags.DoNotIncludeSymbolChain |
// ts.SymbolFormatFlags.AllowAnyNodeKind,
// );
// }
return symbol.parent ? getFullyQualifiedPropertyAccessExpression(symbol.parent, type, delimiter) + delimiter + typeChecker.symbolToString(symbol) : typeChecker.symbolToString(symbol, undefined,
/*meaning*/
undefined, //$todo Some problem about TypeScript enums conversion and bitwise operators
ts.SymbolFormatFlags.DoNotIncludeSymbolChain | ts.SymbolFormatFlags.AllowAnyNodeKind);
} else {
return printPropertyAccessExpression(type);
}
}
function getFullyQualifiedName(symbol, type, checks = true, delimiter = "$") {
if (_checker.checker.current) {
var _symbol$parent4, _symbol$parent4$value, _symbol$parent5, _symbol$parent5$value, _symbol$parent6, _symbol$valueDeclarat;
const typeChecker = _checker.checker.current;
if (checks) {
let isExternalSymbol = false;
const leftMost = (0, _smartIdentifiers.getLeftMostEntityName)(type);
if (leftMost) {
var _leftMostSymbol$paren;
//$todo Flow has problems when switching variables instead of literals
const leftMostSymbol = typeChecker.getSymbolAtLocation(leftMost);
const decl = leftMostSymbol && leftMostSymbol.declarations && leftMostSymbol.declarations.length ? leftMostSymbol.declarations[0] : {};
isExternalSymbol = decl.kind === ts.SyntaxKind.NamespaceImport || decl.kind === ts.SyntaxKind.NamedImports || decl.kind === ts.SyntaxKind.TypeParameter || (leftMostSymbol == null ? void 0 : (_leftMostSymbol$paren = leftMostSymbol.parent) == null ? void 0 : _leftMostSymbol$paren.escapedName) === "__global";
}
if (!symbol || typeChecker.isUnknownSymbol(symbol) || isExternalSymbol) {
return printEntityName(type);
}
}
if (((_symbol$parent4 = symbol.parent) == null ? void 0 : (_symbol$parent4$value = _symbol$parent4.valueDeclaration) == null ? void 0 : _symbol$parent4$value.kind) === ts.SyntaxKind.SourceFile || ((_symbol$parent5 = symbol.parent) == null ? void 0 : (_symbol$parent5$value = _symbol$parent5.valueDeclaration) == null ? void 0 : _symbol$parent5$value.kind) === ts.SyntaxKind.ModuleDeclaration && (((_symbol$parent6 = symbol.parent) == null ? void 0 : _symbol$parent6.valueDeclaration.flags) & ts.NodeFlags.Namespace) === 0) {
return typeChecker.symbolToString(symbol);
} // if (
// (symbol.flags & ts.SymbolFlags.ValueModule) ===
// ts.SymbolFlags.ValueModule
// ) {
// return typeChecker.symbolToString(
// symbol,
// undefined,
// /*meaning*/ undefined,
// ts.SymbolFormatFlags.DoNotIncludeSymbolChain |
// ts.SymbolFormatFlags.AllowAnyNodeKind,
// );
// }
if (((_symbol$valueDeclarat = symbol.valueDeclaration) == null ? void 0 : _symbol$valueDeclarat.kind) === ts.SyntaxKind.EnumMember) delimiter = ".";
return symbol.parent ? getFullyQualifiedName(symbol.parent, type, true, delimiter) + delimiter + typeChecker.symbolToString(symbol) : typeChecker.symbolToString(symbol, undefined,
/*meaning*/
undefined, //$todo Some problem about TypeScript enums conversion and bitwise operators
ts.SymbolFormatFlags.DoNotIncludeSymbolChain | ts.SymbolFormatFlags.AllowAnyNodeKind);
} else {
return printEntityName(type);
}
}
function getTypeofFullyQualifiedName(symbol, type, delimiter = ".") {
if (_checker.checker.current) {
var _symbol$parent7, _symbol$parent7$value, _symbol$parent8, _symbol$parent8$value, _symbol$parent9, _symbol$parent10;
const typeChecker = _checker.checker.current;
let isExternalSymbol = false;
const leftMost = (0, _smartIdentifiers.getLeftMostEntityName)(type);
if (leftMost) {
//$todo Flow has problems when switching variables instead of literals
const leftMostSymbol = typeChecker.getSymbolAtLocation(leftMost); // todo(flow->ts)
const decl = leftMostSymbol ? leftMostSymbol.declarations[0] : {};
isExternalSymbol = decl.kind === ts.SyntaxKind.NamespaceImport || decl.kind === ts.SyntaxKind.NamedImports;
}
if (!symbol || typeChecker.isUnknownSymbol(symbol) || isExternalSymbol) {
return printEntityName(type);
}
if (((_symbol$parent7 = symbol.parent) == null ? void 0 : (_symbol$parent7$value = _symbol$parent7.valueDeclaration) == null ? void 0 : _symbol$parent7$value.kind) === ts.SyntaxKind.SourceFile || ((_symbol$parent8 = symbol.parent) == null ? void 0 : (_symbol$parent8$value = _symbol$parent8.valueDeclaration) == null ? void 0 : _symbol$parent8$value.kind) === ts.SyntaxKind.ModuleDeclaration && (((_symbol$parent9 = symbol.parent) == null ? void 0 : _symbol$parent9.valueDeclaration.flags) & ts.NodeFlags.Namespace) === 0) {
return typeChecker.symbolToString(symbol);
}
if (((_symbol$parent10 = symbol.parent) == null ? void 0 : _symbol$parent10.escapedName) === "__type") {
return symbol.parent ? getTypeofFullyQualifiedName( // @ts-expect-error todo(flow->ts)
symbol.parent.declarations[0].parent.symbol, type) + delimiter + typeChecker.symbolToString(symbol) : typeChecker.symbolToString(symbol, undefined,
/*meaning*/
undefined, //$todo Some problem about TypeScript enums conversion and bitwise operators
ts.SymbolFormatFlags.DoNotIncludeSymbolChain | ts.SymbolFormatFlags.AllowAnyNodeKind);
} else {
var _symbol$valueDeclarat2;
let delimiter = "$";
if (((_symbol$valueDeclarat2 = symbol.valueDeclaration) == null ? void 0 : _symbol$valueDeclarat2.kind) === ts.SyntaxKind.EnumMember) {
delimiter = ".";
}
return symbol.parent ? getTypeofFullyQualifiedName(symbol.parent, type, delimiter) + delimiter + typeChecker.symbolToString(symbol) : typeChecker.symbolToString(symbol, undefined,
/*meaning*/
undefined, //$todo Some problem about TypeScript enums conversion and bitwise operators
ts.SymbolFormatFlags.DoNotIncludeSymbolChain | ts.SymbolFormatFlags.AllowAnyNodeKind);
}
} else {
return printEntityName(type);
}
}
function printFlowGenHelper(env) {
let helpers = "";
if (env.conditionalHelpers) {
helpers += `
// see https://gist.github.com/thecotne/6e5969f4aaf8f253985ed36b30ac9fe0
type $FlowGen$If<X: boolean, Then, Else = empty> = $Call<
& ((true, Then, Else) => Then)
& ((false, Then, Else) => Else),
X,
Then,
Else,
>;
type $FlowGen$Assignable<A, B> = $Call<
& ((...r: [B]) => true)
& ((...r: [A]) => false),
A,
>;`;
}
return helpers;
}
function fixDefaultTypeArguments(symbol, type) {
var _decl$typeParameters;
if (!symbol) return;
if (!symbol.declarations) return;
const decl = symbol.declarations[0];
const allTypeParametersHaveDefaults = // @ts-expect-error todo(flow->ts)
!!(decl != null && (_decl$typeParameters = decl.typeParameters) != null && _decl$typeParameters.length) && // @ts-expect-error todo(flow->ts)
decl.typeParameters.every(param => !!param.default);
if (allTypeParametersHaveDefaults && !type.typeArguments) {
type.typeArguments = [];
}
}
/**
* Log an error, while returning a commented FlowFixMe type.
*
* This is appropriate for error conditions that indicate a bug within
* Flowgen.
*
* The error uses `logger.error` for a nice message pointing at the input
* source code corresponding to `node`, to help identify what triggered the
* issue.
*/
const printErrorType = (description, node) => {
logger.error(node, {
type: "FlowgenInternalError",
description
});
return `($FlowFixMe /* flowgen-error: ${description} */)`;
};
const printType = (0, _env.withEnv)((env, rawType) => {
var _type$name, _name, _type$name2;
// debuggerif()
//TODO: #6 No match found in SyntaxKind enum
const type = rawType;
const keywordPrefix = // @ts-expect-error todo(flow->ts)
type.modifiers && // @ts-expect-error todo(flow->ts)
type.modifiers.some(modifier => modifier.kind === ts.SyntaxKind.StaticKeyword) ? "static " : "";
const kind = ts.SyntaxKind[type.kind].toString();
switch (type.kind) {
case ts.SyntaxKind.VoidKeyword:
return printers.basics.print(kind);
case ts.SyntaxKind.StringKeyword:
return printers.basics.print(kind);
case ts.SyntaxKind.AnyKeyword:
return printers.basics.print(kind);
case ts.SyntaxKind.NumberKeyword:
return printers.basics.print(kind);
case ts.SyntaxKind.BooleanKeyword:
return printers.basics.print(kind);
case ts.SyntaxKind.NullKeyword:
return printers.basics.print(kind);
case ts.SyntaxKind.UndefinedKeyword:
return printers.basics.print(kind);
case ts.SyntaxKind.ObjectKeyword:
return printers.basics.print(kind);
case ts.SyntaxKind.FalseKeyword:
return printers.basics.print(kind);
case ts.SyntaxKind.TrueKeyword:
return printers.basics.print(kind);
case ts.SyntaxKind.NeverKeyword:
return printers.basics.print(kind);
case ts.SyntaxKind.UnknownKeyword:
return printers.basics.print(kind);
case ts.SyntaxKind.SymbolKeyword:
// TODO: What to print here?
return "Symbol";
case ts.SyntaxKind.BigIntKeyword:
return printers.basics.print(kind);
// JSDoc types
case ts.SyntaxKind.JSDocAllType:
return "*";
case ts.SyntaxKind.JSDocUnknownType:
return "?";
case ts.SyntaxKind.JSDocOptionalType:
return printType(type.type) + "=";
case ts.SyntaxKind.JSDocFunctionType:
{
const params = type.parameters.map(param => printType(param.type)).join(", ");
const ret = type.type ? `: ${printType(type.type)}` : "";
return `function(${params})${ret}`;
}
case ts.SyntaxKind.JSDocTypeLiteral:
return "object";
case ts.SyntaxKind.JSDocVariadicType:
return "..." + printType(type.type);
case ts.SyntaxKind.JSDocNonNullableType:
return "!" + printType(type.type);
case ts.SyntaxKind.JSDocNullableType:
return "?" + printType(type.type);
case ts.SyntaxKind.JSDocNameReference:
// @ts-expect-error todo(flow->ts) - 'escapedText' does not exist on type 'EntityName | JSDocMemberName'
return (type == null ? void 0 : (_type$name = type.name) == null ? void 0 : _type$name.escapedText) || "";
case ts.SyntaxKind.ConditionalType:
{
env.conditionalHelpers = true;
return `$FlowGen$If<$FlowGen$Assignable<${printType(type.checkType)},${printType(type.extendsType)}>,${printType(type.trueType)},${printType(type.falseType)}>`;
}
case ts.SyntaxKind.ComputedPropertyName:
{
var _type$expression, _type$expression$expr, _type$expression2, _type$expression2$nam, _type$expression3, _type$expression3$exp, _type$expression4, _type$expression4$nam;
if ( // @ts-expect-error todo(flow->ts)
((_type$expression = type.expression) == null ? void 0 : (_type$expression$expr = _type$expression.expression) == null ? void 0 : _type$expression$expr.text) === "Symbol" && // @ts-expect-error todo(flow->ts)
((_type$expression2 = type.expression) == null ? void 0 : (_type$expression2$nam = _type$expression2.name) == null ? void 0 : _type$expression2$nam.text) === "iterator") {
return "@@iterator";
}
if ( // @ts-expect-error todo(flow->ts)
((_type$expression3 = type.expression) == null ? void 0 : (_type$expression3$exp = _type$expression3.expression) == null ? void 0 : _type$expression3$exp.text) === "Symbol" && // @ts-expect-error todo(flow->ts)
((_type$expression4 = type.expression) == null ? void 0 : (_type$expression4$nam = _type$expression4.name) == null ? void 0 : _type$expression4$nam.text) === "asyncIterator") {
return "@@asyncIterator";
}
if (type.expression.kind === ts.SyntaxKind.StringLiteral) {
return printType(type.expression);
}
logger.error(type.expression, {
type: "UnsupportedComputedProperty"
});
return `[typeof ${printType(type.expression)}]`;
}
case ts.SyntaxKind.FunctionType:
//case SyntaxKind.FunctionTypeAnnotation:
return printers.functions.functionType(type);
case ts.SyntaxKind.TypeLiteral:
return printers.declarations.interfaceType(type, "", [], false, true);
//case SyntaxKind.IdentifierObject:
//case SyntaxKind.StringLiteralType:
case ts.SyntaxKind.Identifier:
{
return printers.relationships.namespace( // @ts-expect-error todo(flow->ts)
printers.identifiers.print(type.text), true);
}
case ts.SyntaxKind.BindingElement:
// @ts-expect-error todo(flow->ts)
return printers.common.typeParameter(type);
case ts.SyntaxKind.TypeParameter:
// @ts-expect-error todo(flow->ts)
return printers.common.typeParameter(type);
case ts.SyntaxKind.PrefixUnaryExpression:
switch (type.operator) {
case ts.SyntaxKind.MinusToken:
// @ts-expect-error todo(flow->ts)
return `-${type.operand.text}`;
default:
console.log('"NO PRINT IMPLEMENTED: PrefixUnaryExpression"');
return '"NO PRINT IMPLEMENTED: PrefixUnaryExpression"';
}
case ts.SyntaxKind.TypePredicate:
//TODO: replace with boolean %checks when supported in class declarations
return "boolean";
case ts.SyntaxKind.IndexedAccessType:
{
let fn = "$ElementType";
if (ts.isLiteralTypeNode(type.indexType) && type.indexType.literal.kind === ts.SyntaxKind.StringLiteral) {
fn = "$PropertyType";
}
return `${fn}<${printType(type.objectType)}, ${printType(type.indexType)}>`;
}
case ts.SyntaxKind.TypeOperator:
switch (type.operator) {
case ts.SyntaxKind.KeyOfKeyword:
return `$Keys<${printType(type.type)}>`;
case ts.SyntaxKind.UniqueKeyword:
logger.error(type, {
type: "UnsupportedUniqueSymbol"
});
return printType(type.type);
case ts.SyntaxKind.ReadonlyKeyword:
if (ts.isArrayTypeNode(type.type)) {
return `$ReadOnlyArray<${printType(type.type.elementType)}>`;
} else if (type.type.kind === ts.SyntaxKind.TupleType) {
return printType(type.type);
} else {
const error = {
type: "UnsupportedTypeOperator",
operator: type.operator
};
logger.error(type, error);
return `/* ${(0, _errorMessage.printErrorMessage)(error)} */ any`;
}
default:
{
const error = {
type: "UnsupportedTypeOperator",
// @ts-expect-error
operator: type.operator
};
logger.error(type, error);
return `/* ${(0, _errorMessage.printErrorMessage)(error)} */ any`;
}
}
case ts.SyntaxKind.MappedType:
{
const constraint = type.typeParameter.constraint;
const typeName = printType(type.typeParameter.name);
const value = printType(type.type);
let source = `{[k: ${printType(constraint)}]: any}`; // @ts-expect-error todo(flow->ts)
if (constraint.operator === ts.SyntaxKind.KeyOfKeyword) {
// @ts-expect-error todo(flow->ts)
source = printType(constraint.type);
}
return `$ObjMapi<${source}, <${typeName}>(${typeName}) => ${value}>`;
}
case ts.SyntaxKind.BigIntLiteral:
return type.text;
case ts.SyntaxKind.FirstLiteralToken:
// @ts-expect-error todo(flow->ts)
return type.text;
case ts.SyntaxKind.ImportType:
return printErrorType("Failed to transform an ImportType node", type);
case ts.SyntaxKind.FirstTypeNode:
return printers.common.literalType(type);
case ts.SyntaxKind.LastTypeNode:
return printers.common.literalType(type);
case ts.SyntaxKind.LiteralType:
return printers.common.literalType(type);
case ts.SyntaxKind.QualifiedName:
{
let symbol;
if (_checker.checker.current) {
//$todo
symbol = _checker.checker.current.getSymbolAtLocation(type);
}
return getFullyQualifiedName(symbol, type);
}
case ts.SyntaxKind.StringLiteral:
return JSON.stringify(type.text);
case ts.SyntaxKind.TypeReference:
{
let symbol;
if (_checker.checker.current) {
symbol = _checker.checker.current.getSymbolAtLocation(type.typeName); //$todo
fixDefaultTypeArguments(symbol, type);
const isRenamed = (0, _smartIdentifiers.renames)(symbol, type);
if (!isRenamed) {
//$todo weird union errors
// @ts-expect-error todo(flow->ts)
type.typeName.escapedText = getFullyQualifiedName(symbol, type.typeName);
}
const getAdjustedType = targetSymbol => {
const isTypeImport = symbol && symbol.declarations && symbol.declarations[0] && ts.isTypeOnlyImportOrExportDeclaration(symbol.declarations[0]);
if (targetSymbol && targetSymbol.declarations && targetSymbol.declarations[0].kind === ts.SyntaxKind.EnumMember) {
return `${isTypeImport ? "" : "typeof"}
${getTypeofFullyQualifiedName(targetSymbol, type.typeName)}`;
} else if (targetSymbol && targetSymbol.declarations && targetSymbol.declarations[0].kind === ts.SyntaxKind.EnumDeclaration) {
return `$Values<
${isTypeImport ? "" : "typeof "}
${getTypeofFullyQualifiedName(targetSymbol, type.typeName)}>`;
}
return printers.declarations.typeReference(type, !targetSymbol);
}; // if importing an enum, we have to change how the type is used across the file
if (symbol && symbol.declarations && symbol.declarations[0].kind === ts.SyntaxKind.ImportSpecifier) {
return getAdjustedType(_checker.checker.current.getTypeAtLocation(type).symbol);
} else {
return getAdjustedType(symbol);
}
}
return printers.declarations.typeReference(type, !symbol);
}
case ts.SyntaxKind.VariableDeclaration:
return printers.declarations.propertyDeclaration(type, keywordPrefix);
case ts.SyntaxKind.PropertyDeclaration:
return printers.declarations.propertyDeclaration(type, keywordPrefix);
//$todo some weird union errors
case ts.SyntaxKind.OptionalType:
return `${printType(type.type)} | void`;
case ts.SyntaxKind.TupleType:
{
const lastElement = type.elements[type.elements.length - 1];
if (lastElement && ts.isRestTypeNode(lastElement)) // @ts-expect-error todo(flow->ts)
type.elements.pop();
let tuple = `[${type.elements.map(printType).join(", ")}]`;
if (lastElement && ts.isRestTypeNode(lastElement)) {
tuple += ` & ${printType(lastElement.type)}`;
}
return tuple;
}
case ts.SyntaxKind.MethodSignature:
return printers.common.methodSignature(type);
case ts.SyntaxKind.ExpressionWithTypeArguments:
return printType(type.expression) + printers.common.generics(type.typeArguments);
case ts.SyntaxKind.PropertyAccessExpression:
return getFullyQualifiedPropertyAccessExpression( //$todo some weird union errors
_checker.checker.current.getSymbolAtLocation(type), type);
// case SyntaxKind.NodeObject:
// return (
// printers.relationships.namespace(type.expression.text) +
// printType(type.name)
// );
case ts.SyntaxKind.PropertySignature:
return printers.common.parameter(type);
case ts.SyntaxKind.CallSignature:
{
// TODO: rewrite to printers.functions.functionType
const generics = printers.common.genericsWithoutDefault(type.typeParameters);
const str = `${generics}(${type.parameters // @ts-expect-error todo(flow->ts)
.filter(param => param.name.text !== "this").map(printers.common.parameter).join(", ")})`; // TODO: I can't understand this
return type.type ? `${str}: ${printType(type.type)}` : `${str}: any`;
}
case ts.SyntaxKind.UnionType:
{
const join = type.types.length >= 5 ? "\n" : " "; // debugger
return type.types.map(printType).join(`${join}| `);
}
case ts.SyntaxKind.ArrayType:
return printType(type.elementType) + "[]";
case ts.SyntaxKind.ThisType:
return "this";
case ts.SyntaxKind.IndexSignature:
if (type.type) {
return `[${type.parameters.map(printers.common.parameter).join(", ")}]: ${printType(type.type)}`;
}
return "";
case ts.SyntaxKind.IntersectionType:
{
// for non-class types, we can't easily just merge types together using &
// this is because in Typescript
// { a: number } & { b: string}
// is NOT equivalent to {| a: number |} & {| b: string |} in Flow
// since you can't intersect exact types in Flow
// https://github.com/facebook/flow/issues/4946#issuecomment-331520118
// instead, you have to use the spread notation
// HOWEVER, you must use & to intersect classes (you can't spread a class)
const containsClass = type.types.map(_checker.checker.current.getTypeAtLocation).find(type => type.isClass());
if (containsClass) {
return type.types.map(printType).join(" & ");
}
const spreadType = type.types.map(type => `...${printType(type)}`).join(",");
const isInexact = (0, _options.opts)().inexact;
return isInexact ? `{ ${spreadType} }` : `{| ${spreadType} |}`;
}
case ts.SyntaxKind.MethodDeclaration:
// Skip methods marked as private
if (type.modifiers && type.modifiers.some(modifier => modifier.kind === ts.SyntaxKind.PrivateKeyword)) {
return "";
}
return keywordPrefix + printers.common.methodSignature(type);
case ts.SyntaxKind.ConstructorType:
// Not implemented. The return is just a guess.
return "(" + type.parameters.map(printers.common.parameter).join(", ") + ") => " + printType(type.type);
case ts.SyntaxKind.ConstructSignature:
return "new " + printers.functions.functionType(type, true);
case ts.SyntaxKind.TypeQuery:
{
//$todo some weird union errors
const symbol = _checker.checker.current.getSymbolAtLocation(type.exprName);
return "typeof " + getTypeofFullyQualifiedName(symbol, type.exprName);
}
case ts.SyntaxKind.Constructor:
return "constructor(" + type.parameters.map(printers.common.parameter).join(", ") + "): this";
case ts.SyntaxKind.ParenthesizedType:
return `(${printType(type.type)})`;
case ts.SyntaxKind.ImportSpecifier:
if (_checker.checker.current) {
//$todo some weird union errors
const symbol = _checker.checker.current.getSymbolAtLocation(type.name);
(0, _smartIdentifiers.renames)(symbol, type);
}
return printers.relationships.importExportSpecifier(type);
case ts.SyntaxKind.ExportSpecifier:
return printers.relationships.importExportSpecifier(type);
case ts.SyntaxKind.GetAccessor:
return keywordPrefix + printers.common.parameter(type);
case ts.SyntaxKind.SetAccessor:
return printers.common.parameter(type);
case ts.SyntaxKind.InferType:
return printType(type.typeParameter);
default:
}
console.log(`
ts.SyntaxKind[type.kind]: ${ts.SyntaxKind[type.kind]}
name: ${type == null ? void 0 : (_name = type.name) == null ? void 0 : _name.escapedText}
kind: ${type.kind}
type: ${_util.default.inspect(type)}
`); // @ts-expect-error todo(flow->ts)
const output = `${(_type$name2 = type.name) == null ? void 0 : _type$name2.escapedText}: /* NO PRINT IMPLEMENTED: ${// @ts-expect-error todo(flow->ts)
ts.SyntaxKind[type.kind]} */ any`;
console.log(output);
return output;
});
exports.printType = printType;
var _default = printType;
exports.default = _default;