Skip to content

Commit ebcbd8f

Browse files
authored
Merge pull request #15790 from aozgaa/typeToStringViaTypeNode
Type to string via type node
2 parents ed7ae80 + 11019e4 commit ebcbd8f

19 files changed

+511
-279
lines changed

src/compiler/checker.ts

Lines changed: 274 additions & 185 deletions
Large diffs are not rendered by default.

src/compiler/emitter.ts

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ namespace ts {
153153
for (let i = 0; i < numNodes; i++) {
154154
const currentNode = bundle ? bundle.sourceFiles[i] : node;
155155
const sourceFile = isSourceFile(currentNode) ? currentNode : currentSourceFile;
156-
const shouldSkip = compilerOptions.noEmitHelpers || (sourceFile && getExternalHelpersModuleName(sourceFile) !== undefined);
156+
const shouldSkip = compilerOptions.noEmitHelpers || getExternalHelpersModuleName(sourceFile) !== undefined;
157157
const shouldBundle = isSourceFile(currentNode) && !isOwnFileEmit;
158158
const helpers = getEmitHelpers(currentNode);
159159
if (helpers) {
@@ -212,7 +212,7 @@ namespace ts {
212212
emitLeadingCommentsOfPosition,
213213
} = comments;
214214

215-
let currentSourceFile: SourceFile;
215+
let currentSourceFile: SourceFile | undefined;
216216
let nodeIdToGeneratedName: string[]; // Map of generated names for specific nodes.
217217
let autoGeneratedIdToGeneratedName: string[]; // Map of generated names for temp and loop variables.
218218
let generatedNames: Map<string>; // Set of names generated by the NameGenerator.
@@ -264,7 +264,12 @@ namespace ts {
264264
return endPrint();
265265
}
266266

267-
function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile, output: EmitTextWriter) {
267+
/**
268+
* If `sourceFile` is `undefined`, `node` must be a synthesized `TypeNode`.
269+
*/
270+
function writeNode(hint: EmitHint, node: TypeNode, sourceFile: undefined, output: EmitTextWriter): void;
271+
function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile, output: EmitTextWriter): void;
272+
function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, output: EmitTextWriter) {
268273
const previousWriter = writer;
269274
setWriter(output);
270275
print(hint, node, sourceFile);
@@ -305,8 +310,10 @@ namespace ts {
305310
return text;
306311
}
307312

308-
function print(hint: EmitHint, node: Node, sourceFile: SourceFile) {
309-
setSourceFile(sourceFile);
313+
function print(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined) {
314+
if (sourceFile) {
315+
setSourceFile(sourceFile);
316+
}
310317
pipelineEmitWithNotification(hint, node);
311318
}
312319

@@ -781,6 +788,7 @@ namespace ts {
781788

782789
function emitIdentifier(node: Identifier) {
783790
write(getTextOfNode(node, /*includeTrivia*/ false));
791+
emitTypeArguments(node, node.typeArguments);
784792
}
785793

786794
//
@@ -815,6 +823,7 @@ namespace ts {
815823
function emitTypeParameter(node: TypeParameterDeclaration) {
816824
emit(node.name);
817825
emitWithPrefix(" extends ", node.constraint);
826+
emitWithPrefix(" = ", node.default);
818827
}
819828

820829
function emitParameter(node: ParameterDeclaration) {
@@ -955,7 +964,10 @@ namespace ts {
955964

956965
function emitTypeLiteral(node: TypeLiteralNode) {
957966
write("{");
958-
emitList(node, node.members, ListFormat.TypeLiteralMembers);
967+
// If the literal is empty, do not add spaces between braces.
968+
if (node.members.length > 0) {
969+
emitList(node, node.members, getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers);
970+
}
959971
write("}");
960972
}
961973

@@ -1002,9 +1014,15 @@ namespace ts {
10021014
}
10031015

10041016
function emitMappedType(node: MappedTypeNode) {
1017+
const emitFlags = getEmitFlags(node);
10051018
write("{");
1006-
writeLine();
1007-
increaseIndent();
1019+
if (emitFlags & EmitFlags.SingleLine) {
1020+
write(" ");
1021+
}
1022+
else {
1023+
writeLine();
1024+
increaseIndent();
1025+
}
10081026
writeIfPresent(node.readonlyToken, "readonly ");
10091027
write("[");
10101028
emit(node.typeParameter.name);
@@ -1015,8 +1033,13 @@ namespace ts {
10151033
write(": ");
10161034
emit(node.type);
10171035
write(";");
1018-
writeLine();
1019-
decreaseIndent();
1036+
if (emitFlags & EmitFlags.SingleLine) {
1037+
write(" ");
1038+
}
1039+
else {
1040+
writeLine();
1041+
decreaseIndent();
1042+
}
10201043
write("}");
10211044
}
10221045

@@ -1035,7 +1058,7 @@ namespace ts {
10351058
}
10361059
else {
10371060
write("{");
1038-
emitList(node, elements, ListFormat.ObjectBindingPatternElements);
1061+
emitList(node, elements, getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.ObjectBindingPatternElements : ListFormat.ObjectBindingPatternElementsWithSpaceBetweenBraces);
10391062
write("}");
10401063
}
10411064
}
@@ -2637,7 +2660,9 @@ namespace ts {
26372660
if (node.kind === SyntaxKind.StringLiteral && (<StringLiteral>node).textSourceNode) {
26382661
const textSourceNode = (<StringLiteral>node).textSourceNode;
26392662
if (isIdentifier(textSourceNode)) {
2640-
return "\"" + escapeNonAsciiCharacters(escapeString(getTextOfNode(textSourceNode))) + "\"";
2663+
return getEmitFlags(node) & EmitFlags.NoAsciiEscaping ?
2664+
`"${escapeString(getTextOfNode(textSourceNode))}"` :
2665+
`"${escapeNonAsciiString(getTextOfNode(textSourceNode))}"`;
26412666
}
26422667
else {
26432668
return getLiteralTextOfNode(textSourceNode);
@@ -2950,11 +2975,14 @@ namespace ts {
29502975
// Precomputed Formats
29512976
Modifiers = SingleLine | SpaceBetweenSiblings,
29522977
HeritageClauses = SingleLine | SpaceBetweenSiblings,
2953-
TypeLiteralMembers = MultiLine | Indented,
2978+
SingleLineTypeLiteralMembers = SingleLine | SpaceBetweenBraces | SpaceBetweenSiblings | Indented,
2979+
MultiLineTypeLiteralMembers = MultiLine | Indented,
2980+
29542981
TupleTypeElements = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented,
29552982
UnionTypeConstituents = BarDelimited | SpaceBetweenSiblings | SingleLine,
29562983
IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine,
2957-
ObjectBindingPatternElements = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited | SpaceBetweenSiblings,
2984+
ObjectBindingPatternElements = SingleLine | CommaDelimited | SpaceBetweenSiblings,
2985+
ObjectBindingPatternElementsWithSpaceBetweenBraces = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited | SpaceBetweenSiblings,
29582986
ArrayBindingPatternElements = SingleLine | AllowTrailingComma | CommaDelimited | SpaceBetweenSiblings,
29592987
ObjectLiteralExpressionProperties = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented | Braces,
29602988
ArrayLiteralExpressionElements = PreserveLines | CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | Indented | SquareBrackets,

src/compiler/factory.ts

Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,27 @@ namespace ts {
107107

108108
// Identifiers
109109

110-
export function createIdentifier(text: string): Identifier {
110+
export function createIdentifier(text: string): Identifier;
111+
/* @internal */
112+
export function createIdentifier(text: string, typeArguments: TypeNode[]): Identifier;
113+
export function createIdentifier(text: string, typeArguments?: TypeNode[]): Identifier {
111114
const node = <Identifier>createSynthesizedNode(SyntaxKind.Identifier);
112115
node.text = escapeIdentifier(text);
113116
node.originalKeywordKind = text ? stringToToken(text) : SyntaxKind.Unknown;
114117
node.autoGenerateKind = GeneratedIdentifierKind.None;
115118
node.autoGenerateId = 0;
119+
if (typeArguments) {
120+
node.typeArguments = createNodeArray(typeArguments);
121+
}
116122
return node;
117123
}
118124

125+
export function updateIdentifier(node: Identifier, typeArguments: NodeArray<TypeNode> | undefined): Identifier {
126+
return node.typeArguments !== typeArguments
127+
? updateNode(createIdentifier(node.text, typeArguments), node)
128+
: node;
129+
}
130+
119131
let nextAutoGenerateId = 0;
120132

121133
/** Create a unique temporary variable. */
@@ -271,21 +283,23 @@ namespace ts {
271283

272284
// Type Elements
273285

274-
export function createPropertySignature(name: PropertyName | string, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertySignature {
286+
export function createPropertySignature(modifiers: Modifier[] | undefined, name: PropertyName | string, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertySignature {
275287
const node = createSynthesizedNode(SyntaxKind.PropertySignature) as PropertySignature;
288+
node.modifiers = asNodeArray(modifiers);
276289
node.name = asName(name);
277290
node.questionToken = questionToken;
278291
node.type = type;
279292
node.initializer = initializer;
280293
return node;
281294
}
282295

283-
export function updatePropertySignature(node: PropertySignature, name: PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) {
284-
return node.name !== name
296+
export function updatePropertySignature(node: PropertySignature, modifiers: Modifier[] | undefined, name: PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) {
297+
return node.modifiers !== modifiers
298+
|| node.name !== name
285299
|| node.questionToken !== questionToken
286300
|| node.type !== type
287301
|| node.initializer !== initializer
288-
? updateNode(createPropertySignature(name, questionToken, type, initializer), node)
302+
? updateNode(createPropertySignature(modifiers, name, questionToken, type, initializer), node)
289303
: node;
290304
}
291305

@@ -492,7 +506,7 @@ namespace ts {
492506
export function createTypeReferenceNode(typeName: string | EntityName, typeArguments: TypeNode[] | undefined) {
493507
const node = createSynthesizedNode(SyntaxKind.TypeReference) as TypeReferenceNode;
494508
node.typeName = asName(typeName);
495-
node.typeArguments = asNodeArray(typeArguments);
509+
node.typeArguments = typeArguments && parenthesizeTypeParameters(typeArguments);
496510
return node;
497511
}
498512

@@ -545,7 +559,7 @@ namespace ts {
545559

546560
export function createArrayTypeNode(elementType: TypeNode) {
547561
const node = createSynthesizedNode(SyntaxKind.ArrayType) as ArrayTypeNode;
548-
node.elementType = elementType;
562+
node.elementType = parenthesizeElementTypeMember(elementType);
549563
return node;
550564
}
551565

@@ -585,7 +599,7 @@ namespace ts {
585599

586600
export function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: TypeNode[]) {
587601
const node = createSynthesizedNode(kind) as UnionTypeNode | IntersectionTypeNode;
588-
node.types = createNodeArray(types);
602+
node.types = parenthesizeElementTypeMembers(types);
589603
return node;
590604
}
591605

@@ -614,7 +628,7 @@ namespace ts {
614628
export function createTypeOperatorNode(type: TypeNode) {
615629
const node = createSynthesizedNode(SyntaxKind.TypeOperator) as TypeOperatorNode;
616630
node.operator = SyntaxKind.KeyOfKeyword;
617-
node.type = type;
631+
node.type = parenthesizeElementTypeMember(type);
618632
return node;
619633
}
620634

@@ -624,7 +638,7 @@ namespace ts {
624638

625639
export function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode) {
626640
const node = createSynthesizedNode(SyntaxKind.IndexedAccessType) as IndexedAccessTypeNode;
627-
node.objectType = objectType;
641+
node.objectType = parenthesizeElementTypeMember(objectType);
628642
node.indexType = indexType;
629643
return node;
630644
}
@@ -2489,6 +2503,25 @@ namespace ts {
24892503

24902504
/* @internal */
24912505
namespace ts {
2506+
export const nullTransformationContext: TransformationContext = {
2507+
enableEmitNotification: noop,
2508+
enableSubstitution: noop,
2509+
endLexicalEnvironment: () => undefined,
2510+
getCompilerOptions: notImplemented,
2511+
getEmitHost: notImplemented,
2512+
getEmitResolver: notImplemented,
2513+
hoistFunctionDeclaration: noop,
2514+
hoistVariableDeclaration: noop,
2515+
isEmitNotificationEnabled: notImplemented,
2516+
isSubstitutionEnabled: notImplemented,
2517+
onEmitNode: noop,
2518+
onSubstituteNode: notImplemented,
2519+
readEmitHelpers: notImplemented,
2520+
requestEmitHelper: noop,
2521+
resumeLexicalEnvironment: noop,
2522+
startLexicalEnvironment: noop,
2523+
suspendLexicalEnvironment: noop
2524+
};
24922525

24932526
// Compound nodes
24942527

@@ -3289,16 +3322,6 @@ namespace ts {
32893322
return statements;
32903323
}
32913324

3292-
export function parenthesizeConditionalHead(condition: Expression) {
3293-
const conditionalPrecedence = getOperatorPrecedence(SyntaxKind.ConditionalExpression, SyntaxKind.QuestionToken);
3294-
const emittedCondition = skipPartiallyEmittedExpressions(condition);
3295-
const conditionPrecedence = getExpressionPrecedence(emittedCondition);
3296-
if (compareValues(conditionPrecedence, conditionalPrecedence) === Comparison.LessThan) {
3297-
return createParen(condition);
3298-
}
3299-
return condition;
3300-
}
3301-
33023325
/**
33033326
* Wraps the operand to a BinaryExpression in parentheses if they are needed to preserve the intended
33043327
* order of operations.
@@ -3600,6 +3623,35 @@ namespace ts {
36003623
return expression;
36013624
}
36023625

3626+
export function parenthesizeElementTypeMember(member: TypeNode) {
3627+
switch (member.kind) {
3628+
case SyntaxKind.UnionType:
3629+
case SyntaxKind.IntersectionType:
3630+
case SyntaxKind.FunctionType:
3631+
case SyntaxKind.ConstructorType:
3632+
return createParenthesizedType(member);
3633+
}
3634+
return member;
3635+
}
3636+
3637+
export function parenthesizeElementTypeMembers(members: TypeNode[]) {
3638+
return createNodeArray(sameMap(members, parenthesizeElementTypeMember));
3639+
}
3640+
3641+
export function parenthesizeTypeParameters(typeParameters: TypeNode[]) {
3642+
if (some(typeParameters)) {
3643+
const nodeArray = createNodeArray() as NodeArray<TypeNode>;
3644+
for (let i = 0; i < typeParameters.length; ++i) {
3645+
const entry = typeParameters[i];
3646+
nodeArray.push(i === 0 && isFunctionOrConstructorTypeNode(entry) && entry.typeParameters ?
3647+
createParenthesizedType(entry) :
3648+
entry);
3649+
}
3650+
3651+
return nodeArray;
3652+
}
3653+
}
3654+
36033655
/**
36043656
* Clones a series of not-emitted expressions with a new inner expression.
36053657
*

0 commit comments

Comments
 (0)