mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-06 15:03:14 -05:00
Basic parens handling and stubbed TypeFormatFlags
This commit is contained in:
@@ -2287,8 +2287,16 @@ namespace ts {
|
||||
interface NodeBuilderContext {
|
||||
readonly enclosingDeclaration: Node | undefined;
|
||||
readonly flags: NodeBuilderFlags | undefined;
|
||||
|
||||
// State
|
||||
encounteredError: boolean;
|
||||
inObjectTypeLiteral: boolean;
|
||||
// TODO: needed for part of parens handling
|
||||
InElementType: boolean; // Writing an array or union element type
|
||||
// TODO: ???
|
||||
InFirstTypeArgument: boolean; // Writing first type argument of the instantiated type
|
||||
// TODO: ???
|
||||
InTypeAlias: boolean; // Writing type in type alias declaration
|
||||
checkAlias: boolean;
|
||||
symbolStack: Symbol[] | undefined;
|
||||
}
|
||||
@@ -2299,18 +2307,28 @@ namespace ts {
|
||||
flags,
|
||||
encounteredError: false,
|
||||
inObjectTypeLiteral: false,
|
||||
InElementType: false,
|
||||
InFirstTypeArgument: false,
|
||||
InTypeAlias: false,
|
||||
checkAlias: true,
|
||||
symbolStack: undefined
|
||||
};
|
||||
}
|
||||
|
||||
function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode {
|
||||
const InElementType = context.InElementType;
|
||||
// TODO: why doesn't tts unset the flag?
|
||||
context.InElementType = false;
|
||||
|
||||
// TODO: should be assert?
|
||||
if (!type) {
|
||||
context.encounteredError = true;
|
||||
// TODO(aozgaa): should we return implict any (undefined) or explicit any (keywordtypenode)?
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (type.flags & TypeFlags.Any) {
|
||||
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
|
||||
}
|
||||
@@ -2390,16 +2408,17 @@ namespace ts {
|
||||
|
||||
if (context.checkAlias && type.aliasSymbol) {
|
||||
const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false, context);
|
||||
const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments);
|
||||
const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments, /*addInElementTypeFlag*/ false);
|
||||
return createTypeReferenceNode(name, typeArgumentNodes);
|
||||
}
|
||||
context.checkAlias = false;
|
||||
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
const formattedUnionTypes = formatUnionTypes((<UnionType>type).types);
|
||||
const unionTypeNodes = formattedUnionTypes && mapToTypeNodeArray(formattedUnionTypes);
|
||||
if (unionTypeNodes && unionTypeNodes.length > 0) {
|
||||
return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, unionTypeNodes);
|
||||
if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) {
|
||||
const types = type.flags & TypeFlags.Union ? formatUnionTypes((<UnionType>type).types) : (<IntersectionType>type).types;
|
||||
const typeNodes = types && mapToTypeNodeArray(types, /*addInElementTypeFlag*/ true);
|
||||
if (typeNodes && typeNodes.length > 0) {
|
||||
const unionOrIntersectionTypeNode = createUnionOrIntersectionTypeNode(type.flags & TypeFlags.Union ? SyntaxKind.UnionType : SyntaxKind.IntersectionType, typeNodes);
|
||||
return InElementType ? createParenthesizedTypeNode(unionOrIntersectionTypeNode) : unionOrIntersectionTypeNode;
|
||||
}
|
||||
else {
|
||||
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowEmptyUnionOrIntersection)) {
|
||||
@@ -2409,10 +2428,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
if (type.flags & TypeFlags.Intersection) {
|
||||
return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, mapToTypeNodeArray((type as UnionType).types));
|
||||
}
|
||||
|
||||
if (objectFlags & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) {
|
||||
Debug.assert(!!(type.flags & TypeFlags.Object));
|
||||
// The type is an object literal type.
|
||||
@@ -2421,25 +2436,33 @@ namespace ts {
|
||||
|
||||
if (type.flags & TypeFlags.Index) {
|
||||
const indexedType = (<IndexType>type).type;
|
||||
context.InElementType = <boolean>true;
|
||||
const indexTypeNode = typeToTypeNodeHelper(indexedType, context);
|
||||
Debug.assert(context.InElementType === false);
|
||||
return createTypeOperatorNode(indexTypeNode);
|
||||
}
|
||||
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
context.InElementType = <boolean>true;
|
||||
const objectTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).objectType, context);
|
||||
Debug.assert(context.InElementType === false);
|
||||
const indexTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).indexType, context);
|
||||
return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode);
|
||||
}
|
||||
|
||||
Debug.fail("Should be unreachable.");
|
||||
|
||||
function mapToTypeNodeArray(types: Type[]): TypeNode[] {
|
||||
function mapToTypeNodeArray(types: Type[], addInElementTypeFlag: boolean): TypeNode[] {
|
||||
const result = [];
|
||||
Debug.assert(context.InElementType === false, "should be unset at the beginning of the helper");
|
||||
for (const type of types) {
|
||||
context.InElementType = addInElementTypeFlag;
|
||||
const typeNode = typeToTypeNodeHelper(type, context);
|
||||
if (typeNode) {
|
||||
result.push(typeNode);
|
||||
}
|
||||
}
|
||||
Debug.assert(context.InElementType === false, "should be unset at the beginning of the helper");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2523,6 +2546,7 @@ namespace ts {
|
||||
|
||||
if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) {
|
||||
const signature = resolved.callSignatures[0];
|
||||
shouldAddParenthesisAroundFunctionType(signature, context);
|
||||
return <FunctionTypeNode>signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, context);
|
||||
}
|
||||
if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) {
|
||||
@@ -2538,6 +2562,20 @@ namespace ts {
|
||||
return createTypeLiteralNode(members);
|
||||
}
|
||||
|
||||
|
||||
function shouldAddParenthesisAroundFunctionType(callSignature: Signature, context: NodeBuilderContext) {
|
||||
if (context.InElementType) {
|
||||
return true;
|
||||
}
|
||||
else if (context.InFirstTypeArgument) {
|
||||
// Add parenthesis around function type for the first type argument to avoid ambiguity
|
||||
const typeParameters = callSignature.target && (context.flags & NodeBuilderFlags.WriteTypeArgumentsOfSignature) ?
|
||||
callSignature.target.typeParameters : callSignature.typeParameters;
|
||||
return typeParameters && typeParameters.length !== 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function createTypeQueryNodeFromSymbol(symbol: Symbol) {
|
||||
const entityName = symbolToName(symbol, /*expectsIdentifier*/ false, context);
|
||||
return createTypeQueryNode(entityName);
|
||||
@@ -2546,12 +2584,14 @@ namespace ts {
|
||||
function typeReferenceToTypeNode(type: TypeReference) {
|
||||
const typeArguments: Type[] = type.typeArguments || emptyArray;
|
||||
if (type.target === globalArrayType) {
|
||||
context.InElementType = true;
|
||||
const elementType = typeToTypeNodeHelper(typeArguments[0], context);
|
||||
context.InElementType = false;
|
||||
return createArrayTypeNode(elementType);
|
||||
}
|
||||
else if (type.target.objectFlags & ObjectFlags.Tuple) {
|
||||
if (typeArguments.length > 0) {
|
||||
const tupleConstituentNodes = mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type)));
|
||||
const tupleConstituentNodes = mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type)), /*addInElementTypeFlag*/ false);
|
||||
if (tupleConstituentNodes && tupleConstituentNodes.length > 0) {
|
||||
return createTupleTypeNode(tupleConstituentNodes);
|
||||
}
|
||||
@@ -2566,6 +2606,7 @@ namespace ts {
|
||||
let i = 0;
|
||||
let qualifiedName: QualifiedName | undefined = undefined;
|
||||
if (outerTypeParameters) {
|
||||
let inFirstTypeArgument = true;
|
||||
const length = outerTypeParameters.length;
|
||||
while (i < length) {
|
||||
// Find group of type arguments for type parameters with the same declaring container.
|
||||
@@ -2577,6 +2618,7 @@ namespace ts {
|
||||
// When type parameters are their own type arguments for the whole group (i.e. we have
|
||||
// the default outer type arguments), we don't show the group.
|
||||
if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) {
|
||||
// inFirstTypeArgument???
|
||||
const qualifiedNamePart = symbolToName(parent, /*expectsIdentifier*/ true, context);
|
||||
if (!qualifiedName) {
|
||||
qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/ undefined);
|
||||
@@ -2587,6 +2629,7 @@ namespace ts {
|
||||
qualifiedName = createQualifiedName(qualifiedName, /*right*/ undefined);
|
||||
}
|
||||
}
|
||||
inFirstTypeArgument = false;
|
||||
}
|
||||
}
|
||||
let entityName: EntityName = undefined;
|
||||
@@ -2600,7 +2643,7 @@ namespace ts {
|
||||
entityName = nameIdentifier;
|
||||
}
|
||||
const typeParameterCount = (type.target.typeParameters || emptyArray).length;
|
||||
const typeArgumentNodes = some(typeArguments) ? mapToTypeNodeArray(typeArguments.slice(i, typeParameterCount - i)) : undefined;
|
||||
const typeArgumentNodes = some(typeArguments) ? mapToTypeNodeArray(typeArguments.slice(i, typeParameterCount - i), /*addInElementTypeFlag*/ false) : undefined;
|
||||
return createTypeReferenceNode(entityName, typeArgumentNodes);
|
||||
}
|
||||
}
|
||||
@@ -2695,7 +2738,7 @@ namespace ts {
|
||||
const returnType = getReturnTypeOfSignature(signature);
|
||||
returnTypeNode = returnType && typeToTypeNodeHelper(returnType, context);
|
||||
}
|
||||
if(context.flags & NodeBuilderFlags.suppressAnyReturnType) {
|
||||
if(context.flags & NodeBuilderFlags.SuppressAnyReturnType) {
|
||||
if(returnTypeNode && returnTypeNode.kind === SyntaxKind.AnyKeyword) {
|
||||
returnTypeNode = undefined;
|
||||
}
|
||||
@@ -2733,6 +2776,8 @@ namespace ts {
|
||||
return parameterNode;
|
||||
}
|
||||
|
||||
// TODO: add meaning: SymbolFlags argument.
|
||||
// TODO: add SymbolFormatFlags?? Yes to add outer type parameters. Defer UseOnlyExternalAliasing until a separate symbolbuilder PR.
|
||||
function symbolToName(symbol: Symbol, expectsIdentifier: true, context: NodeBuilderContext): Identifier;
|
||||
function symbolToName(symbol: Symbol, expectsIdentifier: false, context: NodeBuilderContext): EntityName;
|
||||
function symbolToName(symbol: Symbol, expectsIdentifier: boolean, context: NodeBuilderContext): EntityName {
|
||||
@@ -2826,6 +2871,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getNameOfSymbol(symbol: Symbol, context: NodeBuilderContext): string {
|
||||
const declaration = firstOrUndefined(symbol.declarations);
|
||||
if (declaration) {
|
||||
|
||||
@@ -2947,8 +2947,9 @@ namespace ts {
|
||||
// Precomputed Formats
|
||||
Modifiers = SingleLine | SpaceBetweenSiblings,
|
||||
HeritageClauses = SingleLine | SpaceBetweenSiblings,
|
||||
SingleLineTypeLiteralMembers = SpaceBetweenBraces | SpaceBetweenSiblings | Indented, // MultiLine | Indented,
|
||||
SingleLineTypeLiteralMembers = SingleLine | SpaceBetweenBraces | SpaceBetweenSiblings | Indented, // MultiLine | Indented,
|
||||
MultiLineTypeLiteralMembers = MultiLine | Indented,
|
||||
|
||||
TupleTypeElements = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented,
|
||||
UnionTypeConstituents = BarDelimited | SpaceBetweenSiblings | SingleLine,
|
||||
IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine,
|
||||
|
||||
@@ -393,6 +393,18 @@ namespace ts {
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createParenthesizedTypeNode(type: TypeNode) {
|
||||
const parenthesizedTypeNode = createSynthesizedNode(SyntaxKind.ParenthesizedType) as ParenthesizedTypeNode;
|
||||
parenthesizedTypeNode.type = type;
|
||||
return parenthesizedTypeNode;
|
||||
}
|
||||
|
||||
export function updateParenthesizedTypeNode(node: ParenthesizedTypeNode, type: TypeNode) {
|
||||
return node.type !== type
|
||||
? updateNode(createParenthesizedTypeNode(type), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createTypeLiteralNode(members: TypeElement[]) {
|
||||
const typeLiteralNode = createSynthesizedNode(SyntaxKind.TypeLiteral) as TypeLiteralNode;
|
||||
typeLiteralNode.members = createNodeArray(members);
|
||||
|
||||
@@ -2559,14 +2559,36 @@ namespace ts {
|
||||
|
||||
export enum NodeBuilderFlags {
|
||||
None = 0,
|
||||
allowThisInObjectLiteral = 1 << 0,
|
||||
allowQualifedNameInPlaceOfIdentifier = 1 << 1,
|
||||
allowTypeParameterInQualifiedName = 1 << 2,
|
||||
allowAnonymousIdentifier = 1 << 3,
|
||||
allowEmptyUnionOrIntersection = 1 << 4,
|
||||
allowEmptyTuple = 1 << 5,
|
||||
suppressAnyReturnType = 1 << 6,
|
||||
ignoreErrors = allowThisInObjectLiteral | allowQualifedNameInPlaceOfIdentifier | allowTypeParameterInQualifiedName | allowAnonymousIdentifier | allowEmptyUnionOrIntersection | allowEmptyTuple
|
||||
// Options
|
||||
NoTruncation = 1 << 0, // Don't truncate result
|
||||
// TODO: part of emit.
|
||||
WriteArrayAsGenericType = 1 << 1, // Write Array<T> instead T[]
|
||||
// TODO: part of emit.
|
||||
UseTypeOfFunction = 1 << 2, // Write typeof instead of function type literal
|
||||
// TODO: part of emit.
|
||||
WriteArrowStyleSignature = 1 << 3, // Write arrow style signature
|
||||
// TODO: turn it into a failing type reference?
|
||||
WriteOwnNameForAnyLike = 1 << 4, // Write symbol's own name instead of 'any' for any like types (eg. unknown, __resolving__ etc)
|
||||
// TODO
|
||||
WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature
|
||||
// TODO
|
||||
UseFullyQualifiedType = 1 << 6, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
|
||||
// TODO
|
||||
UseTypeAliasValue = 1 << 7, // Serialize the type instead of using type-alias. This is needed when we emit declaration file.
|
||||
SuppressAnyReturnType = 1 << 8, // If the return type is any-like, don't offer a return type.
|
||||
// TODO
|
||||
AddUndefined = 1 << 9, // Add undefined to types of initialized, non-optional parameters
|
||||
|
||||
// Error handling
|
||||
allowThisInObjectLiteral = 1 << 10,
|
||||
allowQualifedNameInPlaceOfIdentifier = 1 << 11,
|
||||
allowTypeParameterInQualifiedName = 1 << 12,
|
||||
allowAnonymousIdentifier = 1 << 13,
|
||||
allowEmptyUnionOrIntersection = 1 << 14,
|
||||
allowEmptyTuple = 1 << 15,
|
||||
|
||||
ignoreErrors = allowThisInObjectLiteral | allowQualifedNameInPlaceOfIdentifier | allowTypeParameterInQualifiedName | allowAnonymousIdentifier | allowEmptyUnionOrIntersection | allowEmptyTuple,
|
||||
|
||||
}
|
||||
|
||||
export interface SymbolDisplayBuilder {
|
||||
|
||||
@@ -322,7 +322,8 @@ namespace ts {
|
||||
nodesVisitor((<UnionOrIntersectionTypeNode>node).types, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
throw Debug.fail("not implemented.");
|
||||
return updateParenthesizedTypeNode(<ParenthesizedTypeNode>node,
|
||||
visitNode((<ParenthesizedTypeNode>node).type, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.TypeOperator:
|
||||
return updateTypeOperatorNode(<TypeOperatorNode>node, visitNode((<TypeOperatorNode>node).type, visitor, isTypeNode));
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
function signatureToMethodDeclaration(signature: Signature, enclosingDeclaration: Node, body?: Block) {
|
||||
const signatureDeclaration = <MethodDeclaration>checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration, NodeBuilderFlags.suppressAnyReturnType);
|
||||
const signatureDeclaration = <MethodDeclaration>checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration, NodeBuilderFlags.SuppressAnyReturnType);
|
||||
if (signatureDeclaration) {
|
||||
signatureDeclaration.decorators = undefined;
|
||||
signatureDeclaration.modifiers = modifiers;
|
||||
|
||||
Reference in New Issue
Block a user